Scenario: you launch an email campaign with a UTM tag ?utm_source=newsletter&utm_campaign=spring-sale. Open rate 32%, 8,400 clicks recorded by your email tool. An hour later you check GA4 — and see 5,200 visits attributed to “direct”. Where did the other 3,200 go? They are not gone — GA just cannot see them: your UTM was stripped somewhere between the email client and your site.
This is not a GA bug, not your bug, not the mail provider's bug. This is simply 2026: a dozen places where URL parameters can disappear, and more than half are outside your control. Below — where exactly the loss happens, how to measure it honestly, and why server-side tracking through TDS shows a picture closer to reality.
UTM gets stripped at four points: Safari ITP during chained redirects, link shorteners inside social apps, in-app webview on Instagram/TikTok/Telegram, and Google AMP pages. On average, 25–40% of mobile attribution is lost. TDS logs the click at the moment of the click — on our redirect, before the UTM has a chance to disappear — and then syncs to GA4/Mixpanel through a server-side API. Attribution no longer depends on what happens to the URL downstream.
Four places where UTM physically disappears
1. Safari ITP on a chain of redirects
Since iOS 17, Safari aggressively trims cross-site tracking. When a user goes through email → shortener → intermediate redirect → your site, Safari on one of those hops can drop the query string “for privacy”. Especially if any domain in the chain is on Safari's tracking list — which is almost any shortener.
On our measurements, a clean Safari iOS session in a two-redirect chain loses the UTM in 18–23% of cases. Chrome iOS is the same — it uses WebKit under the hood.
2. Link shorteners inside social platforms
When you post a link on Twitter/X, it gets wrapped in t.co/xyz. On Facebook — l.facebook.com. On LinkedIn — lnkd.in. These wrappers preserve the query string 95% of the time, but not always — sometimes parameters get reordered, sometimes Cyrillic encoding gets mangled, sometimes anything after # is dropped.
Real example: a marketer set ?utm_campaign=spring-2026 with non-ASCII characters in their Twitter post. After two redirects through t.co the user landed on a malformed parameter — and GA4 could not parse it, attributing the click to “(not set)”. Fix: always transliterate UTM values to ASCII.
3. In-app webview of social platforms
The most painful category. When a user clicks a link directly inside Instagram/TikTok/Telegram, it opens not in Safari/Chrome but in the app's embedded webview. This is an ephemeral session: no cookies, no localStorage, no history. UTM works on open, but GA4 sees every user as new — attribution to the ad campaign holds for exactly one session and evaporates on the next visit.
In reports this looks like “lots of clicks, low return, zero retention” — and the site owner concludes the traffic is junk. In reality it is webview sessions that cannot persist attribution.
4. AMP and Google cache
If your landing is an AMP page and the user arrives from Google results, they get sent first to google.com/amp/.... Some UTM survives, some gets renamed (utm_source may become amp_source), and in some cases Google simply does not pass UTM to the canonical URL after an AMP Quick View click. This is a closed Google system and almost impossible to diagnose from outside.
How to see whether you are losing attribution (5 minutes)
Simple diagnostic for any site:
- Open GA4 → Acquisition → Traffic acquisition.
- Select the last 7 days.
- Look at
(direct) / (none)— what percentage of total traffic? - Pull up a mobile vs desktop split. If mobile “direct” is 2–3× higher than desktop, you have a classic ITP/webview loss.
Healthy site: desktop “direct” is 10–20%, mobile 20–30%. Unhealthy: mobile “direct” is 40–60%. If you are in the second bucket — half of your mobile attribution is drowning in “direct”, and you have no idea where the traffic is coming from.
Of 50 client GA accounts we audited last quarter, 41 had “(direct) / (none)” above 40% on mobile. For most teams, nearly half of mobile traffic flows without a known source — and these are not direct visits, this is lost attribution.
How TDS solves it
The idea is simple: capture the UTM at click time, not at landing time. When a user clicks a link like tds.so/abc (or your custom domain) we do three things synchronously in under 30 ms:
- Log the click with all UTM parameters in our database.
- Generate a
click_id— a short unique signature, ~10 characters. - Pass that
click_idto the landing page via the URL (not UTM tags).
Now even if every one of the four mechanisms above strips something downstream — we still have the click with full attribution in our database, tied to this visitor. When a conversion happens on your site, your JS posts the click_id back to us through the postback API, and we stitch click and conversion together.
Roughly what it looks like on the client:
// On the landing page, on load
const clickId = new URLSearchParams(location.search).get('cid');
if (clickId) {
localStorage.setItem('tds_cid', clickId);
}
// On a successful conversion (order, lead, signup)
const cid = localStorage.getItem('tds_cid');
fetch('https://api.tds.so/postback', {
method: 'POST',
body: JSON.stringify({
click_id: cid,
event: 'order_completed',
value: 49.90,
}),
});
TDS stitches the click and the conversion together, and your dashboard now shows honest sources: those 3,200 “lost” clicks from the opening example are correctly attributed to newsletter / spring-sale.
Export back to GA4 and Mixpanel
Server-side tracking does not mean abandoning GA4 or Mixpanel. The Measurement Protocol lets us send a “backfilled” event straight to GA4 from the server, bypassing webview and ITP entirely:
POST https://www.google-analytics.com/mp/collect
?measurement_id=G-XXXXXXX&api_secret=...
{
"client_id": "<the same client_id the user has in the browser>",
"events": [{
"name": "purchase",
"params": {
"campaign_source": "newsletter",
"campaign_name": "spring-sale",
"value": 49.90
}
}]
}
Same idea for Mixpanel through their Server SDK. In TDS this export is configured on a single screen: drop in the measurement_id and api_secret, pick event types — and it forwards automatically. UTM attribution reaches GA4 even from the 40% that would have been lost to “direct”.
When plain UTM is enough
Do not over-engineer this. Plain UTM is fine when:
- traffic is mostly desktop (B2B, corporate services);
- traffic comes from desktop email and search results, not social apps and messengers;
- the conversion happens in the same session as the click (low-ticket purchases that close in 1–2 minutes);
- GA4 “(direct) / (none)” on mobile is below 30%.
If even one of these is not true — UTM is leaking and you are under-counting sources. Server-side is worth wiring up.
Conclusion
UTM was great for the 2010s, but in 2026 it needs reinforcement. Four places where it disappears: ITP, shorteners, webview, AMP. A simple diagnostic on the “(direct) / (none)” mobile segment shows the scale in 5 minutes. The fix is server-side tracking via click_id and the Measurement Protocol — and attribution stops depending on what happens to the URL along the way.