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 $pageview system event fires on initial page load and on every SPA route change (History API pushState / popstate).
  • Auto-capture is identity-gated: page views fire only after setup() has set a userId (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 captureQueryParams allowlist and maskUrl hook.

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

javascript
FirstDistro.track('event_name', {
  property1: 'value1',
  property2: 'value2'
});

Example events

javascript
// 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
});

Use setup() to set both user and account context in one call. This is the recommended approach as it handles the correct ordering automatically.

javascript
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 account override)

Benefits of setup():

  • One method instead of two
  • Impossible to get the ordering wrong
  • Cleaner, more readable code

Updating context:

javascript
// 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() and group() methods have been retired in favor of a single setup() call. Use setup({ user: { id, email } }) as shown above — it handles account derivation and ordering for you. New installs should not use identify() or group().

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_id and 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

javascript
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.

javascript
// 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_id and account_id in 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)

Track these events for best Customer Insights:

1. authentication events

  • user_signed_up - New user registration
  • user_logged_in - User login
  • user_logged_out - User logout

2. feature usage events

  • feature_used - Any feature interaction
  • data_imported - Data import completed
  • data_exported - Data export completed
  • report_generated - Report created

3. milestone events

  • milestone_reached - Important milestones
  • first_feature_used - First feature interaction
  • milestone_100_users - User count milestones
  • milestone_1000_users - User count milestones

4. engagement events

  • Page navigation — captured automatically as $pageview; no manual tracking needed
  • session_started - Session begins
  • session_ended - Session ends

Event properties

Include relevant properties with each event:

javascript
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:

javascript
// 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:

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:

tsx
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

tsx
// 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:

tsx
// 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() with user.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.