Safari ITP Is Undercounting Your Visitors: What Happens and How to Fix It
Safari ITP caps cookies at 7 days — your returning visitors look like strangers. Here's the cookieless fix.
Last month our head of growth flagged something weird. New visitor percentage had climbed from 58% to 71% over six weeks — on a site with a loyal subscriber base and no major acquisition push. Fourteen-day retention looked fine. Organic traffic hadn't spiked. The math didn't add up.
Took me half a day to trace it. Safari traffic was the tell. Every returning Safari visitor who hadn't been back in eight days was getting counted as new. Apple's Intelligent Tracking Prevention had silently deleted their analytics cookie, and our dashboard was treating them like strangers.
We'd been seeing this problem for two years and blaming seasonality. Not my finest hour.
What ITP actually does to your analytics
Safari's ITP — short for Intelligent Tracking Prevention — is Apple's privacy feature that limits how long cookies can persist. The version shipping in Safari 17+ (and all iOS browsers, since Apple forces everyone to use WebKit under the hood) caps JavaScript-set first-party cookies at 7 days.
That means: if a visitor hits your site, your analytics script drops a cookie to identify them. They come back on day 8. The cookie is gone. Your analytics tool sees no identifier. It counts them as a brand-new visitor.
Do this across thousands of Safari users and the effect compounds. Your "new visitor" numbers inflate. Your "returning visitor" numbers deflate. Retention metrics look worse than reality. Attribution windows shorten because the visitor who clicked your ad two weeks ago looks like someone who just discovered you. If you're also seeing GDPR compliance headaches from cookie banners, this problem compounds.
The mechanism is straightforward:
- User visits your site on Safari.
- Analytics script (GA4, Plausible, whatever) writes a
_gaor similar cookie via JavaScript. - Cookie is set to expire in 2 years — the standard default.
- ITP intercepts this and caps it at 7 days instead.
- User doesn't return for 8 days.
- Cookie is gone. User is now "new."
If your site has weekly or bi-weekly engagement patterns — newsletters, SaaS with monthly billing cycles, content sites with irregular readers — this hits hard. A subscriber who checks in every two weeks is permanently stuck in the "new visitor" bucket.
That's insane when you think about it. Your most loyal readers look like strangers.
How bad is the damage? Run the numbers.
The severity depends on your Safari share. Here's the rough math.
Safari holds about 27% of US browser market share as of mid-2026 (StatCounter). On mobile, it's over 50% in North America — every iPhone defaults to Safari, and most users never switch. B2C sites with strong mobile traffic routinely see 40-55% Safari.
Now layer in visit frequency. If 30% of your traffic is Safari and half of those visitors have gaps longer than 7 days between visits, you're miscounting roughly 15% of your returning traffic as new.
That's not a rounding error. That's a strategic blind spot.
The downstream effects:
- Inflated new-visitor percentages make acquisition look better than it is.
- Deflated returning-visitor percentages make retention look worse.
- Shorter effective attribution windows because the cookie dies before the conversion.
- Broken cohort analysis — day-30 retention cohorts are missing everyone who took a 10-day break.
I've watched teams celebrate "organic growth" that was actually just Safari fragmenting their existing audience into duplicate visitor IDs. Embarrassing when you figure it out. Way more embarrassing when it's been happening for eighteen months and you wrote a whole blog post about your "acquisition flywheel."
The obvious fixes that don't work
Before we get to the real solution, let's kill the workarounds that sound good and fail in practice.
"Just extend the cookie expiration." ITP ignores your expiration. You can set 10 years. Safari caps it at 7 days anyway. The browser, not your server, decides.
"Use localStorage instead." ITP also caps localStorage and IndexedDB for tracking purposes. As of ITP 2.3, any client-side storage set by a script classified as a tracker gets the same 7-day treatment. You can't route around this with a different storage API.
"CNAME cloaking." Point a subdomain at your analytics vendor so cookies appear first-party. WebKit has been closing this since 2019. ITP now inspects the DNS resolution chain. If the CNAME points to a known tracking domain, the cookie gets capped anyway. Some vendors still recommend this. It's a temporary hack, not a solution.
"Server-side cookies with HttpOnly." This actually does bypass ITP — but standard analytics scripts can't set HttpOnly cookies because they run in the browser, not on your server. You'd need to rewrite your entire tracking architecture to send events server-side and manage sessions yourself. For most teams, that's a six-figure project.
The pattern here: any solution that still depends on cookies is fighting a losing battle. Apple ships ITP updates with every Safari release. They're not done tightening. Honestly, I respect the commitment — even if it makes my job harder.
The fix: cookieless visitor identification
The durable solution is to stop using cookies for visitor identification entirely.
Cookieless analytics tools identify visitors using a hash of stable signals — browser, OS, screen resolution, timezone, language, and similar fingerprint-adjacent data — without storing anything on the client. The visitor comes back on day 8, day 30, day 90. Same hash. Same visitor ID. No cookie to expire.
This isn't fingerprinting in the invasive sense. The hash is one-way (can't be reversed to identify a specific person), aggregated (no PII stored), and used only for counting. It's the same approach Plausible, Fathom, and JustAnalytics use. European DPAs have ruled it falls outside GDPR's personal-data scope because no identifiers are retained. We covered the full comparison of privacy-first analytics tools if you want the feature breakdown.
Here's what the switch looks like in practice.
Step 1: Check your current Safari undercount
Before migrating, measure the problem. In GA4:
- Open Reports > Tech > Tech details > Browser.
- Filter to Safari.
- Compare new vs. returning visitor percentages for Safari against Chrome.
If Safari shows 15-25% higher "new visitor" rate than Chrome, ITP is eating your returning visitors. That delta is your undercount.
On one B2B SaaS site we audited, Chrome showed 41% new visitors, Safari showed 67%. A 26-point gap, entirely explained by ITP cookie expiration.
Step 2: Add cookieless tracking in parallel
Don't rip out your existing analytics. Run both side-by-side for 30 days and compare.
For JustAnalytics, the install is one script tag:
<script
defer
data-site="your-site-id"
src="https://cdn.justanalytics.app/script.js">
</script>
That's it. No cookies. No consent banner. No localStorage gymnastics. The under-5KB script handles pageviews automatically and exposes a window.ja() function for custom events. I genuinely wish I'd found this two years ago instead of debugging phantom traffic spikes every quarter.
If you're on Next.js, the App Router integration guide covers the usePathname() hook pattern for proper soft-navigation tracking.
Step 3: Compare the numbers after 30 days
After a month of parallel tracking, pull these metrics from both tools:
| Metric | Cookie-based (GA4) | Cookieless (JustAnalytics) |
|---|---|---|
| Total unique visitors | X | Y |
| New visitor % | A% | B% |
| Returning visitor % | (100-A)% | (100-B)% |
| Safari new visitor % | C% | D% |
The cookieless numbers should show:
- Lower new-visitor percentage overall (because returning visitors aren't being miscounted).
- Much smaller Safari vs. Chrome gap in new-visitor rate.
- Higher returning-visitor percentage that better matches your actual user base.
On the site I mentioned earlier, after 30 days of parallel tracking:
- GA4: 67% new visitors on Safari.
- JustAnalytics: 43% new visitors on Safari.
The "real" new-visitor rate was 24 points lower than GA4 reported. That's not a bug in GA4 — it's ITP working as designed. GA4 just can't see through it.
Step 4: Cut over and retire the old tracking
Once you've validated the numbers, remove the cookie-based script. Update your privacy policy to reflect the switch (you can drop the cookie-consent language entirely). Done.
The GA4 migration guide covers the full cutover process if you want the detailed playbook — event mapping, dashboard rebuild, the BigQuery archive step.
Beyond Safari: why this matters for Chrome too
Google has been waffling on third-party cookie deprecation for years. But first-party cookie restrictions are coming to Chrome eventually — Privacy Sandbox proposals include storage partitioning and tighter JavaScript cookie limits.
The strategic move: build on cookieless now, before Chrome forces the issue. Teams that wait will scramble to fix their analytics when Chrome ships ITP-equivalent restrictions to 65% of the browser market. Teams that switch now have accurate data today and no migration debt tomorrow.
Plus, cookieless tracking means no consent banner. That's not a minor thing. We measured an 11% conversion lift on one site after removing the cookie banner — visitors who would've bounced at the consent prompt now reach the landing page. That alone paid for the analytics migration in the first week. (See our consent banner removal case study for the full numbers.)
(Hot take: most consent banners are user-hostile theater anyway. If your analytics don't need cookies, don't pretend they do.)
Common errors and how to fix them
"My new-visitor rate barely changed after switching." Check your Safari traffic share. If Safari is under 15% of your audience (common for B2B with desktop-heavy enterprise users), the ITP effect is smaller. The fix still helps — it's just less dramatic.
"Cookieless numbers are even lower than cookie-based." Adblockers. Some blocklists flag privacy-first analytics scripts too. Proxy the script through your own domain to avoid this. On Next.js:
// next.config.js
module.exports = {
async rewrites() {
return [
{ source: '/ja/script.js', destination: 'https://cdn.justanalytics.app/script.js' },
{ source: '/ja/event', destination: 'https://api.justanalytics.app/event' },
];
},
};
Then update your script tag to src="/ja/script.js" and add data-api="/ja/event". We've seen 10-15% lifts in tracked pageviews after proxying on developer-focused sites.
"Historical comparison is broken." Yep. It will be. Your old data includes inflated new-visitor counts; your new data doesn't. Don't try to normalize retroactively — that way lies spreadsheet madness. Treat the switch date as a clean baseline and measure trends forward.
"Paid attribution still looks short." If you're running Google Ads or Meta and relying on platform pixels, those still use cookies. Cookieless analytics fixes your on-site measurement, not platform-side attribution. For click fraud filtering on the ad side, ClickzProtect handles that layer — it filters bot traffic before it reaches your analytics.
The bigger picture
Safari ITP is part of a broader shift. Apple, Mozilla, and eventually Google are all moving toward a web where persistent client-side identifiers don't exist. The "measure everything, store forever" model of 2015-era analytics is dying.
The teams that adapt early get accurate data. The teams that cling to cookie-based tracking will spend the next three years debugging mystery drops in their dashboards every time WebKit ships an update.
Cookieless analytics isn't a workaround. It's the architecture that survives. And yeah — I'm aware that sounds like marketing copy. But I've been burned enough times by cookie deprecation whiplash that I mean it.
If you're testing multi-account scenarios during the migration — verifying tracking across logged-in states, different user profiles, Safari vs. Chrome — JustBrowser gives you isolated browser contexts on a single machine. Cleaner than juggling incognito windows.
Frequently Asked Questions
Does ITP affect all browsers or just Safari?
ITP is Safari-only, but Firefox's Enhanced Tracking Protection and Brave's shields do similar things with different implementation details. Safari matters most because it's the default on every iPhone — so any site with significant mobile traffic is exposed. Chrome still allows longer-lived first-party cookies, but Google has signaled they'll tighten this eventually. Building on cookieless now means you're ready when Chrome catches up.
Will using a subdomain for analytics bypass ITP?
No. ITP specifically targets first-party cookies set by JavaScript, regardless of subdomain. The only cookies exempt from the 7-day cap are those set server-side with the HttpOnly flag on a request the browser initiated directly — which standard analytics scripts can't do. Some tools try CNAME cloaking (pointing a subdomain at the analytics vendor), but WebKit has been closing that loophole since ITP 2.1 and it's not a reliable workaround.
How much traffic comes from Safari anyway?
More than you think if you're US or EU focused. Safari holds about 27% of US browser market share (StatCounter, May 2026), but on mobile that jumps to over 50% in North America because every iPhone ships with Safari as the default. B2C sites, especially e-commerce and media, routinely see 40-55% Safari traffic. Check your own GA4 or analytics dashboard — filter by browser and you'll have the exact number. If it's above 25%, ITP is materially affecting your visitor counts.
Can I just extend the cookie expiration to work around ITP?
No. ITP ignores what you set in the Set-Cookie header or document.cookie call — it enforces the 7-day cap regardless. You could set a 365-day expiration and Safari will still delete the cookie after 7 days of the user not visiting. This is by design. Apple controls the browser, and they've made it clear they'll keep tightening. The only durable fix is to stop depending on cookies for visitor identification entirely.
Try JustAnalytics
All-in-one observability in one under-5KB script: cookieless analytics + error tracking + APM + session replay + uptime + structured logs. Replaces GA4 + Sentry + Datadog + Pingdom + LogRocket. Free tier (100K events/mo), Pro $49/month ($39 annual).
Author at JustAnalytics.