Skip to main content

GA4 / dataLayer Tracking Modes

If your site already pushes events to a dataLayer (typically for GA4), the SDK can read from it instead of — or alongside — collecting its own events. Set this with data-tracking-mode (or trackingMode in b2mConfig). Unrecognized or empty values silently fall back to native, so a typo in the mode name won't throw an error — it just won't behave as expected.

native (default)datalayerhybrid
SDK generates its own events?Yes — all of themNo — none of themOnly names not already seen in the dataLayer
Listens to the dataLayer?NoYesYes
Platform tracker (Ticimax/Shopify/...)RunsDoes not runRuns
Auto click/scroll/engagement trackingRunsDoes not runRuns for names the dataLayer doesn't provide
RiskDuplicate data if a dataLayer also existsData loss if the dataLayer has gaps—

Which Mode Should You Pick?​

  • No dataLayer, or it's unreliable / partially populated → native (the default — don't set the attribute at all).
  • dataLayer is complete — everything that goes to GA4, including the full e-commerce funnel, is already pushed → datalayer. The SDK never becomes a second source, so there's zero duplication risk.
  • dataLayer exists but has gaps — e.g. purchase is pushed but scroll_depth isn't → hybrid. The SDK fills in exactly the gaps.

How Hybrid Decides, Exactly​

The distinction is per event name, and it's dynamic: the moment a given name is seen once in the dataLayer, the dataLayer owns that name for the rest of the page — the SDK stops generating it from its own sources (auto-track, platform tracker, SPA routing). Names never seen keep flowing from the SDK.

In practice: on the same page, purchase can come from the dataLayer while scroll_depth comes from the SDK — and if you later add scroll_depth to the dataLayer too, the SDK stops sending it automatically, with no configuration change needed.

Login identity in dataLayer mode

If the dataLayer includes user_id, it overrides the SDK's own identity for that event. If you write to both the dataLayer and b2mSetUserId, the dataLayer value wins. On logout, either b2mSetUserId(null) or dataLayer.push({ user_id: null }) clears a sticky dataLayer identity.

data-event-groups is still required in every mode — the tracking mode decides where an event's data comes from, event-group gating decides which names are accepted at all. A name outside the enabled groups is dropped even if the dataLayer sends it.