Event Tracking

A vs B tracks two kinds of events. A variation is one specific version being tested: the control or one of the challengers. An exposure is the moment a visitor gets assigned to a variation, and that variation activates. A conversion fires when a visitor completes something one of your metrics measures, like clicking a button or viewing a page. Knowing how these are collected and sent helps you debug data gaps and plan your own custom tracking.

Exposure events

Exposures are the denominator in your results: they tell A vs B how many visitors were in each variation group.

Important properties of exposure tracking:

  • Counted once per visitor per experiment: however many pages a visitor views, your results count them once for that experiment. Ten visits from the same visitor is still one exposure.
  • Sent once per browser session: the snippet remembers, until the browser tab is closed, which exposures it has already sent. Reloading the page or moving to another page does not send the same exposure again. A different variation (after avsb.forceVariation()) or a different visitor ID (after avsb.setVisitorId()) is sent as a new exposure.
  • Queued the moment the variation activates: this happens before any conversion event for that visitor can be queued.
  • Sent in the next batch: see Event batching below for exactly when that is.

Conversion events

A vs B sets up tracking automatically based on your metric configuration:

  • Click metrics: A vs B listens for clicks anywhere on the page. It checks whether the element you clicked, or one of its parent elements, matches your metric's CSS selector. This also catches elements added to the page after it loaded, since the listener is not tied to specific elements.
  • Pageview metrics: A vs B fires a conversion when the visitor loads the target URL. On single-page apps, it re-checks on every client-side navigation, so this fires again on every visit to the target URL.
  • Custom events: fire these yourself by calling avsb.track.event(eventKey) from your own code. eventKey is the same text you typed as the metric's event key when you created it. A number works too: A vs B compares it as text.
  • Revenue and other values: pass a second argument, avsb.track.event(eventKey, { revenue: 49.99 }). Use value instead of revenue for a metric that averages or ranks a number that is not money, like page-load time or items purchased.
Unknown event key

If eventKey does not match any metric's event key, nothing is tracked. A vs B logs a console warning naming the keys it does know. A typo, or a metric you have not created yet, is easy to spot while you are instrumenting.

Conversion deduplication

By default, your results count a visitor as converted at most once per metric per experiment, however many times they trigger it. If the same visitor clicks a button ten times in one session, your results still show one conversion for that visitor.

Some metric types, revenue among them, can be configured to count every occurrence instead of just the first. This lets you count every purchase, for example, rather than only whether a visitor purchased at all. Check the individual metric's settings for this option.

Event batching

Sending every event as its own network request would be slow and wasteful. Instead, A vs B collects events in memory and sends them in batches, whichever of these happens first:

  • Every 2 seconds: a repeating timer flushes whatever is queued.
  • The instant 10 events are queued: a busy page does not wait out the full 2 seconds.
  • When the visitor leaves: closes the tab, navigates away, or puts the browser in the background. A vs B immediately flushes everything queued, using the browser's sendBeacon API so the send survives the page closing.
sendBeacon

navigator.sendBeacon is a browser API built for sending analytics data as a page unloads. A normal fetch request can be cancelled when the page closes; sendBeacon hands the request to the browser, which keeps sending it after the page is gone. It is best effort, not a guarantee: a beacon can still be lost to a dropped connection or a device going offline. Where the browser refuses it, A vs B falls back to a fetch request with keepalive set.

Manual event tracking

Fire custom events from anywhere in your code using avsb.track.event(). Pass the metric's event key (the text you typed when you created the metric) and an optional properties object for revenue or another value. This is useful for actions a CSS selector cannot capture: a form submission, a video play, a custom interaction.

JavaScript
// Track a custom event ('signup_completed' is the metric's event key)avsb.track.event('signup_completed');// Track a revenue event with a valueavsb.track.event('purchase_completed', { revenue: 79.99 });// Track from within variation JSconst submitButton = document.querySelector('#checkout-form button[type="submit"]');if (submitButton) {  submitButton.addEventListener('click', () => {    avsb.track.event('checkout_submitted');  });}
JavaScript13 lines
Tip

Custom events you fire with avsb.track.event() are automatically attributed to whatever experiment and variation the visitor is currently in. You never pass an experiment ID: A vs B handles attribution internally.

Where the data goes

Events are sent to A vs B's data ingestion endpoint (ingest.avsb.cloud). From there, they flow into the analytics pipeline and are processed to compute experiment results. Results are typically visible in the dashboard within a few minutes of events being sent.

Error capture

Alongside exposures and conversions, the snippet reports errors and warnings produced by your running variations. This helps you catch a broken variation before it costs you conversions:

  • Uncaught variation errors: exceptions thrown by a variation's custom JavaScript, including asynchronous ones, attributed to the exact experiment and variation that produced them.
  • Visual-change failures: a warning when a visual edit's target element cannot be found on the page, or an error when applying an edit throws.
  • Project JavaScript errors: exceptions thrown by your Project JS. See Project JavaScript for what is and is not caught.

Reports are de-duplicated per page load and batched to the ingestion endpoint the same way events are: every 10 seconds and on page hide.

What we don't capture

Error reports are scrubbed before they leave the browser. Page URLs have their query string and hash stripped, and messages and stack traces are truncated. No DOM node contents or form values are ever included. Captured errors are kept for 90 days.

Was this helpful?