Cross-domain tracking in GA4: stop losing the source at the domain hop
When a client's journey crosses domains they own, GA4 starts a new session and credits the wrong source — unless you configure cross-domain. What it is, how to set it up, and the subdomain/third-party cases it doesn't cover.
TL;DR
When a user crosses between two different domains the client owns (brand.com → brandstore.com), GA4 by default treats the second domain as a brand-new session with the first domain as the referrer — so the original source (the ad, the organic visit) is lost and the conversion gets credited to a self-referral. Cross-domain tracking fixes it by passing GA4's client ID across the hop via a linker parameter (_gl), so the session — and its real source — survives. Set it up in GA4 Admin → Data streams → Configure tag settings → Configure your domains (list every owned domain in the journey). Two cases it does not cover: subdomains of the same root (they share cookies already — usually fine) and third-party domains you don't own (Stripe, Shopify checkout — use referral exclusions, not cross-domain). Below: the setup and the gotchas.
A client runs their main site on brand.com and their store on brandstore.com, a Google Ads click lands on the main site, the user clicks through to the store and buys — and GA4 credits the purchase to a "referral from brand.com." The ad that paid for it gets nothing. That's the cross-domain problem, and it silently mis-attributes revenue on any client whose funnel spans more than one owned domain.
Why the hop breaks attribution
GA4 identifies a user with a client ID stored in a first-party cookie — which is scoped to one domain. Cross from brand.com to brandstore.com and the second domain can't read the first's cookie, so GA4 mints a new client ID, starts a new session, and records the previous domain as the referrer. Result: the journey splits in two, and the conversion's real source (the ad, the organic search) is replaced by a self-referral. Multiply across every cross-domain journey and a chunk of the client's attribution is quietly wrong.
The fix: configure cross-domain
Tell GA4 the domains belong together and it will carry the client ID across the hop using a linker parameter (_gl) appended to the links between them:
- GA4 Admin → Data streams → [your web stream] → Configure tag settings → Configure your domains.
- List every domain in the journey you own (
brand.com,brandstore.com,app.brand.io, …). - Save. GA4 now decorates links between the listed domains with
_gl, so the receiving domain reads the same client ID and continues the session with its original source intact.
(If you load GA4 through GTM, the same domains can be set on the Google tag's configuration — the GTM-vs-GA4 split still applies: this is a GA4 tag setting, configured in GA4 Admin or the GTM tag's fields, not a standalone GTM tag.)
Two cases cross-domain does NOT cover
1. Subdomains of the same root domain (www.brand.com ↔ app.brand.com). These share cookies automatically, so the client ID already carries — you usually don't need cross-domain for them. But you may still see one show up as a referral after a redirect; if so, that's a referral-exclusion fix, not a cross-domain one.
2. Third-party domains you don't own (checkout.stripe.com, pay.shopify.com, a booking tool). You can't cross-domain a domain you don't control — there's no tag to put on it. Instead, add it to the unwanted referrals list so the return trip doesn't start a new, mis-sourced session. Cross-domain is for owned domains; referral exclusions are for third parties. Mixing them up is a common dead-end.
Verify it (don't assume)
Cross-domain fails quietly when a redirect strips the _gl parameter or the domain list is incomplete. Test it:
- Click a link from
brand.comtobrandstore.comand confirm the destination URL gains a_gl=...parameter. - In GA4 DebugView, confirm the session continues across the hop (same user, source preserved) rather than starting fresh.
- A week later, check that the owned domains have stopped appearing as referrals in your traffic reports.
This belongs in the standing GA4 audit for any multi-domain client — it's exactly the kind of thing that's set up once, works, then breaks when the client adds a new domain and nobody updates the list.
Where this fits
Cross-domain is a small setting with outsized impact — it decides whether a multi-domain client's revenue is attributed to the ad that drove it or to itself. Phloz models each client's domains and their tracking relationships as part of the tracking-infrastructure map with a health state, so "is this client's cross-domain configured for every domain in the journey?" is a view, not a thing you rediscover when the numbers look off. The CRM for ecommerce agencies and pricing pages cover the workflow — but the rule is simple: every owned domain in the funnel goes on the cross-domain list, every third-party hop goes on the referral-exclusion list, and you verify the _gl actually carries.