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.

typescript
// 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():

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

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

  1. Every 5 seconds — If the queue has events, they're sent as a batch
  2. At 10 events — If the queue reaches 10 events, it flushes immediately
  3. On page unload — Remaining events are sent via navigator.sendBeacon (reliable even during navigation)
  4. 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:

typescript
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