Custom Integration

A vs B talks to nine tools directly from the Integrations tab: Google Analytics 4, Google Tag Manager, Mixpanel, Segment, Amplitude, Heap, Fullstory, Contentsquare, and Adobe Analytics. For anything else, the event bus hands you every experiment event so you can route it wherever you like.

Google Tag Manager has its own card now

You no longer need custom code to get experiment data into the dataLayer. Turn on the Google Tag Manager card and A vs B pushes the events for you, with the field names and trigger name documented on the Google Tag Manager page. The rest of this page is for tools that have no card.

Subscribing to events

JavaScript
avsb.on?.('event', function (event) {  console.log('A vs B event:', event);});
JavaScript3 lines

avsb.on returns a function that removes your subscription, and you can subscribe as many times as you like. Where you put this matters: subscribe from Project JS and you catch every event, including the first experiment view. An inline script works too, as long as it sits below the install stub, which holds early calls until the snippet loads. See the event bus reference for the full record and the setup order.

onEvent has been removed

window.avsb.onEvent no longer exists. It held a single callback, so a second integration silently replaced the first. Replace window.avsb.onEvent = fn with avsb.on('event', fn). The data your function receives is the same, with more fields on it.

What you receive

TypeScript
const exampleEvent: AvsbIntegrationRecord = {  experiment_id: '482',  experiment_name: 'Homepage hero',  variation_id: '1913',  variation_name: 'Variant B',  event_type: 'exposure',        // branch on this, not on the name  event_name: 'avsb_experiment_viewed',  event_id: '3f9a2b1c-7d4e-4a58-9c02-5e6d1f8b3a47',  revenue: null,  value: null,  visitor_id: '...',  page_url: 'https://example.com/',  timestamp: 1753800000000,  sdk_version: '1.0.0'};
TypeScript15 lines

Purchases also carry currency and transaction_id, conversions carry goal_key, and recommendation events carry attributes. Records from preview or internal traffic carry source. Every field is listed on the event bus reference.

Examples

Send experiment views to a tool with no card:

JavaScript
avsb.on?.('event', function (event) {  if (event.event_type !== 'exposure') return;  myAnalytics.track('Experiment Viewed', {    experiment: event.experiment_name,    variation: event.variation_name  });});
JavaScript8 lines

Post everything to your own endpoint:

JavaScript
avsb.on?.('event', function (event) {  fetch('/api/experiment-events', {    method: 'POST',    headers: { 'Content-Type': 'application/json' },    body: JSON.stringify(event)  }).catch(function () {    // fail quietly: never interrupt the visitor  });});
JavaScript9 lines

Pendo:

TypeScript
// `pendo` is the global Pendo's own agent installs on the page.declare const pendo: { track(name: string, properties: Record<string, unknown>): void } | undefined;avsb.on?.('event', function (event) {  if (event.event_type !== 'exposure') return;  if (typeof pendo === 'undefined') return;  pendo.track('avsb_experiment', {    experiment_name: event.experiment_name,    variation_name: event.variation_name  });});
TypeScript12 lines

Ignore your own preview and internal traffic:

JavaScript
avsb.on?.('event', function (event) {  if (event.source) return; // preview or internal QA session  myAnalytics.track(event.event_name, { ...event });});
JavaScript4 lines
Your callback runs while the event is being processed

Keep it quick and avoid blocking work. Use fetch() or XMLHttpRequest asynchronously for network calls. If your code throws, A vs B carries on and any other subscribers still run.

When to use this

Reach for the bus when the tool you want has no card and is not reachable through Google Tag Manager. Common examples are Pendo, Intercom, HubSpot, an internal analytics system, or your own warehouse endpoint.

Was this helpful?