Cross-Domain Tracking
Why a user becomes two users at the domain boundary
Analytics tools identify visitors primarily by a first-party cookie scoped to the domain that set it. A visitor browsing shop.example.com gets a GA4 client ID stored on that domain. The moment they click through to checkout.examplepay.com — a separate domain handling payment — the browser does not send shop.example.com's cookies to it. The checkout domain has no idea who this visitor is, so it mints a brand-new client ID.
The practical damage: your session is split into two. The visit that browsed products and added to cart becomes session A on domain 1; the purchase becomes session B, from an entirely new 'user,' on domain 2. GA4 reports a Direct/None session converting out of nowhere, while the session that actually drove the purchase shows zero conversions. Attribution, source/medium, and even basic conversion counts become unreliable the instant a funnel spans more than one domain — this happens constantly with hosted checkouts (Shopify, Stripe Checkout), subdomains treated as separate domains by mistake, or multi-brand sites sharing one funnel.
How GA4 solves it: linking domains
GA4 (and Universal Analytics before it) solves this with a technique sometimes still called 'linker' logic. When a visitor clicks a link from domain A to domain B, the GA4 tag intercepts the outbound link and appends the client ID (and session ID) as a URL query parameter, e.g. ?_gl=1*abc123*.... When the page loads on domain B, the GA4 tag on that page reads the _gl parameter, recognizes the client ID that was passed, and reuses it instead of generating a new one. The two domains now agree on who the visitor is, and the session continues unbroken across the handoff.
This is configured in GA4 under Admin → Data Streams → Configure tag settings → Configure your domains. You list every domain that participates in the same user journey. Behind the scenes this sets the allow_linker and linker.domains parameters on the gtag config call.
gtag('config', 'G-XXXXXXXXXX', {
'linker': {
'domains': ['shop.example.com', 'checkout.examplepay.com'],
'decorate_forms': true
}
});
// Resulting decorated outbound link:
// https://checkout.examplepay.com/pay?_gl=1*abc123*_ga*MTIzNDU2Nzg5...Decorating links vs decorating forms
Link decoration handles <a href> clicks automatically once domains are listed — GA4's tag rewrites the href on click. But many checkout handoffs happen via form submission (a POST to the payment processor), not a clicked link. If you only configure link decoration, forms silently break the chain.decorate_forms: true tells the GA4 tag to also inject a hidden _gl input field into forms whose action points to one of the listed cross-domain targets, so the parameter survives a POST submission the same way it survives a GET navigation. Teams frequently debug 'cross-domain tracking isn't working' for days before realizing their checkout uses a form POST and they never enabled this flag.
Subdomains do not need cross-domain linking
www.example.com and app.example.com. Cookies set without an explicit, narrower domain attribute are scoped to the registrable domain by default in many implementations, but GA4's own cookie (_ga) is set at the eTLD+1 level (example.com) by default specifically so subdomains share it automatically. True cross-domain linking is only required when the second domain is a genuinely different registrable domain (different eTLD+1), like a third-party checkout or payment provider.Client ID linking and the hit-level consequence
Under the hood, every GA4 event carries a client ID in the cid parameter of the Measurement Protocol payload sent to Google's collection endpoint. Cross-domain linking's entire job is making sure that cid value is identical on both sides of the domain jump. Once it is, GA4's session-stitching logic treats every event — on both domains — as part of the same session and the same user, which is what lets a purchase event fired on the checkout domain inherit the session's original source/medium (e.g. google / cpc) instead of reporting as a disconnected (direct) / (none) session.
This matters even more once you add server-side tagging or a CAPI integration (see Meta CAPI or server-side GTM content): if the client ID itself is unstable across the funnel, every downstream system inherits the same broken identity problem — deduplication, attribution modeling, and even basic session counts all degrade together.
Same-domain vs cross-domain session continuity
| Scenario | Needs cross-domain config? | Failure mode if misconfigured |
|---|---|---|
| www.example.com → app.example.com | No — shared eTLD+1 cookie by default | Rarely an issue; cookie already shared |
| shop.example.com → checkout.stripe.com | Yes | New client ID on checkout.stripe.com; purchase attributed to (direct)/(none) |
| example.com → examplecorp-payments.com | Yes | Funnel split into two sessions; source/medium lost on conversion |
| Multi-brand site, two completely separate domains sharing one GA4 property | Yes | Cross-domain users double-counted as separate users entirely |
Verifying it actually works
Don't trust the configuration screen alone — verify empirically. Open DevTools Network tab, click through from domain A to domain B, and inspect the destination URL for the _gl query parameter. Then check GA4 DebugView (with debug_mode enabled) and confirm the client ID reported on domain B's first event matches the client ID that was active on domain A immediately before the click.
A second common failure: ad blockers and some privacy extensions strip _gl parameters from URLs, treating them (not unreasonably) as cross-site tracking parameters. There is no full client-side fix for this — it's one more reason server-side measurement (CAPI-style approaches) is increasingly necessary alongside, not instead of, browser-based cross-domain linking.
Cross-domain tracking is identity continuity, not a GA4-only concept
_fbc/_fbp, TikTok Pixel, LinkedIn Insight Tag. Any funnel that spans domains should audit every tracking tag it runs for the same continuity gap, not just analytics.What's next
Once identity survives the domain jump, the next problem is making sure the events themselves are structured correctly for conversion reporting — see E-commerce Tracking in GA4 for the view_item/add_to_cart/purchase event schema that cross-domain tracking is protecting the continuity of.
Next: E-commerce Tracking in GA4 →
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.