Skip to content

A/B Test Tracking

When you run an A/B test using an external tool (Google Optimize’s replacement, VWO, Optimizely, Kameleoon), you need to send the test assignment to GA4 so you can split your conversion data by variant. This recipe covers the dataLayer integration for any testing tool, plus how to model the data correctly in GA4.

Every A/B testing tool assigns the user to a variant before the page renders. The right place to push the variant assignment to the dataLayer is immediately after your testing tool determines the assignment — usually in a callback or immediately after the tool’s script initialises.

dataLayer.push() experiment_impression

Push this when the test variant is assigned, before the variant renders.

// Generic pattern — adapt to your testing tool's callback
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'experiment_impression',
experiment_id: 'checkout-button-color-v2',
experiment_name: 'Checkout Button Color Test',
variant_id: 'B',
variant_name: 'Green Button'
});
// VWO onActivate callback
VWO.event('vwo-loaded', function(data) {
var campaignData = data.campaignData;
for (var id in campaignData) {
if (campaignData.hasOwnProperty(id)) {
var campaign = campaignData[id];
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'experiment_impression',
experiment_id: 'vwo_' + id,
experiment_name: campaign.name,
variant_id: String(campaign.variationId),
variant_name: campaign.variationName
});
}
}
});
  1. Create a Custom Event Trigger

    • Trigger type: Custom Event
    • Event name: experiment_impression
  2. Create Data Layer Variables

    • DLV - experiment_idexperiment_id
    • DLV - experiment_nameexperiment_name
    • DLV - variant_idvariant_id
    • DLV - variant_namevariant_name
  3. Create a GA4 Event Tag

    • Event name: experiment_impression
    • Parameters:
      • experiment_id{{DLV - experiment_id}}
      • experiment_name{{DLV - experiment_name}}
      • variant_id{{DLV - variant_id}}
      • variant_name{{DLV - variant_name}}
    • Trigger: the Custom Event trigger
  4. Register custom dimensions in GA4

    Go to GA4 → Admin → Custom Definitions → Custom Dimensions:

    • experiment_id → Event scope
    • experiment_name → Event scope
    • variant_id → Event scope
    • variant_name → Event scope
  5. Set as a User Property for session-level persistence

    If you want to filter conversion events by variant (not just filter experiment impression events), set the variant as a user property:

    In your GA4 event tag, add a User Property:

    • Name: active_experiment
    • Value: {{DLV - experiment_id}}_{{DLV - variant_id}}

    Register this in GA4 → Admin → Custom Definitions → User Properties as well.

Tag Configuration

GA4 - experiment_impression

Type
Google Analytics: GA4 Event
Trigger
Custom Event - experiment_impression
Variables
DLV - experiment_idDLV - variant_idDLV - variant_name

Once the user property is set, you can split any GA4 report by experiment variant:

  1. Go to Explore → Blank Exploration
  2. Add dimension: User > active_experiment
  3. Add metrics: Conversions, Purchase revenue, Engaged sessions per user
  4. Filter to only users who were exposed to the test

For statistical significance, export the data to Google Sheets or BigQuery and run a chi-squared test or Bayesian analysis. GA4 does not have built-in statistical significance testing.

  1. Open GTM Preview and navigate to the page with the A/B test
  2. Trigger the variant assignment (your testing tool should do this on page load)
  3. Verify experiment_impression fires in the Summary pane
  4. Check variant_id and experiment_id are correct in the Variables tab
  5. In GA4 DebugView, verify the event appears with the variant parameters

Testing tool fires after GTM. If the testing tool loads asynchronously after GTM, the dataLayer push may arrive before the testing tool has determined the variant. Use the testing tool’s own callback or activation hook, not a hardcoded delay.

Anti-flicker snippet timing. Many testing tools hide the <body> content with CSS until the variant is applied, to prevent flash of original content. The dataLayer push timing should match the variant application, not the page load.

Multiple experiments running simultaneously. If you run multiple experiments at once, push separate experiment_impression events for each. Do not try to concatenate them into a single event.