Event Tracking
CADENCE uses three types of events to measure experiment outcomes. Understanding how they work helps you track the right things and get accurate results.
Event types
Exposure events (automatic)
When you call getVariant(), the SDK automatically tracks an exposure event. This records that a specific user saw a specific variant.
// This line tracks an exposure event behind the scenes
const variant = cadence.getVariant('hero-test')
You don't need to do anything extra. Exposure events include the experiment ID, variant ID, and user ID.
Call getVariant() once per page load
Each call to getVariant() sends an exposure event. If you call it in a component that re-renders frequently, you'll inflate your exposure count. Call it once and store the result.
Custom events
Track any user action with track():
cadence.track('button-click', { location: 'hero' })
cadence.track('page-view', { page: '/pricing' })
cadence.track('video-played', { duration: 30 })
Custom events are stored for analysis but don't directly appear in experiment results. Use them for behavioral insights alongside your tests.
Conversion events
Conversion events are the core metric for experiments. They measure whether users completed the action you're testing:
cadence.trackConversion('signup')
cadence.trackConversion('purchase', { value: 49.99, plan: 'pro' })
cadence.trackConversion('activation', { step: 'first-test-created' })
When you view experiment results in the dashboard, the conversion rate is calculated as:
Conversion Rate = Conversion Events / Exposure Events
Track at the right moment
Call trackConversion() after the action succeeds, not when the user clicks a button. For purchases, track after the payment API confirms success. For signups, track after the account is created. This prevents counting failed attempts as conversions.
Event properties
Every event includes these fields automatically:
| Field | Source | Description |
|-------|--------|-------------|
| event_type | SDK | 'exposure', 'custom', or 'conversion' |
| event_name | Your code | The name you passed to track() or trackConversion() |
| user_id | SDK config | From your userId or auto-generated |
| session_id | sessionStorage | Unique per browser tab, resets when tab closes |
| project_id | SDK config | Your project ID (from the config endpoint) |
| timestamp | SDK | ISO 8601 timestamp |
| user_agent | Browser | Captured automatically |
| ip_address | Server | Captured server-side during event ingestion |
| properties | Your code | Your custom key-value pairs |
For exposure events, these additional fields are included:
| Field | Description |
|-------|-------------|
| experiment_id | The experiment that was evaluated |
| variant_id | The variant assigned to the user |
How batching works
Events aren't sent immediately. The SDK queues them in memory and flushes in batches for performance:
- Every 5 seconds — If the queue has events, they're sent as a batch
- At 10 events — If the queue reaches 10 events, it flushes immediately
- On page unload — Remaining events are sent via
navigator.sendBeacon(reliable even during navigation) - On failure — If a batch fails to send, events are re-queued for the next attempt
This means there's a small delay (up to 5 seconds) before events appear in the dashboard. This is normal.
Viewing events
Navigate to Projects > [Your Project] > Events in the dashboard to see raw events. The events page shows:
- Event type and name
- User and session information
- Timestamp
- Properties
For experiment results, go to the experiment detail page. Events are automatically aggregated into conversion rates, lift percentages, and statistical significance.
Best practices
Name events consistently. Use kebab-case: purchase-complete, not PurchaseComplete or purchase_complete.
Include meaningful properties. Revenue, plan type, and other context make your data more useful:
cadence.trackConversion('purchase', {
value: 49.99,
plan: 'pro',
currency: 'USD',
})
Don't over-track. Focus on events that matter for your experiments. Tracking every mouse move creates noise without value.
Deduplicate conversions in your logic. The SDK doesn't deduplicate. If a user can convert multiple times, decide whether you want to count all conversions or just the first.
Next steps
- Creating Tests — Set up experiments that use these events
- Reading Results — How conversion events become experiment results
- API Reference — Full method signatures