Skip to main content

GA4 export

ABTestly pushes a Google-spec experience_impression event to your site’s dataLayer so you can cross-check experiment exposures (and run deeper GA4-native analysis) inside your own GA4 property. The data lands in your GA4 — ABTestly never sees it. This is off by default. Enable it per site under Site → GA4 Integration.
ABTestly’s built-in results remain the primary analysis surface (clean significance math, sample-ratio checks, per-variant lift with CIs). The GA4 export is for cross-validation and for richer GA4-native explorations (e.g. conversion-by-variant for one experiment via the Segment recipe below, or unconstrained multi-experiment SQL in BigQuery).

How it works

When a visitor is bucketed into a running experiment, the snippet pushes the Google official A/B-testing vendor event:
window.dataLayer.push({
  event: 'experience_impression',
  exp_variant_string: 'ABT-7-1',     // canonical combined dimension
  experiment_id: '7',                // per-org display number
  variant_id: '1',                   // variant index (0 = control)
  experiment_name: 'Change hero text' // optional, human-readable
});
The event name and exp_variant_string parameter follow Google’s official spec for third-party A/B-testing tools, which means our data plugs into standard GA4 A/B tooling and Looker Studio templates designed for it. The ABT- prefix scopes the dimension to ABTestly experiments. The push is consent-gated: under Google Consent Mode v2 deferred mode, no event fires until consent is granted. It also only fires for sites where the GA4 toggle is on.

Event parameters

ParameterDescriptionExample
exp_variant_stringCanonical combined dimensionABT-7-1
experiment_idPer-org experiment number (string)7
variant_idVariant index, 0 = control (string)1
experiment_nameHuman-readable experiment name (optional)Change hero text

Concurrent experiments

A visitor in N experiments fires N experience_impression events per page — one per experiment. That is correct and required: it’s what the per-experiment Segment recipe below relies on. There is no single “the variant” for a visitor when they’re in multiple tests — that’s a property of how A/B attribution works, not a tool limitation.

Setup (≈ 5 minutes)

The fastest path is the Google Tag Manager container template, which wires up everything except your Measurement ID.
1

Import the GTM container

Download the template from Site → GA4 Integration → Download GTM container. In Google Tag Manager: Admin → Import Container → choose a workspace → Merge. It creates the four Data Layer Variables, the experience_impression trigger, and a GA4 event tag.
2

Point the tag at your GA4

Open the imported GA4 - ABTestly experience_impression tag and set its Measurement ID to your G-XXXXXXXXXX (or reference your existing GA4 configuration tag).
3

Register the Custom Dimensions in GA4

In GA4: Admin → Custom definitions → Create custom dimension. Create event-scoped dimensions matching the event parameter names: exp_variant_string, experiment_id, variant_id, and (optional) experiment_name.
Not retroactive. GA4 only captures dimension values from the moment a Custom Dimension is registered. Register these before you start experiments you plan to analyze in GA4, or you’ll have impression events with empty dimension values.
4

Publish and enable

Publish the GTM container, then turn on the Export to GA4 toggle in ABTestly.

Without Google Tag Manager

If you tag GA4 directly (gtag.js) instead of GTM, listen for the experience_impression event and forward the parameters to GA4:
window.dataLayer = window.dataLayer || [];
const _push = window.dataLayer.push.bind(window.dataLayer);
window.dataLayer.push = function (item) {
  if (item && item.event === 'experience_impression') {
    gtag('event', 'experience_impression', {
      exp_variant_string: item.exp_variant_string,
      experiment_id: item.experiment_id,
      variant_id: item.variant_id,
      experiment_name: item.experiment_name
    });
  }
  return _push(item);
};
You still need to register the matching event-scoped Custom Dimensions in GA4 (step 3 above).

Verifying it works

  1. Open your site with GA4’s DebugView active (or the GTM Preview pane).
  2. Trigger an experiment exposure (load a page where a running test targets you).
  3. You should see an experience_impression event with exp_variant_string, experiment_id, variant_id, and experiment_name.
Custom Dimensions can take up to 24–48 hours to populate in standard reports; DebugView shows them immediately.

GA4 numbers vs your ABTestly dashboard

If you compare the experience_impression count in GA4 to the participant count on your ABTestly dashboard, GA4’s number will usually be higher. That’s expected — the two counts measure different things.
  • experience_impression (GA4) is an exposure event. It fires when a visitor sees an experiment on a qualifying page view. GA4 counts events.
  • Participants (ABTestly dashboard) are distinct visitors. Each visitor is counted once per experiment, no matter how many times they view the tested page.
So a visitor who views the tested page three times in a session generates three experience_impression events but is one participant. This is by design, not a discrepancy.
Compare variants in GA4 with rates, not counts. For a variant comparison inside GA4, analyse conversion rate per variant — conversions ÷ exposures (or conversions ÷ users, when using a User segment) — segmented by exp_variant_string. Rates are robust to the events-vs-participants difference; raw impression counts are not. The Segment recipe below sets this up correctly.
For an apples-to-apples participant count in GA4, build the Segment recipe below with User segments rather than Session segments — GA4’s user join gives you a per-visitor view that matches the way ABTestly counts participants.

Analyzing one experiment in GA4 (the Segment recipe)

Why you can’t just put exp_variant_string as a dimension against a conversion metric. GA4 event-scoped Custom Dimensions populate only on events that carry the parameter. Your conversion events (signup, purchase, …) don’t carry exp_variant_string, so a cross-tab “signup count by variant” reads (not set). This is a GA4 mechanic, not a bug. The correct approach — used by every other vendor that follows this spec — is Segments in an Exploration.

Recipe — one variant per segment, then compare

To break down a conversion event by variant for one experiment (say, display number 7), do this once per variant:
1

Open Explore → Free form

In GA4: Explore → + → Free form.
2

Create one Segment per variant

Click Segments → + and choose User segment (preferred — survives across sessions when User-ID or Google Signals is on) or Session segment (single-session). Add an Include condition:Event experience_impression with parameter exp_variant_string exactly matches ABT-7-0 (the control).Save as “Exp 7 · Control”. Repeat for each variant — ABT-7-1, ABT-7-2, etc.
3

Build the comparison

Drop the segments into the Segment comparisons slot. Drop your conversion event count (or revenue) into Values. The table now shows that metric per variant — the right way.

What this method gives you

  • A conversion metric (signups, revenue, anything in GA4) attributed per variant for one experiment, using GA4’s session/user join — the same attribution GA4 uses for everything else.
  • Works for any event the customer already tracks in GA4 — no need to forward the variant onto every conversion event.

Caveats — these are GA4 mechanics, not ABTestly bugs

  • Not retroactive. Custom Dimensions only capture data from registration forward. Register them before you need to analyze.
  • One experiment at a time. A visitor in N experiments carries N exp_variant_string values; there is no single “the variant” for a conversion event. Build one set of Segments per experiment. For across- experiment analysis at scale, use BigQuery.
  • Cross-device / cross-session attribution. GA4’s “user” is per-browser- cookie unless you have User-ID set or Google Signals on. Without one of those, a user who is exposed on desktop and converts on mobile counts as two users.
  • 4-comparison limit in standard reports. Standard reports cap at four comparisons. Experiments with 5+ variants must use Explorations (Segment comparisons handle more).
  • (other) cardinality rollup. GA4 collapses high-cardinality dimension values into (other) in standard reports for properties with many running experiments. The Segment recipe avoids this (it filters to a specific string), which is another reason to prefer it over broad dimensional cross-tabs.

When you need more — BigQuery

For power users — many concurrent experiments, exact attribution across overlapping tests, or no dimension/audience caps — pipe GA4 to BigQuery and join impressions to conversions on user_pseudo_id with the parameterized SQL we ship. See GA4 BigQuery analysis.

Importing GA4 goals

Re-using an existing GA4 conversion as an experiment goal is on the roadmap but not yet available. If you need it, let us know at support@abtestly.com and we’ll prioritise it.