Event Dispatching and Analytics
The problem: reliable tracking without performance cost
Section titled “The problem: reliable tracking without performance cost”Experiments are only useful if you can measure their outcomes. Every time a visitor clicks a button, completes a purchase, or reaches a milestone, that conversion event must reach Optimizely’s analytics backend. But sending an HTTP request on every single event would slow down your application and create a fragile dependency on network availability.
Optimizely solves this by decoupling event capture from event delivery. Events are collected locally, batched together, and dispatched asynchronously. If delivery fails, events are retried. Your application never waits for analytics to respond.
How events flow through the system
Section titled “How events flow through the system”The event pipeline has four stages, shared conceptually by both Feature Experimentation and Web Experimentation:
- Capture — Your code signals that something happened (a click, a purchase, a signup).
- Enrich — The SDK or snippet attaches context: which experiment the user is in, which variation they saw, user attributes, and a timestamp.
- Batch — Multiple events are grouped into a single network payload to reduce HTTP overhead.
- Dispatch — The batched payload is sent to Optimizely’s event endpoint via HTTPS POST.
Once events reach Optimizely’s backend, Stats Engine processes them, updates experiment results, and determines statistical significance.
Event tracking in Feature Experimentation
Section titled “Event tracking in Feature Experimentation”In Feature Experimentation, you explicitly track events in your application code:
// Track a conversion eventoptimizelyClient.track('purchase_completed', userId, { revenue: 4999, // in cents currency: 'USD'});The SDK handles the rest. It attaches the user’s experiment assignments, bundles the event into a batch, and dispatches it asynchronously. Your application code does not block on the network call.
Event batching
Section titled “Event batching”Server-side SDKs batch events to reduce network overhead. The batch processor collects events and flushes them based on two triggers:
- Batch size — When the queue reaches a configurable number of events (default: 10), the batch is dispatched.
- Flush interval — When a configurable time period elapses (default: 30 seconds), whatever is in the queue is dispatched regardless of size.
You can tune both parameters at SDK initialization. High-traffic applications benefit from larger batch sizes. Low-traffic applications benefit from shorter flush intervals to avoid stale data.
Retry logic
Section titled “Retry logic”If a dispatch fails (network timeout, server error), the SDK retries with exponential backoff. Events are not lost on transient failures. However, if your application shuts down before a flush completes, queued events may be lost. Call close() on the SDK during graceful shutdown to flush remaining events.
Custom event dispatchers
Section titled “Custom event dispatchers”For environments with specific networking requirements — corporate proxies, custom logging, or compliance constraints — you can replace the default event dispatcher with your own implementation. A custom dispatcher receives the event payload and is responsible for delivering it.
Common use cases for custom dispatchers:
- Warehouse-native analytics — Route events to your data warehouse (Snowflake, BigQuery, Redshift) instead of or in addition to Optimizely
- Queue-based delivery — Write events to a message queue (Kafka, SQS) for guaranteed delivery
- Compliance filtering — Strip or hash PII attributes before events leave your infrastructure
Event tracking in Web Experimentation
Section titled “Event tracking in Web Experimentation”Web Experimentation tracks events differently because it runs in the browser:
- Automatic tracking — Click goals and pageview goals defined in the Optimizely UI are tracked automatically. The snippet attaches event listeners to matching elements.
- Custom events — For events that are not simple clicks or pageviews, you use the push API:
// Track a custom conversion eventwindow.optimizely.push({ type: 'event', eventName: 'purchase_completed', tags: { revenue: 4999, currency: 'USD' }});The snippet dispatches events using the browser’s navigator.sendBeacon() API when available, falling back to XHR. Beacon is preferred because it reliably delivers data even during page unload — visitors navigating away do not cause lost events.
Shared analytics infrastructure
Section titled “Shared analytics infrastructure”After events reach Optimizely’s backend, the processing pipeline is identical:
- Deduplication — Duplicate events (from retries) are identified and collapsed.
- Attribution — Events are attributed to the correct experiment and variation based on the user context attached at capture time.
- Aggregation — Raw events are rolled up into metrics: conversion rates, revenue per visitor, and other KPIs.
- Statistical analysis — Stats Engine applies sequential testing to determine whether observed differences are statistically significant.
Results appear on the experiment results page, typically within minutes of event dispatch.
Revenue tracking
Section titled “Revenue tracking”Both products support revenue tracking by attaching a revenue tag to events. Revenue values should be in the smallest currency unit (cents for USD, pence for GBP). Optimizely aggregates revenue per visitor and calculates statistical significance on revenue metrics just like conversion rates.
Event volume and tier limits
Section titled “Event volume and tier limits”Event capacity scales with your Optimizely plan tier:
| Tier | Monthly event capacity |
|---|---|
| Essential | Included allocation per contract |
| Enhanced | Higher allocation with overage pricing |
| Advanced | Significantly higher allocation |
| Ultimate | Custom allocation with dedicated support |
If your application generates high event volume, use batching aggressively and consider filtering low-value events before dispatch. Not every user interaction needs to be an experiment metric.
Debugging event dispatch
Section titled “Debugging event dispatch”When events are not appearing in results, check these common causes:
- SDK not initialized — Events tracked before the SDK finishes initialization are silently dropped.
- Event key mismatch — The event name in
track()must exactly match the event key defined in the Optimizely app. - Missing decision — A user who was never bucketed into an experiment will not have their events attributed to that experiment.
- Flush timing — Events are batched. Check whether your flush interval is long enough that you are simply waiting for the next batch.
- Network failures — Inspect outbound requests to
logx.optimizely.comto confirm events are being dispatched.