Event tracking guide
Track product usage events to power Customer Insights health scores and customer health monitoring.
Last Updated: June 7, 2026
Overview
Event tracking allows you to monitor how customers use your product. Events are automatically batched (20 per batch) and sent to FirstDistro every 5 seconds or on page unload.
Prerequisites: Before tracking events, ensure you've completed the Getting Started guide - specifically installing the SDK (see Installation Guide) and calling setup() to identify users.
What's captured automatically
Once you call setup(), the SDK automatically captures page views — you don't
need to track them manually:
- A
$pageviewsystem event fires on initial page load and on every SPA route change (History APIpushState/popstate). - Auto-capture is identity-gated: page views fire only after
setup()has set auserId(no anonymous tracking in v1). - Query strings are stripped by default from captured URLs and referrers to
keep PII and secrets out of FirstDistro. See the
Quick Start privacy section for
the
captureQueryParamsallowlist andmaskUrlhook.
These page views power Activity, Engagement, and Recency in your health scores
on their own. Do not call track('page_viewed') for navigation — it would
duplicate the automatic $pageview. Custom track() events (below) are optional
and sharpen the Milestones signal.
Basic tracking
Track an event
FirstDistro.track('event_name', {
property1: 'value1',
property2: 'value2'
});
Example events
// User actions
FirstDistro.track('user_signed_up', { plan: 'pro', source: 'website' });
FirstDistro.track('user_logged_in', { method: 'email' });
FirstDistro.track('user_logged_out');
// Feature usage
FirstDistro.track('feature_used', {
feature: 'export',
format: 'pdf',
page_count: 10
});
FirstDistro.track('feature_used', {
feature: 'import',
file_type: 'csv',
row_count: 1000
});
// Milestones
FirstDistro.track('milestone_reached', {
milestone: '100_users',
user_count: 100
});
FirstDistro.track('milestone_reached', {
milestone: 'first_payment',
amount: 99.00
});
Setting user and account context (recommended)
Use setup() to set both user and account context in one call. This is the recommended approach as it handles the correct ordering automatically.
FirstDistro.setup({
user: {
id: 'user-123',
name: 'John Doe',
email: 'john@example.com',
role: 'admin'
},
// account optional — server derives company from email domain
// account: { id: 'account-456', name: 'Acme Corp', plan: 'growth' }
});
When to call:
- After user logs in
- When user information loads (email required for account derivation)
- When switching accounts (pass optional
accountoverride)
Benefits of setup():
- One method instead of two
- Impossible to get the ordering wrong
- Cleaner, more readable code
Updating context:
// Update only user traits
FirstDistro.setup({
user: { id: 'user-123', role: 'superadmin' }
});
// Switch to a different account
FirstDistro.setup({
account: { id: 'new-account', name: 'New Team', plan: 'pro' }
});
Legacy: identify() / group() (deprecated)
Deprecated. The standalone
identify()andgroup()methods have been retired in favor of a singlesetup()call. Usesetup({ user: { id, email } })as shown above — it handles account derivation and ordering for you. New installs should not useidentify()orgroup().
Account context for customer insights
Customer Insights needs events linked to an account. With setup({ user: { id, email } }),
FirstDistro derives the account from the user's email domain server-side (corporate
email → company account; free email → per-user account).
Without user email in setup:
- ✅ Events are stored in the database
- ❌ Events may lack
account_idand won't be processed for health scoring - ❌ Customers won't appear in Customer Insights
With setup({ user: { id, email } }):
- ✅ Account is derived automatically from email domain
- ✅ Events are aggregated into
customer_accounts - ✅ Health scores are calculated on the cron schedule
- ✅ Customers appear in Customer Insights
Optional account override: Pass explicit account: { id, name, plan } only when
you need to override server derivation (e.g. multi-domain org).
Recommended pattern: setup() → page views are automatic
FirstDistro.setup({
user: { id: user.id, name: user.name, email: user.email },
});
// Page views are now captured automatically on navigation.
// Optionally track product milestones:
FirstDistro.track('feature_used', { feature: 'export' });
Advanced patterns: For complex account grouping scenarios (multiple accounts, account switching), call setup() again with the new account context when switching.
Handling logout
When a user logs out of your application, you must call FirstDistro.reset() to clear the current user session. This ensures that subsequent events are not incorrectly attributed to the previous user.
// Example: Call this in your logout handler
function handleLogout() {
// Clear FirstDistro user context BEFORE signing out
if (window.FirstDistro) {
FirstDistro.reset();
}
// ... your existing logout logic ...
}
Why this matters:
- The SDK persists
user_idandaccount_idin localStorage - Without
reset(), a new user logging in may inherit the previous user's context - This can cause events to be incorrectly attributed, polluting your analytics data
When to call reset():
- User clicks "Log out" or "Sign out"
- User session expires
- Before switching between accounts (if your app supports multiple accounts)
Recommended events
Track these events for best Customer Insights:
1. authentication events
user_signed_up- New user registrationuser_logged_in- User loginuser_logged_out- User logout
2. feature usage events
feature_used- Any feature interactiondata_imported- Data import completeddata_exported- Data export completedreport_generated- Report created
3. milestone events
milestone_reached- Important milestonesfirst_feature_used- First feature interactionmilestone_100_users- User count milestonesmilestone_1000_users- User count milestones
4. engagement events
- Page navigation — captured automatically as
$pageview; no manual tracking needed session_started- Session beginssession_ended- Session ends
Event properties
Include relevant properties with each event:
FirstDistro.track('feature_used', {
// Feature details
feature: 'export',
feature_category: 'data',
// Usage context
format: 'pdf',
page_count: 10,
file_size_kb: 250,
// User context (auto-added after setup())
user_id: 'user-123', // Auto-added
account_id: 'account-456', // Auto-derived from user email domain
// Custom properties
source: 'dashboard',
workflow: 'monthly_report'
});
Event batching
Events are automatically batched:
- Batch size: 20 events per batch
- Flush interval: 5 seconds
- Unload flush: Events sent on page close using
sendBeacon()
You don't need to manage batching - it's handled automatically!
Best practices
1. track key user actions
Focus on actions that indicate product value:
- Feature usage
- Data operations
- User milestones
- Engagement patterns
2. use consistent event names
Use snake_case and be descriptive:
- ✅
user_signed_up - ✅
feature_used - ✅
milestone_reached - ❌
signup(too vague) - ❌
click(not descriptive)
3. include relevant properties
Add properties that provide context:
- Feature names
- User/account identifiers
- Quantities (counts, sizes, etc.)
- Timestamps (auto-added)
4. use setup() for context
Use setup() to set user and account context - it handles the ordering automatically:
// Set user and account context in one call
FirstDistro.setup({
user: { id: user.id, name: user.name, email: user.email },
account: { id: account.id, name: account.name, plan: account.plan }
});
// Track events (both user_id and account_id auto-attached)
FirstDistro.track('feature_used', { feature: 'export' });
Why use setup():
- Handles correct ordering internally (account before user)
- Both user_id and account_id are automatically included in tracked events
- This ensures user data appears correctly in Customer Insights
Examples
React integration
Step 1: Add the script tag to your public/index.html:
<!-- Add before closing </body> tag -->
<script src="https://firstdistro.com/sdk/install/fd_your-token-here.js"></script>
Step 2: Use the SDK in your React components:
function App() {
useEffect(() => {
// SDK is automatically initialized after script loads
if (user && account) {
// Set user and account context in one call
FirstDistro.setup({
user: { id: user.id, name: user.name, email: user.email },
account: { id: account.id, name: account.name, plan: account.plan }
});
}
}, [user, account]);
const handleFeatureUse = () => {
FirstDistro.track('feature_used', {
feature: 'export',
format: 'pdf'
});
};
return <button onClick={handleFeatureUse}>Export</button>;
}
Get your token: Dashboard → Settings → SDK Configuration
Next.js integration
// app/layout.tsx
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Script
src="https://firstdistro.com/sdk/install/fd_your-token-here.js"
strategy="afterInteractive"
/>
{children}
</body>
</html>
);
}
Then use the SDK in your pages:
// app/page.tsx
'use client';
import { useEffect } from 'react';
export default function HomePage() {
useEffect(() => {
if (typeof window === 'undefined' || !window.FirstDistro) return;
// SDK is automatically initialized
if (user && account) {
// Set user and account context in one call.
// Page views are captured automatically after setup() — including this
// route and every subsequent client-side navigation.
window.FirstDistro.setup({
user: { id: user.id, name: user.name, email: user.email },
account: { id: account.id, name: account.name, plan: account.plan }
});
}
}, []);
return <div>Welcome</div>;
}
See the Installation Guide for complete setup instructions.
Troubleshooting
Events not sending?
- Check tracking is enabled in dashboard
- Verify API key is correct
- Check browser console for errors
- Verify network requests in Network tab
Events delayed?
- Events are batched (up to 5 seconds delay)
- Events flush on page unload
- This is normal behavior
Too many events?
- Use sample rate in dashboard config
- Filter events client-side before tracking
- Batch related events together
Customers not appearing in Customer Insights?
- Ensure you've called
FirstDistro.setup()withuser.email— the account is derived from the email domain server-side - Verify events include
account_id(check browser console) - See Getting Started guide for setup
"No users found" in Customer Detail Modal?
- Ensure you've called
FirstDistro.setup()with both user and account context - Verify user traits include name and email:
setup({ user: { id, name, email }, account: { id, name } }) - Check that events include
user_id(check browser console)
For more help, email us at hello@firstdistro.com.