Cookie Lifetime: The Three Browser Caps and How the Way a Cookie Is Set Changes It

Contents
A cookie header is a request, not an instruction. Max-Age=63072000 asks for two years, and what the browser grants depends on something the header does not mention: how the cookie came into being. The same line produces two years in one case and seven days in another, and nothing in the response says which.
The difference matters beyond tidiness. A returning visitor is only returning as long as the cookie that recognises them exists; once it is gone they are counted as new, and every window longer than the cookie’s life is arithmetic on data that no longer exists.

The Three Caps
Safari caps every cookie written through document.cookie at seven days. That is the rule with the largest practical effect, because most measurement cookies are written exactly that way – by a tag that runs in the page.
Safari applies the same seven days to cookies that arrive in an HTTP response from a host that resolves elsewhere through a CNAME. The intention is to catch the arrangement where a subdomain of the site points at a measurement provider; the effect is that a first-party cookie set the correct way is treated like a third-party one.
Chrome and Firefox cap at 400 days. That number rarely hurts – it is above every reasonable measurement window – but it does quietly end the two-year cookie that has been in the tag template since 2018.
Why the Route Decides, Not the Attribute
Two cookies with identical attributes can have different lifetimes, and the only difference is who wrote them. A cookie set by a script in the page is capped; the same cookie set in the response of one’s own server is not.
That is why moving the cookie into the response is the single most effective change available: it costs one endpoint on one’s own domain, and it is the difference between recognising a visitor for a week and recognising them for a year. The tag then reads the cookie rather than writing it.
The move has a second effect that is worth stating: a cookie written in a response can carry HttpOnly, and a cookie with HttpOnly cannot be read by any script on the page – including the ones nobody put there deliberately.
What a CNAME Changes
A subdomain pointing at a provider looks first-party in the address bar and is transparent to the browser: the resolution chain is visible, and the browser can see that the host ends up somewhere else. That is what the cloaking defence keys on.
The consequence is worth planning for rather than discovering: an arrangement built to escape third-party restrictions inherits the seven-day cap in Safari and gains, in return, a subdomain whose failure takes the whole measurement with it. Where the endpoint runs on one’s own infrastructure, neither applies.
The Attributes a Cookie Fails On
| Written like this | What happens |
|---|---|
SameSite=None without Secure |
Rejected outright by every current browser – the cookie is never stored. |
No SameSite at all |
Treated as Lax, so the cookie is absent from cross-site requests. |
__Host- with a Domain |
Rejected: the prefix forbids Domain and requires Secure and Path=/. |
| Name and value above 4096 bytes | Dropped without a word, which is how a consent string that grew stops arriving. |
Max-Age and Expires together |
Max-Age wins. Expires is only there for browsers nobody has anymore. |
All of these fail the same way: the response is fine, the cookie is simply not there afterwards. The only reliable check is to look at what the browser stored rather than at what was sent.
What Follows for the Measurement
A seven-day cookie makes a visitor who returns after eight days a new one. In a report that shows up as a share of returning visitors that is lower on Safari than everywhere else, and as conversion paths that are shorter than the sales cycle – not because the journey was short, but because the earlier part is no longer connected to it.
Where the cookie cannot be extended, the honest response is to shorten the window rather than to keep reporting one the data cannot support. A thirty-day attribution window over a seven-day cookie describes a period the browser has no memory of, and every figure derived from it inherits that gap.
Questions and answers
Does a cookie written by script get extended if the tag rewrites it on every visit?
Yes, but only until the first longer break. In Safari, every write through document.cookie sets a new seven-day limit counted from that moment. A visitor who returns within seven days therefore stays recognised, however often that repeats; one who stays away for eight days comes back as a new visitor, as described in the article.
Is it enough to connect one’s own measurement endpoint to the subdomain with an A record instead of a CNAME?
Not necessarily. Since Safari 16.4, WebKit checks the IP address as well as the CNAME chain: if the server answering on the subdomain sits in a clearly different address range from the site itself, Safari caps the cookies from its responses at seven days as well. An A record pointing at a server with a cloud provider while the main site is hosted elsewhere therefore escapes the CNAME rule and still runs into the same cap.
“One’s own infrastructure” in the sense of the article therefore means that the endpoint answers from the same address range as the site, for instance because both sit behind the same server or the same upstream network, or that it runs under a path on the main domain that forwards the request internally. Whether that worked is shown by the same check as for the attributes: the expiry Safari actually stored, not the header that was sent.
What does moving the cookie into the server response change about consent and its withdrawal?
Nothing about consent. Whether a cookie needs consent is decided by its purpose, not by the route by which it comes into being; it is stored on the device and read from there either way. A measurement cookie from the server response therefore needs the same consent as before, and the endpoint has to know the consent state before setting it. The longer lifetime also belongs wherever the storage period is stated, in the consent banner and in the privacy policy.
Withdrawal is a different matter. A cookie with HttpOnly cannot be deleted by any script on the page, including the consent banner’s. Withdrawal therefore has to trigger a request to one’s own server, which removes the cookie with a response such as Max-Age=0; otherwise the cookie outlives the withdrawal until its lifetime runs out, and that can now be a year.
How can the lifetime a browser actually granted to a cookie be checked?
By comparing two places in the developer tools, in each browser separately:
- The Set-Cookie header in the network panel shows what was asked for, Max-Age or Expires as the server sent it.
- The storage panel shows what was granted: the expiry the browser actually stored. For a cookie written by script that asks for two years, Safari shows a date seven days ahead, Chrome and Firefox one 400 days ahead.
- If the cookie is missing from storage altogether, it failed on one of the attributes in the table. Chrome flags rejected cookies in the details of the request concerned and states the reason.
The seven-day rules come from WebKit and can only be measured there, that is in Safari; a test in desktop Chrome shows at most the 400 days. Nor does a look at the report replace the check: the lower share of returning visitors on Safari is the consequence, not proof of the cause.