Event tracking guide
Track product usage events to power Customer Insights health scores.
Events show how customers use your product. The browser SDK batches them (about 20 per batch, every 5 seconds or on page unload) and sends them to FirstDistro.
Prerequisites: Install the SDK and call setup() so events link to a user and account. New here? Start with Getting started.
Server events
For backend truth (payments, KYC, syncs, sessions), use @firstdistro/sdk/server with a secret sk_* key. See the Server tab on Install for install → init → track → verify, curl examples, and the recommended server events. In Cursor, server wiring uses @firstdistro/mcp tools get_server_event_template, setup_server_tracking, and check_server_events_flowing. See MCP overview.
When those server events are active in event settings, they can also trigger CS playbooks and Today's 5 cards. See Server risk events and CS playbooks.
What is captured automatically
Once you call setup(), the SDK captures page views. You do not track them manually:
- A
$pageviewsystem event fires on initial page load and on every SPA route change. - Auto-capture is identity-gated: page views fire only after
setup()has set auserId. - Query strings are stripped by default. See Quick start privacy for
captureQueryParamsandmaskUrl.
These page views power Activity, Engagement, and Recency on their own. Do not call track('page_viewed') for navigation. That would duplicate $pageview. Custom track() events below are optional. They feed Activity and Recency, and move Milestones only when the name is a default or custom milestone.
Basic tracking
FirstDistro.track('feature_used', {
feature: 'export',
format: 'pdf',
page_count: 10,
});
Prefer React hooks from @firstdistro/sdk/react when you use the npm package. See Quick start and React hooks.
Setting user and account context
Use setup() (or useFirstDistroSetup in React) with user id and email. FirstDistro derives the company account from the email domain. Pass account only to override (for example a multi-domain org).
FirstDistro.setup({
user: {
id: 'user-123',
name: 'Jane Doe',
email: 'jane@acme.com',
},
});
Without email in setup: events may lack account_id and will not score for Customer Insights.
With email: account is derived, events aggregate into customer accounts, and health scores update on schedule.
Deprecated: Do not use standalone
identify()/group(). Usesetup()only.
Handling logout
Call FirstDistro.reset() on logout so the next user does not inherit the previous context from localStorage.
function handleLogout() {
if (window.FirstDistro) {
FirstDistro.reset();
}
// ... your logout logic
}
Recommended browser events
Default milestones the product already recognizes:
account_createdfirst_feature_useddata_importeduser_invitedmilestone_100_usersmilestone_1000_users
Useful optional custom events:
feature_usedwith afeaturepropertyuser_signed_up/user_logged_inwhen those moments matter for your funnel
Page navigation is captured automatically as $pageview. For backend payments, KYC, and syncs, use the recommended server events.
Event properties
Keep properties small and useful. Avoid PII and secrets.
FirstDistro.track('feature_used', {
feature: 'export',
feature_category: 'data',
format: 'pdf',
page_count: 10,
});
After setup(), user_id and account_id are attached automatically.
Event batching
- Batch size: 20 events
- Flush interval: about 5 seconds
- Unload flush:
sendBeacon()on page close
You do not manage batching yourself.
Best practices
- Track actions that show product value, not every click.
- Use snake_case names (
feature_used, notclick). - Prefer enums and buckets over raw balances or IDs in properties.
- Always
setup()with email before expecting Customer Insights rows.
Troubleshooting
Events not sending? Check the dashboard, browser console, and network tab. Confirm your install token.
Events delayed? Batching can add a few seconds. Flush on unload is normal.
Customers missing from Customer Insights? Call setup() with user.email. See Getting started.
For more help: hello@firstdistro.com.