Skip to content
SnapFrom

The Cookies That Arrive Before the Page Does

· · 9 min read

A wall of numbered wooden lockers with one door open and a pair of brown leather boots left inside

A cookie does not need JavaScript, a consent banner or a click. It needs one line in an HTTP response, and the specification puts no condition on which response: “Origin servers MAY send a Set-Cookie response header with any response”[1]. That includes the first one a site ever sends you, the one that carries the HTML.

On 11 October 2026 we requested the home page of the 500 top domains on the Tranco list[7], once each, with no cookies and no history, and read the headers that came back with the page. 204 distinct hostnames returned HTML. 116 of them set at least one cookie on that response. Between them they set 365.

Twenty-five of those sites asked the browser to keep a cookie for more than 400 days. One asked for 68 years. No current version of Chrome will keep any of them that long.

One line in the response

This is a cookie from roblox.com’s first response, with the value removed:

set-cookie: GuestData=...; domain=.roblox.com; expires=Thu, 26-Feb-2054 06:28:06 GMT; path=/

A name, a value, and three attributes. expires is a date 27 years out. domain=.roblox.com widens the cookie from the one hostname that set it to every subdomain. Nothing else is specified, so nothing else is restricted.

The browser stores it before it has parsed a byte of HTML, and sends it back on every later request that matches. What happens on the page afterwards is a separate matter: a banner can appear, a script can ask for consent, and this cookie was written before either of them existed. An earlier article covered what your request tells the server before any script runs. A Set-Cookie on the first response is how the server remembers that it was you.

What 204 home pages sent

on the first responsehostnamesshare of 204
At least one cookie11657%
At least one cookie that outlives the session10150%
A cookie requested for a year or more5527%
A cookie requested for more than 400 days2512%

Single request per site from one location, 11 October 2026, HTTP/2 client in Node.js 24.18 sending the request headers Chrome sends on a navigation, redirects followed, cookies counted on the final response only. Deletions (a cookie sent already expired) are excluded.

Half of the cookie-setting sites sent one or two. The most on a single response was 15, from weebly.com, followed by bing.com and dell.com with 11 each.

How long they ask for

A cookie with neither Max-Age nor Expires is kept until “the current session is over”[1]. Everything else is persistent, for as long as the server says. Here is what the 365 cookies asked for:

requested lifetimecookies
Session only79
Up to 1 hour53
1 hour to 1 day20
1 to 30 days52
30 days to 6 months28
6 months to 1 year61
Just over a year, up to 400 days30
More than 400 days42

The top of the last row:

sitecookierequested lifetime
alibaba.comcna68 years
alibabacloud.com_alicloud_ab_trace_id31.7 years
roblox.comGuestData, RBXEventTrackerV227.4 years
espn.com, go.comSWID20 years
goodreads.comccsid20 years
dell.comakGD12.2 years
weebly.comcookie-consent, srv_domainuserid10 years
yandex.ru, yandex.com_yasc10 years

Below those sit a group at 5 years (wordpress.com, discord.com, dropbox.com), PayPal at 3, and a long row at exactly 2 years: Bing, X, Yahoo Japan, MSN, Reddit, SoundCloud, Samsung.

We can report the name and the lifetime. We cannot report the purpose. A cookie’s name is whatever the site chose to call it, and nothing in the header says whether the value is an identifier, a preference or a load-balancer hint.

What the browser does with the request

The expiry date is a request. The draft that is set to replace the 2011 cookie specification says so in as many words: the browser “may adjust the specified date and is not required to retain the cookie until that date has passed”[2]. It also puts a number on it. “The recommended cookie expiry upper limit is 400 days”[2], and when a Max-Age is larger than the limit the browser is told to use “the smaller” of the two[2].

Chrome has done this since August 2022: “cookies can no longer set an expiration date more than 400 days in the future”. The long ones are not refused: “their expiration date is set to 400 days instead”[3].

So in Chrome, alibaba.com’s 68 years, Roblox’s 27 and Bing’s 2 all become the same 400 days. Every one of the 42 cookies in the last row of the table is asking for time the browser will not give.

Some sites have noticed. A dozen cookies in the sample ask for 400 days exactly, Instagram’s and Facebook’s among them: Max-Age=34560000, which is 400 days in seconds.

The limit is less of a limit than it looks, because it is measured from the moment the cookie is set[3], and a server can set it again. A site that re-sends the cookie on each visit pushes the date out to 400 days from that visit. For a reader who returns at least once every 400 days, the cookie never expires. What the cap removes is the identifier that survives years of absence.

Two other clocks apply.

Safari’s 7 days are for a different kind of cookie. WebKit “deletes all cookies created in JavaScript and all other script-writeable storage after 7 days of no user interaction with the website”[4]. A cookie that arrives in an HTTP response is not created in JavaScript. For response cookies WebKit applies a 7-day cap only where a third party is hiding behind the first party’s name, through “third-party CNAME cloaking and third-party IP address cloaking”[4]. A first-party cookie set by the site’s own server on the first response is outside both rules.

A session can outlast the session. The 79 cookies with no expiry are meant to go when the browser closes. But “many web browsers have a session restore feature”, and when it is on, “session cookies will also be restored, as if the browser was never closed”[5]. The definition of “session” was left to the browser from the start[1].

Who gets it back

The remaining attributes decide where the cookie travels. Of the 365:

attributecookiesshare
Domain set (shared with subdomains)25770%
Secure24968%
HttpOnly13738%
SameSite missing16545%
SameSite=None14339%
SameSite=Lax4613%
SameSite=Strict113%
Partitioned51%

Domain is the common one. With it set to site.example, the cookie goes to “site.example, www.site.example, and www.corp.site.example”[2]: every service the company runs under that name.

SameSite controls whether the cookie is sent when the site is loaded from inside another site. Strict cookies go “only” with same-site requests. Lax adds top-level navigations from elsewhere. None means the cookie “will be sent with same-site and cross-site requests”[2].

Two in five of the cookies we saw declare None. That is the site asking for its cookie back when it appears as an embed, a widget or a pixel on someone else’s page. Whether it gets it depends on the browser: WebKit “by default blocks all third-party cookies. There are no exceptions to this blocking”[4].

Nearly half declare nothing. For those the browser picks, and the answer is not uniform: “Some browsers use Lax as the default value if SameSite is not specified”[5]. A cookie written with no SameSite in 2015 has a different reach today than its author gave it, without a single byte of the header changing.

Partitioned asks for a cookie that is “stored using partitioned storage”[5], so that an embed keeps a separate copy for each site it is embedded in. All five in the sample came from one site, youtube.com.

The most common cookie in the sample by a wide margin was __cf_bm. It was on 28 of the 116 cookie-setting pages. On 21 pages, every cookie on the response belonged to Cloudflare.

It is set by the CDN in front of the site. “Cloudflare places the __cf_bm cookie on end-user devices that access customer sites protected by Bot Management or Bot Fight Mode”[6]. It is short-lived, expiring “after 30 minutes of continuous inactivity”, and the documentation says it is scoped to one site: “Cloudflare does not track users from site to site or from session to session”[6]. In our data it was requested for 30 minutes every time.

A team can audit its own code, find no Set-Cookie anywhere, and still be setting a cookie on every first visit, because the line is added after the response leaves their server. It can be switched off, “using the bm_cookie_enabled field via the API”[6], at the cost of the bot detection that depends on it.

What this measurement cannot see

One request from one place undercounts and miscounts in ways that should be stated.

The counts are a floor. Everything a page sets from JavaScript after it loads, and everything third-party scripts set, is invisible here.

They also come from one location. Several of the cookies in the sample are named for a country or a region, so the first response plainly depends on where the request comes from, and a visitor somewhere else may be sent fewer cookies than we were, or more.

The client was a script. It sent Chrome’s navigation headers, but a server has other ways to tell a script from a browser, and some of the short-lived cookies here belong to bot-detection products that may have been reacting to ours.

Last, a header count says nothing about what a cookie is used for. The standard that defines cookies has said since 2011 that they “are often criticized for letting servers track users”[1]. A language preference and a visitor identifier look identical at this level. The numbers above measure how much is stored and for how long, which is the part a header can prove.

Checking a site

The request we made is one line:

curl -s -o /dev/null -D - https://www.example.com/ | grep -i '^set-cookie'

Add -L to follow redirects, and remember that each hop can set cookies of its own. 37 of the 204 sites in the sample set at least one on a redirect before the final page.

To see what the browser did with the request, open a private window, load the page, and look at the cookie list in the developer tools before touching anything. The expiry column shows what was stored, which for the long ones will not match what was sent.

Where that leaves you

Half of the most-visited home pages write something persistent to your device in the same response that delivers the HTML. That happens ahead of any banner, because the banner is part of the page and the cookie is part of the envelope it came in.

The lifetimes on those cookies are mostly theatre above 400 days, at least in Chrome, and mostly irrelevant below it, since any visit can renew them. The attributes are where the real differences are: whether a cookie is confined to one hostname or spread across a company’s subdomains, and whether it is offered back when the site is embedded elsewhere. Those two columns say more about a first response than the expiry date does.

Sources

  1. RFC 6265: HTTP State Management Mechanism - RFC Editor, IETF, accessed

    Supports: Published April 2011. Section 3: 'Origin servers MAY send a Set-Cookie response header with any response.' Section 4.1.2.2: 'If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence and controls the expiration date of the cookie. If a cookie has neither the Max-Age nor the Expires attribute, the user agent will retain the cookie until "the current session is over" (as defined by the user agent).' Section 7.1: 'Cookies are often criticized for letting servers track users.'

  2. Cookies: HTTP State Management Mechanism (draft-ietf-httpbis-rfc6265bis-22) - IETF HTTP Working Group, accessed

    Supports: Dated 1 December 2025, 'Obsoletes: 6265 (if approved)', and listed in the RFC Editor's queue on the IETF datatracker when accessed. Section 7.2: 'The recommended cookie expiry upper limit is 400 days. User agents may set a lower limit to enforce shorter data retention timelines, or set the limit higher to support longer retention when appropriate'. In the Max-Age processing steps: 'Let cookie-age-limit be the maximum age of the cookie (which SHOULD be 400 days or less, see Section 5.5). Set delta-seconds to the smaller of its present value and cookie-age-limit.' Section 4.1.2.1: 'The user agent may adjust the specified date and is not required to retain the cookie until that date has passed.' Section 4.1.2.7: with 'Strict' a cookie 'will only be sent along with "same-site" requests'; with 'Lax' it 'will be sent with same-site requests, and with "cross-site" top-level navigations'; with 'None' it 'will be sent with same-site and cross-site requests'; any other value is 'subject to a default enforcement mode that is equivalent to "Lax"'. Section 4.1.2.3: with Domain set to site.example, the cookie is included 'when making HTTP requests to site.example, www.site.example, and www.corp.site.example'.

  3. Cookie Expires and Max-Age attributes now have upper limit - Chrome for Developers, Google, accessed

    Supports: 'As of Chrome release M104 (August 2022) cookies can no longer set an expiration date more than 400 days in the future.' And: 'Cookies that request an expiration date further out than 400 days aren't rejected; their expiration date is set to 400 days instead.'

  4. Tracking Prevention in WebKit - WebKit, Apple, accessed

    Supports: 'ITP deletes all cookies created in JavaScript and all other script-writeable storage after 7 days of no user interaction with the website.' For cookies in HTTP responses the cap applies only to cloaked third parties: 'ITP detects third-party CNAME cloaking and third-party IP address cloaking requests and caps the expiry of any cookies set in the HTTP response to 7 days.' And: 'ITP by default blocks all third-party cookies. There are no exceptions to this blocking.'

  5. Set-Cookie header - MDN Web Docs, Mozilla, accessed

    Supports: On session cookies: 'Many web browsers have a session restore feature that will save all tabs and restore them the next time the browser is used. Session cookies will also be restored, as if the browser was never closed.' On SameSite: 'Some browsers use Lax as the default value if SameSite is not specified'. On Partitioned: it 'Indicates that the cookie should be stored using partitioned storage', and 'Partitioned cookies must be set with Secure.'

  6. Cloudflare cookies - Cloudflare, accessed

    Supports: 'Cloudflare places the __cf_bm cookie on end-user devices that access customer sites protected by Bot Management or Bot Fight Mode.' 'This cookie expires after 30 minutes of continuous inactivity by the end user.' 'A separate __cf_bm cookie is generated for each site that an end user visits, as Cloudflare does not track users from site to site or from session to session.' 'You can disable the __cf_bm cookie using the bm_cookie_enabled field via the API.'

  7. Tranco list 8PXYV (generated 2026-10-10) - Tranco, accessed

    Supports: The sample for the survey: the first 500 domains of Tranco list 8PXYV, generated on 10 October 2026. Tranco ranks registrable domains, not websites, so a share of its top entries (API, CDN and telemetry hostnames) serve no page at all.