← All posts Attribution

Why UTM parameters break at checkout redirects and how to fix attribution

15 Aug 2026 · 5 min read · Twinslytics

You launch a campaign, spend real money, and three days later half your conversions show up as "direct" in GA4. Nobody typed your URL from memory. They clicked an ad, got redirected through a payment gateway, and your UTM parameters vanished somewhere between the landing page and the order confirmation. This isn't a tracking mistake. It's how checkout redirects work, and most DTC teams don't find out until finance asks why blended ROAS looks different from platform-reported ROAS.

The redirect chain eats your parameters

A typical purchase path looks simple: ad click → landing page → product page → cart → checkout → confirmation. In reality, checkout often bounces through two or three domains. Shopify moves shoppers from yourstore.com to checkout.shopify.com. Stripe, PayPal, and Klarna add their own hosted pages. Each hop is a fresh HTTP request, and UTM parameters live in the URL query string — which doesn't automatically carry over when a server issues a 302 redirect to a different domain.

Add to that browser referrer policies. Modern browsers default to strict-origin-when-cross-origin, which strips path and query data once you cross a domain boundary. So even if the redirect preserves some referrer info, the UTM values themselves often don't make the trip. Your analytics tool sees a new session start at checkout with no campaign data attached, and it falls back to "direct" or "(none)."

Where the data actually disappears

It helps to know the exact failure points instead of treating this as one fuzzy problem:

Each of these breaks a different link in the chain, which is why "just add UTMs to the URL" fixes some sessions and not others — you're patching one leak while three more stay open.

Cookies alone don't solve this

The common first fix is a first-party cookie: capture UTM values on landing, write them to a cookie with a reasonable expiration, and read that cookie at checkout instead of relying on the URL. This works for same-domain checkouts and helps with return visits. It does not work when checkout hands off to a genuinely separate domain like a hosted payment page, because cookies don't cross domains any more freely than referrer data does.

It also doesn't help if your analytics setup depends on client-side JavaScript firing at the exact right moment. Ad blockers, Safari's Intelligent Tracking Prevention, and Firefox's Enhanced Tracking Protection all limit how long first-party cookies persist or block third-party scripts from writing them at all. If your attribution model depends on a pixel firing cleanly in the browser, you're already fighting a losing battle against browser vendors actively working to break that model.

Fix it by persisting data server-side

The reliable fix moves attribution data off the browser and into your own data layer as early as possible, then carries it through the order lifecycle using IDs instead of hoping URL parameters survive redirects.

Practical steps that actually hold up:

UTM parameters were built for simple, same-domain journeys. Checkout flows are rarely that simple anymore — multiple domains, hosted payment pages, mobile wallets, and browsers actively stripping referrer data at every hop. Treating the URL string as your only attribution record guarantees leakage. Persist attribution data into order attributes the moment you have it, use stable IDs instead of query strings to survive redirects, and do your real attribution matching in the warehouse where you control the join logic instead of hoping a script fires at the right millisecond.

Further reading

283/408 sessions reattributed — Fixed attribution, returned conversions to Google Ads

Want your attribution reconciled like this?

We patch the join between clicks and closed revenue so bidding optimizes on what actually happened, not what the checkout referrer claims.