The Analytiics Node SDK
@analytiics/sdk-node sends authenticated server events, including revenue and anything your backend knows that the page does not.
Setup
import { createClient } from "@analytiics/sdk-node";
export const analytiics = createClient({
site: "liinks",
writeKey: process.env.ANALYTIICS_WRITE_KEY!,
api: "https://in.analytiics.co",
});Each project gets its own server write key. It is shown once, when issued, and cannot be recovered afterwards — only its hash is stored. A leaked key can only write to the project it was issued for, and revoking one takes no redeploy.
Typed helpers in server handlers
Regenerate your helpers with npx analytiics codegen. Bind a typed helper to each request's adapter after resolving its user:
import { toAnalytiicsClient } from "@analytiics/sdk-node";
import { createTrack } from "./analytics.gen";
// Inside the handler; analytiics is the SDK client from setup above.
const track = createTrack(toAnalytiicsClient(analytiics, { userId: user.id }));
track.pagePublished({ template: "grid", block_count: 7 });
await analytiics.flush();Use the event names and properties in your own manifest. Each helper keeps its own client, so overlapping requests retain the correct user. The legacy configure function changes shared browser convenience calls and must never hold a server request's identity. In serverless handlers, flush before returning.
Attributing revenue to a channel
For Stripe, start with Connect Stripe: paste a restricted key in project settings to import payments, refunds and renewals. Add checkout metadata for attribution. Do not also emit SDK revenue for the same Stripe payments.
The webhook approach below remains available for other providers and custom billing, and for Stripe projects that deliberately use the SDK instead.
A Stripe webhook knows a customer and an amount. It has no cookie, no referrer and no session — nothing that says the customer arrived from a search three days ago. The join key is the user id, in two steps.
In the browser, once the user is known:
window.analytiics.identify(user.id);Call it at signup and at login. That ties the anonymous visitor to a user id, which is what lets a later server-side event find the session — and therefore the source — that earned it.
In the webhook:
if (event.type === "checkout.session.completed") {
const session = event.data.object;
// Use a delivery client for this webhook, after verifying the provider signature.
const delivery = createClient({ site: "liinks", writeKey: process.env.ANALYTIICS_WRITE_KEY! });
delivery.revenue({
name: "subscription_started",
eventId: event.id,
ts: new Date(event.created * 1000).toISOString(),
userId: session.client_reference_id ?? undefined,
revenueCents: session.amount_total,
currency: session.currency.toUpperCase(),
});
try {
await delivery.flush({ throwOnError: true });
} catch {
return new Response("Analytics delivery failed; retry this webhook", { status: 503 });
}
}Currency is required with any amount. Revenue is grouped by currency on the dashboard and never summed across currencies. Keep the provider event id and original timestamp unchanged when a webhook retries. Strict flush reports a delivery failure so the handler can return a retryable response; the default flush remains best-effort. Use a separate SDK client per webhook delivery.
Why not from the browser
The public collector ships to every visitor, so it is unauthenticated by necessity — and therefore ignores revenue_cents outright. If it did not, anyone who could read your page source could post fake sales into your dashboard. This is the whole reason the server path exists.
Last updated 2026-08-27. This page is also available as Markdown at /docs/sdk.md, or from this URL with Accept: text/markdown.