Server-side events Pro

Send events from Node.js using a project API key. Use it for anything that needs to be authoritative: payment webhooks, background jobs, server-rendered signups.

Install

terminal
npm install @clamp-sh/analytics

Use an API key that starts with sk_proj_ from Settings → API Keys. Keys are scoped to one project.

Track from Node

Server events follow the same plan rules as browser track(). They count against your monthly event quota and need a Pro or Growth plan to land in your charts.

server.ts
import { init, track } from "@clamp-sh/analytics/server"

init({ projectId: "proj_xxx", apiKey: "sk_proj_..." })

await track("subscription_created", {
  anonymousId: "anon_abc123",
  properties: { plan: "pro", interval: "monthly" },
})

Server events never fire pageviews or sessions. Use them for authoritative backend events: payments, webhooks, signups confirmed in your database.

Revenue from webhooks

Most real revenue numbers belong on the server. Fire a Money-valued property from a Stripe or billing webhook so the amount is never invented by a browser.

Stripe webhook handler
// POST /api/stripe/webhook
if (event.type === "checkout.session.completed") {
  const s = event.data.object
  await track("checkout_completed", {
    anonymousId: s.metadata.clamp_anon_id,
    properties: {
      plan: s.metadata.plan,
      total: { amount: s.amount_total / 100, currency: s.currency.toUpperCase() },
    },
  })
}

See Revenue for the full pattern: refunds, mixed currencies, and the MCP query shapes.

Linking browser and server events

Pass the anonymous ID from the browser to your API, then include it in server-side calls. Events from both sides then share a visitor.

Browser
import { getAnonymousId } from "@clamp-sh/analytics"

const anonId = getAnonymousId()
await fetch("/api/checkout", {
  method: "POST",
  body: JSON.stringify({ plan: "pro", anonId }),
})
Server
import { track } from "@clamp-sh/analytics/server"

await track("checkout_completed", {
  anonymousId: req.body.anonId,
  properties: { plan: "pro" },
})

For Stripe Checkout, stash the anon ID in metadata when you create the session so the webhook can retrieve it later.