Free website & SEO check: see your score in under a minute  ·  Check my website →Premium Windows software for marketers: talk to us for access and pricing  ·  Explore the software →
Technical Updated May 21, 2026  ·  9 min read

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.

Quick verdict: UTM parameters do not automatically survive a redirect to another domain. Enable GA4's cross-domain measurement (Admin → Data Streams → Configure Tag Settings → Configure your domains), use 302 redirects that pass the query string through, and never strip the _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)

  1. 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.
  2. Scroll to "Configure tag settings." Click "Configure your domains."
  3. Add every domain that should share sessions. Use match types: "Contains" for broad matches, "Exactly matches" for strict ones. Common entries:
    • yourcompany.com
    • landing.yourcompany.com (if separate)
    • app.yourcompany.com
    • checkout.thirdparty.com (if using a third-party checkout)
  4. Save. GA4 will start injecting _gl into outbound links to these domains within a few minutes.
How to test it: Open your landing page in an incognito window. Open browser DevTools → Network tab. Click an outbound link to the second domain. The URL should include ?_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.

FromToCross-domain config needed?
example.comapp.example.comNo · same root
example.comexample-app.comYes
example.comcheckout.stripe.comYes
landing.example.comapp.example.comNo · same root
example.comexample.co.ukYes
If the registrable domain changes, you need cross-domain config. Subdomains under the same root work automatically.

Redirect Patterns That Break UTMs

The other major attribution killer is redirect logic that strips query parameters. Common offenders:

301 redirects from nginx/Apache without $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.
Cloudflare Page Rules without "Preserve query string" enabled. The default behaviour preserves query strings, but custom redirect rules can strip them. Audit if you're using "Forwarding URL" rules.
Meta-refresh redirects in HTML. <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.
Bitly / Dub.co / link shorteners with parameter stripping. Most shorteners preserve query strings now, but a few legacy services strip them. Always test the full chain: short URL → final landing page → next domain.

How to Test the Full Attribution Chain

Don't trust the config until you've walked through a real flow:

  1. Build a test URL with the UTM Builder. Use a fake-but-recognisable campaign name like test-attribution-may-2026.
  2. Click through in an incognito window. Watch the address bar at every redirect.
  3. Confirm UTMs survive each domain handoff. If they vanish at a particular hop, that's where your fix is needed.
  4. Complete a conversion (signup, checkout, whatever your final event is).
  5. 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.

The Cookieless Future (and Why UTMs Still Win)

As third-party cookies disappear, server-side tracking and consent-mode setups are becoming the norm. The good news: UTMs are part of the URL, not a cookie. They survive every privacy-related change browsers throw at us. They're the single most resilient piece of attribution data you control.

If you're moving to server-side GTM or any consent-mode v2 implementation, UTMs continue to flow through unchanged. The _gl linker also works in server-side setups; check Google's documentation for the specific config in your hosting setup.

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

No. The _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.

There's no hard limit, but every domain you add means GA4 will inject _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.

Partially. Iframes from a cross-domain source need explicit GA4 setup on the iframe content. If you embed Calendly or Typeform via iframe, attribution can leak. Move to redirect-based flows where possible, or use the iframe provider's own UTM pass-through feature.

Nothing, past data isn't retroactively reattributed. The fix applies from the moment you enable it forward. Plan a clean break: enable, then mark in your reporting that data before the date is incomplete for cross-domain attribution.

Yes. Open Chrome DevTools (F12) → Network tab on your source page. Hover over an outbound link to a configured domain and the status bar shows the URL with _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.