flowsk.com
Cornerstone

Safari's ITP explained: why your 30-day attribution window is really 7 days

Safari caps JavaScript-set cookies at 7 days. If you run a 30-day attribution window and half your traffic is iOS, most of your window is fiction. Here's the mechanic, the math, and the fix.

Aug 4, 2026· 5 min read ·Why attribution is broken
Quick answer

Effective window (Safari traffic) = min(your window, 7 days)

Safari's Intelligent Tracking Prevention deletes any cookie written by JavaScript after 7 days of no interaction — so a 30-day window only really exists for your non-Safari traffic. If 45% of your traffic is Safari and a third of your buyers take longer than a week to convert, you are structurally blind to roughly 15% of your conversions.

Server-set first-party cookies are exempt from the 7-day cap. That single implementation detail is the whole fix.

You set a 30-day click window in Meta. You set a 30-day lookback in GA4. You report on a 30-day window in the board deck.

For roughly half your mobile traffic, that window is seven days long. It has been since 2017, and nobody sends you an email about it.

What ITP actually does

Intelligent Tracking Prevention is Safari’s privacy system. The version that breaks attribution shipped in Safari 13.1 and has only tightened since:

Any cookie created through document.cookie — that is, written by JavaScript running in the page — is capped at a 7-day expiry. Safari rewrites the expiry you asked for. You ask for 365 days; you get 7.

Two details make this much worse than it sounds.

First, it applies to first-party cookies. This is not the third-party cookie story. This is the cookie on your own domain, written by your own script, identifying your own visitor. Owning the domain does not exempt you.

Second, it applies to storage too. Safari’s 7-day cap covers localStorage, sessionStorage (per session anyway), IndexedDB, the Cache API and service worker registrations. The common workaround — “we’ll just keep the id in localStorage” — buys you nothing.

The clock resets on interaction, but only for sites the user actually engages with. For a visitor who clicked your ad, browsed, and left, the clock runs out.

Here is the rule that matters, and it is not the one most teams have internalised:

Cookie Written by Safari cap
_ga, _fbp, most analytics ids JavaScript (document.cookie) 7 days
Third-party cookie on another domain Third-party script Blocked entirely
Your session cookie, set by Rails/Django/Express Your server (Set-Cookie header) Not capped

Your login session survives for months in Safari. Your analytics id does not. The difference is not the domain, the security flags, or the expiry you requested. It is which side of the wire wrote it.

Every mainstream client-side analytics tag — GA4, the Meta pixel, most CDPs, most “first-party” tag managers — writes its id from JavaScript. All of them are on the 7-day clock.

The math on your own funnel

The share of conversions you cannot credit is roughly:

lost ≈ safari_share × P(time_to_convert > 7 days)

Take a DTC brand: 48% of sessions from Safari/iOS, and 30% of buyers take longer than a week from first click to checkout.

0.48 × 0.30 ≈ 14.4% of conversions structurally uncreditable

Those conversions do not vanish. They show up as direct, organic, or (not set) — a brand-new anonymous visitor with no memory of the ad that paid for them. Your paid channel gets under-credited, your “direct” traffic looks miraculous, and you cut the campaign that was actually working.

The effect is not evenly distributed, which is what makes it so poisonous:

Business Typical Safari share Typical time to convert Uncreditable
Impulse DTC (< $40 AOV) 45% Same session ~2%
Considered DTC ($150+ AOV) 45% 3–14 days ~14%
B2B SaaS trial → paid 25% 14–45 days ~19%
High-ticket coaching / services 40% 21–60 days ~34%

The longer your sales cycle, the more of your window is imaginary. The businesses with the most to lose per conversion are the ones losing the most conversions.

What it looks like in your reports

You will not see an error. You will see these five symptoms:

  1. Safari converts “worse” than Chrome at similar volumes — often 20–40% worse on paid campaigns, with no product reason.
  2. Direct traffic grows in step with paid spend, which is not how direct traffic works.
  3. Meta reports more conversions than your database, because Meta is using its own view-through and self-attribution to fill the gap.
  4. Returning visitors look like new visitors after about a week.
  5. Your 30-day and 7-day window reports are nearly identical. If widening the window changes almost nothing, that is not a signal about your customers — it is a signal that the window is not real.

Symptom 5 is the cheapest to check and the most conclusive. Pull both windows right now.

The fix: move the id to the server

You cannot argue with Safari, and you should not want to — the privacy goal is legitimate. But there is a supported, non-adversarial path that keeps your measurement honest: stop writing the identifier from JavaScript.

  1. Your server sets the visitor id, in a first-party cookie, in an HTTP response. Not capped at 7 days.
  2. Make it HttpOnly. JavaScript never touches it, so ITP’s client-side heuristics never apply.
  3. Send conversions from your backend, not only from the browser. The purchase is confirmed by the system that took the money, not by a tag that may have been blocked.
  4. De-duplicate client and server events on a shared key so the sale is counted once, with the server’s version of the truth.

That is not a hack, a cloaked CNAME, or a workaround that breaks next quarter. It is the boring, standards-compliant answer: first-party data, set first-party, confirmed server-side.

It is also exactly what Flowsk does. In proxy mode your backend owns the cookie and forwards events to us, so the identifier is durable in Safari and the conversion is confirmed by your server. flowsk.com itself runs this way — our own funnel is measured by the product we sell.

What to do this week

  • Pull your 7-day vs 30-day window report. If they match, you have your answer.
  • Segment conversion rate by browser. Quantify the Safari gap.
  • Run the numbers through the ITP attribution-loss estimator so you have one figure to bring to the meeting.
  • Check whether anything on your site sets a durable id server-side. For most stacks, the honest answer is no.

Then decide whether you want to keep optimising against a window that, for half your customers, is 23 days shorter than the one in your report.

Frequently asked questions

Does ITP delete all cookies after 7 days?

No. ITP caps cookies written client-side through document.cookie at 7 days. Cookies set by your own server in an HTTP response (Set-Cookie, first-party, HttpOnly) are not subject to the 7-day cap. That distinction — who wrote the cookie, not who owns the domain — is what most teams miss.

Does this affect Chrome too?

Not the same way. Chrome caps first-party cookies at 400 days and has retired third-party cookies. Firefox's Total Cookie Protection partitions third-party storage. Safari is the aggressive one on first-party JavaScript cookies, and Safari is where most mobile purchase traffic lives in the US, UK, Canada and Australia.

Does localStorage survive ITP?

No. Safari also evicts localStorage, IndexedDB and Cache API data after 7 days of no user interaction with the site. Storing your visitor id in localStorage instead of a cookie does not buy you anything.

How do I know if this is hitting me?

Compare Safari's conversion rate to Chrome's for the same campaigns. If Safari looks systematically worse and the gap widens with longer consideration cycles, you are not seeing a worse audience — you are seeing a shorter memory.

What is the fix?

Set the visitor id from your own server, in a first-party HttpOnly cookie, and record conversions server-side. That is exactly what Flowsk's proxy mode does, and what the flowsk.com site itself runs.

Put a number on it

Enter your Safari share and how long your buyers take to decide. The estimator returns the share of conversions your current window structurally cannot credit.

Open the ITP loss estimator

Stop guessing which ad made the sale.

Flowsk Signals stitches the anonymous click to the email to the purchase — first-party, server-side, de-duplicated. One snippet, $29/mo, and every conversion comes with a receipt you can inspect.

Keep reading