Install
Install FirstDistro for browser and server. One npm package, same track() verb. Browser token (fd_*) and server key (sk_*). First server event in under 3 minutes.
One package (@firstdistro/sdk), one track() verb, two surfaces: browser UI and server truth (payments, KYC, syncs, sessions). Goal: first server event in under 3 minutes.
Get credentials in Settings → SDK Configuration. Prefer the CLI for the fastest path: npx firstdistro init.
Keys
| Surface | Credential | Env var | Exposure |
|---|---|---|---|
| Browser | Install token fd_* | NEXT_PUBLIC_FIRSTDISTRO_TOKEN | Safe to expose in client bundles |
| Server | API key sk_live_* / sk_test_* | FIRSTDISTRO_API_KEY | Keep secret. Server only |
Warning: Never put sk_* in client code. Never use fd_* for server ingest.
Choose your surface
1. Install
npm install @firstdistro/sdk
2. Init and identify
Wrap the app with FirstDistroProvider (NEXT_PUBLIC_FIRSTDISTRO_TOKEN), then call useFirstDistroSetup with user id and email when the user logs in. Account is derived from the email domain.
Full React and Next.js steps (provider, layout, privacy): Quick start (npm).
3. Track
Page views ($pageview) are automatic after setup(). Optional useTrack() calls record product moments. They count toward Activity and Recency. They only move Milestones when the event name is a default or custom milestone (see Understanding health scores).
4. Verify
Log in to your app and visit a couple of routes. Watch the live feed on Settings → SDK Configuration, or open Customer Insights once accounts appear. Append ?fd_debug=true locally for a debug badge.
Script tag: for static sites without a bundler, see the script-tag section on Quick start (npm).
Recommended server events
These eight typed names cover the backend moments that matter most for customer health. Use the ServerEvents constants so typos fail at compile time.
| Constant | Event name | Role |
|---|---|---|
ServerEvents.PaymentFailed | payment_failed | Risk signal (failed charge) |
ServerEvents.SubscriptionStarted | subscription_started | Paid plan begins |
ServerEvents.IntegrationSyncCompleted | integration_sync_completed | Recurring activity (sync finished) |
ServerEvents.FirstProductionApiCall | first_production_api_call | First live API usage |
ServerEvents.KycApproved | kyc_approved | One-time adoption moment |
ServerEvents.FirstDepositCompleted | first_deposit_completed | First funded deposit |
ServerEvents.SessionCompleted | session_completed | Recurring activity (aggregated session) |
ServerEvents.FirstPurchaseValidated | first_purchase_validated | One-time adoption moment |
All of these update Activity and Recency like other custom events. They move the Milestones component only if you add them as custom milestones in event settings (or if the name already matches a default milestone). Defaults today are browser-oriented names such as account_created and first_feature_used. See Understanding health scores.
Raw api (curl)
Prefer @firstdistro/sdk/server in production. For a one-off test, call the batch endpoint directly with a server key.
Endpoint: POST https://firstdistro.com/api/tracking/events/batch
Auth: X-API-Key: sk_live_… (or sk_test_…)
Required per event: eventName, timestamp. For server keys, send userId and accountId. sessionId is optional when authenticating with sk_* (browser keys still require it). Omit vendorId; it is inferred from the key.
curl -sS -X POST 'https://firstdistro.com/api/tracking/events/batch' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: sk_live_YOUR_KEY' \
-d '{
"batchId": "batch_test_001",
"events": [
{
"eventName": "payment_failed",
"userId": "user_123",
"accountId": "acct_456",
"timestamp": "2026-08-10T12:00:00.000Z",
"properties": {
"source": "server",
"failure_reason_category": "card_declined"
}
}
]
}'
Node equivalent:
await fetch('https://firstdistro.com/api/tracking/events/batch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.FIRSTDISTRO_API_KEY!,
},
body: JSON.stringify({
batchId: `batch_${Date.now()}`,
events: [
{
eventName: 'payment_failed',
userId: 'user_123',
accountId: 'acct_456',
timestamp: new Date().toISOString(),
properties: {
source: 'server',
failure_reason_category: 'card_declined',
},
},
],
}),
})
Pii guidance
Server events are the right channel for sensitive product signals. Keep properties minimal.
Never send: exact balances, card or account numbers, government IDs, full transaction amounts, raw KYC documents.
Send instead: enums and buckets, for example failure_reason_category: 'card_declined', verification_tier: 'standard', count_bucket: 'small'.
Treat every property as readable by support staff.
Health scores
Browser $pageview events power Activity, Engagement, and Recency out of the box. Recommended server events (and other custom track() calls) feed Activity and Recency the same way. The Milestones component only counts names in the default milestone list, names starting with milestone_, or custom milestones you configure. Details: Understanding health scores.
Next steps
- Quick start (npm): full React and Next.js browser path
- React hooks reference: hooks and options
- Event tracking guide: browser
track()best practices - MCP overview: query customer health from Claude or Cursor
- Understanding health scores: how scores are calculated