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.
The dataLayer pattern
Section titled “The dataLayer pattern”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.
Push this when the test variant is assigned, before the variant renders.
// Generic pattern — adapt to your testing tool's callbackwindow.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'});Integration with common testing tools
Section titled “Integration with common testing tools”// VWO onActivate callbackVWO.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 }); } }});// Optimizely Web - listen for activation eventsoptimizely.push({ type: 'addListener', filter: { type: 'lifecycle', name: 'activated' }, handler: function(event) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'experiment_impression', experiment_id: event.data.experimentId, experiment_name: event.data.experimentName, variant_id: event.data.variationId, variant_name: event.data.variationName }); }});Kameleoon.API.Experiment.triggerConversion = function(experimentId, goalId) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'experiment_impression', experiment_id: String(experimentId), variant_id: String(Kameleoon.API.Experiment.getAssignedVariationId(experimentId)) });};GTM Configuration
Section titled “GTM Configuration”-
Create a Custom Event Trigger
- Trigger type: Custom Event
- Event name:
experiment_impression
-
Create Data Layer Variables
DLV - experiment_id→experiment_idDLV - experiment_name→experiment_nameDLV - variant_id→variant_idDLV - variant_name→variant_name
-
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
- Event name:
-
Register custom dimensions in GA4
Go to GA4 → Admin → Custom Definitions → Custom Dimensions:
experiment_id→ Event scopeexperiment_name→ Event scopevariant_id→ Event scopevariant_name→ Event scope
-
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.
- Name:
GA4 - experiment_impression
- Type
- Google Analytics: GA4 Event
- Trigger
- Custom Event - experiment_impression
- Variables
-
DLV - experiment_idDLV - variant_idDLV - variant_name
Analysing A/B test results in GA4
Section titled “Analysing A/B test results in GA4”Once the user property is set, you can split any GA4 report by experiment variant:
- Go to Explore → Blank Exploration
- Add dimension:
User > active_experiment - Add metrics:
Conversions,Purchase revenue,Engaged sessions per user - 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.
Test it
Section titled “Test it”- Open GTM Preview and navigate to the page with the A/B test
- Trigger the variant assignment (your testing tool should do this on page load)
- Verify
experiment_impressionfires in the Summary pane - Check
variant_idandexperiment_idare correct in the Variables tab - In GA4 DebugView, verify the event appears with the variant parameters
Common gotchas
Section titled “Common gotchas”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.