Safari ITP has been killing cookies after 7 days since 2019. Since Safari 16.4 (April 2023), this cap also applies to server-set cookies - if the IP prefix of the tracking server does not match the main domain server. Most standard setups (Stape subdomain, GTM on Google Cloud) hit exactly this problem without realizing.
With Safari market share of ~17-20% desktop and ~30% mobile, this means: 15-25% of attribution lost as soon as click and conversion are more than a week apart. Fatal for B2B sales cycles, painful for long e-commerce funnels.
The solution: Same-Origin Path-Based sGTM (example.com/sgtm/ instead of sgtm.example.com) via reverse proxy. Being same-origin, the IP-matching problem disappears and cookies are allowed to live up to 400 days. This article shows the WHY and the HOW - including a Cloudflare Worker example and a test in Safari ITP Debug Mode.
Prerequisite: sGTM container already running (e.g. via Stape). Background on server-side in the Pillar article.
1. What ITP actually does
Intelligent Tracking Prevention is Apple's anti-tracking mechanism in Safari. Lives in the WebKit browser engine, so Safari macOS, Safari iOS, every iPhone browser (Chrome on iPhone uses WebKit, not Blink). ITP classifies domains by user behavior as „tracking" or „non-tracking" and treats cookies on tracking domains more restrictively.
Three central mechanisms:
- 7-day cap for JavaScript cookies (all cookies set via
document.cookie) - 24-hour cap for cross-site trackers (cookies deleted after 24h if domain classified as tracker)
- IP-matching rule (Safari 16.4+): server-set cookies only get full lifetime if IP matches main site
2. History 2017-2026
| Year | Safari version | What was added |
|---|---|---|
| 2017 | Safari 11 | ITP 1.0: third-party cookies 24h cap, then deleted after 30 days |
| 2018 | Safari 12 | ITP 2.0: stronger tracker detection, Storage API restrictions |
| 2019 | Safari 13 | ITP 2.1-2.3: 7-day cap for JavaScript cookies (all, not just trackers) |
| 2020 | Safari 14 | CNAME cloaking detection: CNAME subdomains treated as trackers |
| 2021 | Safari 15 | Improved bounce-tracking detection |
| 2023 | Safari 16.4 | IP-Matching rule: server-set cookies only get full TTL if IP prefix matches |
| 2025+ | Safari 18+ | Strengthened fingerprinting detection, Hidden IP via Private Relay |
3. The cookie capping problem in detail
Normal Google Ads conversion tracking works like this: user clicks ad, GCLID is
written to a cookie (_gcl_aw), cookie lives 90 days, user returns in
3 weeks and converts, GCLID is sent, conversion is attributed.
With Safari ITP: user clicks ad, GCLID is written to cookie via JavaScript, cookie is capped to 7 days by ITP, user returns in 3 weeks - cookie is gone, GCLID gone, conversion not attributed. From Google's view it looks as if the user came „organically."
Apple's argument: typical browsing sessions don't span over a week, legitimate login cookies can be refreshed by user re-login within 7 days. Tracking cookies, however, need long lifetimes - ergo: shorter cap = more private. From a tracking perspective: B2B sales cycles and longer e-commerce funnels break.
4. Safari 16.4 IP-Matching Rule (what many overlook)
Until Safari 16.4 (April 2023), there was a clear workaround: set cookies via HTTP Set-Cookie header from the server instead of via JavaScript. Server-set cookies were exempt from the 7-day cap and lived up to 400 days (browser default).
Since Safari 16.4, this has been restricted: server-set cookies only live their full lifetime if the server's IP address (or at least the /16 subnet prefix) matches the main domain's IP prefix. If not, the cookie still gets capped to 7 days.
Practical example: your website runs on Cloudflare (104.21.x.x), your
sGTM on Stape EU (34.107.x.x). Safari sees: two different IP prefixes
→ treats sGTM cookies as „suspicious first-party" → caps to 7 days, even if you
correctly set them via Set-Cookie HTTP header.
If your sGTM runs on Stape, Google Cloud Run, AWS, or any other third-party provider - which 95% of all sGTM setups out there do - the IP-matching rule kicks in and Safari still caps to 7 days. Standard subdomain sGTM does NOT help Safari users against ITP. That's the uncomfortable truth behind „we use Stape, we have server-side tracking" - it solves browser restrictions, but Safari cookies don't.
5. Why CNAME cloaking is dead today
An old workaround technique was CNAME cloaking: create a subdomain
(track.example.com), point it via DNS CNAME to the tracking provider's
server (e.g. track.example.com → customer.adobe.com).
From the browser's perspective the subdomain is first-party, but Adobe is actually
tracking.
Safari/WebKit detects CNAME cloaking since 2020. Mechanism: Safari performs a DNS lookup, checks if the CNAME target is outside the eTLD+1 (i.e. „outside the registrable domain"), and if yes → treats as tracker, caps JavaScript cookies to 7 days. CNAME cloaking is functionally dead today.
„A new feature in Intelligent Tracking Prevention (ITP) has shipped: a cap of seven days of storage for all script-writeable storage, including cookies set via document.cookie, on third-party CNAME-cloaked first-party subresources."
6. How much it actually costs
Real impact by business model:
| Business model | Typical conversion path | Safari loss without fix |
|---|---|---|
| Small e-commerce (impulse buy) | Click → purchase within days | 3-5% |
| Medium e-commerce (comparison shopping) | Click → purchase within 1-3 weeks | 10-15% |
| SaaS trial → paid | Sign-up → conversion in 2-4 weeks | 15-20% |
| B2B lead-gen | Inquiry → closed deal in 1-6 months | 20-30% |
| Local services (short sales) | Inquiry → call within days | 2-3% |
Loss = Safari market share × share of users who convert after 7+ days. Safari share Germany: ~17% desktop, ~30% mobile. In mobile-first commerce disproportionately painful.
What this means for your conversion tools: with Meta CAPI the fbc and fbp cookies get capped - your EMQ score drops for Safari users. With Google Ads Enhanced Conversions the GCLID cookie only lives 7 days - conversions without an email match get unattributed after a week. Same-Origin sGTM rescues both tools at once.
7. The three solution paths
Three technical options, depending on setup complexity:
| Solution | Effort | Cookie lifetime | Suitable for |
|---|---|---|---|
| HTTP Set-Cookie with IP match | High (infrastructure migration) | Up to 400 days - if IP matches | Only enterprise with own server |
| Same-Origin Path-Based sGTM | Medium (reverse proxy) | 400 days | Most setups |
| Stape Custom Loader Power-Up | Low (plug-and-play) | 400 days | Stape customers without DevOps resources |
8. Same-Origin sGTM via Cloudflare Worker
Concrete setup for most cases - Cloudflare site fronts Stape sGTM:
- Create Cloudflare Worker: Dashboard → Workers & Pages → Create Worker
- Write Worker code (see below)
- Bind route:
example.com/sgtm/*→ Worker - Change sGTM tagging URL in Web container from
https://sgtm.example.comtohttps://example.com/sgtm - Publish container + live test
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Strip /sgtm prefix, forward to Stape endpoint
const targetPath = url.pathname.replace(/^\/sgtm/, '');
const targetUrl = 'https://sgtm.example.com' + targetPath + url.search;
// Rebuild request with original method, headers, body
const proxyRequest = new Request(targetUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'manual'
});
const response = await fetch(proxyRequest);
// Pass through Set-Cookie headers (critical!)
// Cloudflare merges them automatically
return new Response(response.body, {
status: response.status,
headers: response.headers
});
}
};
What happens here: Cloudflare receives requests at
example.com/sgtm/*, proxies them to Stape, returns the response
including Set-Cookie headers. From the browser's perspective: all requests land
on example.com - same domain, same IP range, no IP-matching problem,
cookies live 400 days.
9. Alternative: Stape Custom Loader Power-Up
If you don't want to build a Cloudflare Worker, Stape offers the Custom Loader Power-Up (~$20/month extra). It injects a small loader script into your main domain that routes all sGTM requests through your main domain. Functionally the same result as the Worker approach, but Stape handles the infrastructure for you.
- Stape dashboard → your container → Power-Ups
- Activate Custom Loader
- Stape generates code snippet - place this BEFORE the GTM script on your website
- Switch sub-domain to same-origin path in container settings
- Test in Safari ITP Debug Mode
10. Test in Safari ITP Debug Mode
How to verify your cookies are no longer capped:
- Open Safari → Preferences → Advanced → enable „Show Develop menu"
- Menubar → Develop → Experimental Features → ITP Debug Mode enable
- Visit website → Develop → Show Web Inspector → Storage → Cookies
- For each cookie check the Expires column - should be 400 days in the future, not 7 days
- Console tab search for
ITP Debug:logs - shows why a cookie was capped
For each sGTM cookie should say: „Cookie set via Set-Cookie header from first-party context, full lifetime granted." If instead „capped to 7 days due to network-level criteria" - then the problem is still IP-matching.
11. GDPR remains unchanged
The same-origin solution doesn't change your GDPR obligations:
- ✓ Consent Mode v2 active: cookies only fire with consent
- ✓ Privacy Policy mentions all tracking cookies, even if set as first-party
- ✓ DPA with Stape/Cloudflare: Data Processing Agreement under Art. 28 GDPR
- ✓ Data minimization: 400-day cookie only for data you actually need (e.g. GCLID, session-ID)
Important: longer cookie lifetime does NOT make tracking „more GDPR-compliant" - you still have to meet all GDPR requirements. It just makes it technically functional for Safari users.
12. FAQ
What exactly is Safari ITP?
Intelligent Tracking Prevention is Apple's anti-tracking mechanism in Safari (since 2017). Since 2019, ITP caps all JavaScript-set cookies at a maximum of 7 days. Since Safari 16.4 (April 2023), it also caps server-set cookies if the server IP does not match the main-site IP prefix. Result: attribution data disappears after a week - which destroys performance bidding.
Why doesn't normal server-side GTM automatically help against ITP?
If your sGTM container runs on a subdomain (e.g. sgtm.example.com via
Stape) and the IP prefix of the Stape servers does not match the IP prefix of your
main server, Safari 16.4+ still treats it as „suspicious" and caps cookies at 7
days. Most Stape setups hit this problem - the solution is Same-Origin Path-Based
setup.
What is CNAME cloaking and why doesn't it work anymore?
CNAME cloaking was an old technique: have a subdomain (track.example.com)
point via CNAME to a third-party server so it appears first-party. Safari/WebKit
has detected this since 2020 and caps all JavaScript cookies on such subdomains
at 7 days. CNAME cloaking is functionally dead today - don't use it.
What's the solution against Safari ITP?
Same-Origin Path-Based sGTM: instead of subdomain sgtm.example.com,
sGTM runs under example.com/sgtm/ via a reverse proxy (Cloudflare
Worker, Nginx, or Stape Custom Loader Power-Up). Being same-origin, there are no
IP-matching issues and cookies can be set for up to 400 days. Google explicitly
recommends this setup.
How much difference does it really make?
Safari market share in Germany is ~17-20% desktop, ~30% mobile. With the 7-day cookie cap, all Safari users disappear from attribution as soon as they wait a week between click and conversion. With B2B sales cycles (weeks to months), that's 15-25% of attribution lost. With 400-day cookies via Same-Origin sGTM, attribution is preserved.
Is Same-Origin sGTM GDPR-compliant?
Yes - GDPR compliance does not depend on technical cookie lifetime, but on Consent Mode v2, correct privacy policy, DPA with providers and data minimization. Same-Origin Path-Based sGTM doesn't change these obligations - on the contrary, the first-party nature makes data ownership clearer for the advertiser.
Want same-origin sGTM set up for your site?
I migrate your Stape setup to Same-Origin Path-Based via Cloudflare Worker or Stape Custom Loader. Cookie lifetime goes from 7 to 400 days, Safari attribution is saved. As server-side module from €400.
Request migration