UTM & GA4 Cross-Domain Tracking: How to Stop Losing Conversion Data in 2026
You spent $5,000 on LinkedIn Ads. The landing page is on Webflow. Checkout is on Stripe. GA4 says "Direct" for 60% of your conversions. Welcome to the cross-domain attribution problem, and here's the exact configuration that fixes it.
_gl parameter GA4 adds to outbound links. Five-minute config, zero ongoing work.
The Cross-Domain Problem in Plain English
Imagine a visitor clicks your LinkedIn ad. The ad URL contains utm_source=linkedin&utm_medium=paid-social&utm_campaign=spring-launch-2026. They land on landing.yourcompany.com, read the page, click "Sign up." That button takes them to app.yourcompany.com/signup. They convert.
From GA4's perspective, that's two separate sessions on two separate domains by default. The landing page recorded a session from LinkedIn. The signup page recorded a "(direct)" session, because GA4 sees them as different sites, and nothing told it those two visits belong to the same user.
Your conversion gets attributed to (direct). Your LinkedIn campaign looks like it generated traffic but zero conversions. You pause it. You lose the channel that was actually working.
What Actually Fixes It
Three things, in this order:
1. Configure GA4 cross-domain measurement
GA4 has a feature called the "linker" that injects a client-ID parameter (_gl) into outbound links to domains you've listed. When the visitor lands on the second domain, GA4 reads _gl and recognises them as the same user: same session, same source.
2. Use redirects that preserve the query string
A lot of redirect setups silently strip ?utm_source=... at the boundary. 301 redirects from a server framework (nginx, CloudFront, Vercel) often drop query parameters unless configured explicitly. Test every redirect chain by clicking through and inspecting the final URL.
3. Never strip _gl
Some teams add URL-cleaning logic to remove tracking parameters from their canonical URLs. _gl is one of them, but unlike fbclid or gclid, you need it. Whitelist it in any cleaning logic.
GA4 Cross-Domain Setup (4 Steps)
- GA4 Admin → Data Streams → click your web stream. If you have multiple web streams (one per domain), you only need to configure this on the primary one.
- Scroll to "Configure tag settings." Click "Configure your domains."
- Add every domain that should share sessions. Use match types: "Contains" for broad matches, "Exactly matches" for strict ones. Common entries:
yourcompany.comlanding.yourcompany.com(if separate)app.yourcompany.comcheckout.thirdparty.com(if using a third-party checkout)
- Save. GA4 will start injecting
_glinto outbound links to these domains within a few minutes.
?_gl=1*abc123*.... If it doesn't, GA4 isn't recognising the destination as a linked domain, so check spelling and refresh.
Subdomains: Different Rules
Subdomains of the same root domain don't need cross-domain config because GA4 treats them as one site by default. shop.yourcompany.com and www.yourcompany.com already share sessions and UTM attribution out of the box.
This only matters if you change the registrable domain (the part you pay GoDaddy or Namecheap for). yourcompany.com → yourcompanyapp.com requires cross-domain config. yourcompany.com → app.yourcompany.com does not.
| From | To | Cross-domain config needed? |
|---|---|---|
example.com | app.example.com | No · same root |
example.com | example-app.com | Yes |
example.com | checkout.stripe.com | Yes |
landing.example.com | app.example.com | No · same root |
example.com | example.co.uk | Yes |
Redirect Patterns That Break UTMs
The other major attribution killer is redirect logic that strips query parameters. Common offenders:
$is_args$args. A plain rule like return 301 https://newdomain.com$request_uri usually preserves the query string, but only if $request_uri is used. $uri alone strips it. Test every rule.
<meta http-equiv="refresh" content="0; url=https://newdomain.com"> doesn't preserve the original URL's query string unless you explicitly include it in the target.
How to Test the Full Attribution Chain
Don't trust the config until you've walked through a real flow:
- Build a test URL with the UTM Builder. Use a fake-but-recognisable campaign name like
test-attribution-may-2026. - Click through in an incognito window. Watch the address bar at every redirect.
- Confirm UTMs survive each domain handoff. If they vanish at a particular hop, that's where your fix is needed.
- Complete a conversion (signup, checkout, whatever your final event is).
- Open GA4 → Realtime. Within 1–2 minutes you should see your fake campaign name in the source/medium dimensions, attached to the conversion event.
Common Third-Party Checkout Setups
The most-affected setups in 2026:
Stripe Checkout (hosted)
When you redirect a user from your site to checkout.stripe.com, you lose UTM attribution by default. Add checkout.stripe.com to GA4 cross-domain config, and pass UTMs through to Stripe's client_reference_id field so they show up in Stripe's webhook data when the conversion completes.
Shopify (.myshopify.com or custom domain)
If your storefront is on a custom domain and checkout falls back to checkout.shopify.com, attribution breaks. Shopify Plus customers can use a fully custom checkout on the same domain; others need cross-domain config plus Shopify's "Marketing UTM tracking" setting enabled.
Calendly / SavvyCal / cal.com booking pages
UTMs on the original link survive to the booking page if the booking tool supports parameter pass-through. Calendly does. SavvyCal does. cal.com does. But if the user navigates between booking pages, attribution can reset. Add your booking domain to GA4 cross-domain config and you're covered.
How I actually debug this
Cross-domain bugs feel intimidating because the failure is invisible: nothing errors, the pages load fine, and the data just quietly lands in the wrong bucket. So I stopped trying to reason about it in the abstract and started doing the dumbest possible thing, which also turns out to be the fastest. I open the address bar and read the URL at every hop. Click the ad, read the URL. Land on the Webflow page, read the URL, are the UTMs and the _gl still there? Click through to Stripe checkout, read the URL again. The exact moment a parameter disappears is the exact line of config that's broken, and you've found it without touching a single setting. Every cross-domain problem I've fixed came down to watching where the string vanished. The tools make this sound complicated. The address bar makes it simple.
Frequently Asked Questions
_gl parameter is added at click time by the GA4 tag already loaded on the page. It adds no extra network requests and no measurable performance impact._gl into links pointing there from your tracked pages. Add only the domains where you actually want unified sessions, not every external link you happen to have._gl appended if GA4's linker is working. You can also right-click a link and "Copy link address" to see the full URL.Read the URL at Every Hop
If your funnel crosses domains, you have a UTM attribution problem until you specifically fix it. The fix takes five minutes: configure GA4 cross-domain measurement, audit your redirects to preserve query strings, and verify with a test click. After that you can stop wondering why "(direct)" keeps showing up next to your paid conversions.
