> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abtestly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GA4 dataLayer integration

> How ABTestly pushes an experience_impression event into window.dataLayer, and how to read the exp_variant_string field in GA4.

The GA4 adapter (turn it on under
[Settings → Analytics](/settings/analytics-adapters)) makes ABTestly
push one event per exposure into `window.dataLayer`. Your GA4 property
picks it up like any other custom event.

## The event

Per (visitor, experiment, pageview):

```js theme={null}
window.dataLayer.push({
  event: 'experience_impression',
  experiment_id: '<uuid>',
  experiment_name: '<name>',
  experiment_number: '<short numeric id>',
  variant_key: 'control' | 'variant-1' | …,
  variant_name: '<variant name>',
  exp_variant_string: '<experiment_id>.<variant_key>',
});
```

The event name is `experience_impression`. The single most useful
field is `exp_variant_string`, which follows GA4's convention for
experiment slicing.

## In GA4

To slice any GA4 conversion by variant:

1. **Admin → Custom definitions → Create custom dimension.**
2. **Dimension name**, "ABTestly variant".
3. **Scope**, User (persists across events for this user).
4. **User property**, `exp_variant_string`.

Then in Explorations, add "ABTestly variant" as a dimension. Every
built-in conversion report can now be split by variant, alongside
your other GA4 dimensions.

## Where the event fires

On exposure. That is once per (visitor, experiment, pageview), not
once per goal, not once per session. The event lands **at the moment
the variant applies**, which is what you want for attributing
downstream conversions.

## Consent

The GA4 adapter respects the same consent gate as ABTestly's own
beacons. In deferred consent mode, the adapter waits for grant
before pushing anything.

If you have GA4 consent mode set up on your side, the two systems
compose. ABTestly does not push its event until its own consent
gate is satisfied; GA4 does not fire its conversion until its own
consent mode allows it.

## In preview

Adapter pushes are suppressed in preview. Your GA4 property does not
see previewed exposures.

## When the SDK is not on the page

If `window.dataLayer` does not exist when the exposure fires, the
adapter no-ops silently and reports a first-occurrence-per-session
`/err` event. Your dashboard's Snippet health panel will surface
that.

Fix: load `gtag.js` (or GTM's snippet) somewhere in `<head>`, before
or after ABTestly, either order works, as long as
`window.dataLayer` is defined by the time an experiment first
exposes.

## Other analytics adapters

Same shape, different SDK calls, see
[Product analytics](/product-analytics) for Segment, RudderStack,
Amplitude, Mixpanel.
