Skip to content

The history of the cookie: from Lou Montulli's 1994 hack to SameSite

· 22 min read
Copyright: MIT
The word COOKIE in monospace with a Set-Cookie header underline in orange

Every web request is amnesiac. HTTP, as Tim Berners-Lee designed it, has no memory of the request that came before. You ask for a page, the server answers, the connection closes, and as far as the protocol is concerned you have never existed and never will again. That property made HTTP simple to implement and easy to scale. It also made it useless for anything resembling a session. You could not log in, because there was nothing to stay logged into. You could not fill a shopping cart, because the second item forgot the first.

The fix for that gap was a single HTTP header and a small blob of text the browser agreed to hand back. It took one engineer at Netscape a few weeks in 1994 to design, it shipped in a beta browser the same year, and it has survived every attempt to standardize, constrain, or kill it for more than three decades. This post follows that header from its origin as a Unix borrow-word, through three competing IETF specifications, into the surveillance machine the advertising industry built on top of it, and out the other side into the SameSite era, where the most-promised change in the cookie’s history, the death of the third-party cookie, was announced, delayed, and then quietly cancelled.

The story moves in roughly chronological order: the invention and the magic-cookie origin, the original Netscape spec and its deliberate same-origin design, the three RFCs that tried to formalize it (2109, 2965, and finally 6265), the tracking era that grew in the gap between what the spec recommended and what browsers actually did, the security attributes bolted on after the fact, and the SameSite and partitioning work that defines where the cookie sits in 2026.

In the summer of 1994 Lou Montulli was one of Netscape Communications’ first engineers, working on the browser that would ship as Mosaic Netscape. The assignment was concrete. An e-commerce client needed a shopping cart, and a shopping cart needs the server to remember what you put in it across more than one page load. Montulli’s own description of the problem is the clearest version of it: you browse items, you see a pair of shoes you like, you click buy, and you expect the shoes to land in a cart instead of vanishing into the stateless void.

The mechanism he reached for already had a name in computing. A “magic cookie” was Unix jargon for an opaque token a program receives and later hands back unchanged, without ever needing to understand its contents. The classic example is the data returned by certain system calls, meaningful to the issuer and inert to the holder. Montulli had read the term years earlier in an operating-systems manual, dropped the “magic,” and applied the same idea to the web. The server would hand the browser a small piece of state. The browser would store it and return it on subsequent requests to the same site. Neither side had to keep a per-user table in memory between requests, the thing HTTP refused to do for you.

The wire format was deliberately plain. A server set state by emitting a response header, and the canonical example from the era reads almost exactly like the ones servers send today.

Server → browser (response header) Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=... Browser → server (every later request to the same site) Cookie: CUSTOMER=WILE_E_COYOTE *The original asymmetry, unchanged since 1994: the server speaks Set-Cookie once, the browser echoes Cookie on every subsequent request to the matching site.*

Mosaic Netscape 0.9beta shipped with cookie support on 13 October 1994. The format had a name=value pair, an expiry, a path, and an optional domain, and that small set of fields is still recognizable in the headers a 2026 browser sends. Montulli and John Giannandrea wrote up the behavior in a short preliminary specification that Netscape posted on its site, a document of a few hundred words that browsers other than Netscape’s then copied because there was nothing else to copy.

The privacy property that later defined the whole fight was baked in from that first spec, and it was intentional. A cookie set by a site came back only to that site. The browser scoped each cookie to the host (and optionally a path) that set it, so in the design as written, a server learned only about its own visitors. There was no provision for one site to read another’s cookie. The hole that the tracking industry drove through was not in the cookie itself. It was in a detail the spec did not constrain: which “site” a cookie belongs to when the resource setting it is an image, a script, or a pixel loaded from a third domain inside someone else’s page.

Netscape filed for a patent on the mechanism in October 1995. US Patent 5,774,670, “Persistent client state in a hypertext transfer protocol based client-server system,” lists Lou Montulli as inventor, was assigned to Netscape Communications Corp, filed 6 October 1995, and granted 30 June 1998. The patent’s worked examples are the e-commerce ones: a shopping cart, a subscription service that remembers a paying customer. Surveillance is not in the document. The assignee field on the patent today reads Meta Platforms, an artifact of how the wreckage of Netscape’s patent portfolio drifted through AOL and on.

1996: the gap becomes a business

Within two years the same-origin promise had a commercial exception nobody had asked for. An ad network that served images on Site A and Site B from a single domain could set one cookie from that domain, and because the browser returned a cookie to whoever set it, the network now recognized the same browser on both sites. The cookie was still scoped correctly by the letter of the design. It was just that the relevant scope had become the ad server’s domain rather than the publisher’s, and the ad server appeared on thousands of publishers.

DoubleClick, founded in 1995, built a business on exactly this. The technical move was small and the spec did not forbid it, which is the whole problem. A 1×1 transparent GIF, served from the ad domain and embedded in a page, was enough to set and read a cross-site cookie on every page that carried the tag. The general public found out on 12 February 1996, when the Financial Times ran a story explaining to readers that the files quietly accumulating on their disks could be used to follow them. Two Federal Trade Commission workshops in 1996 and 1997 took up cookie privacy. The mechanism kept growing anyway.

This is the through-line for the rest of the cookie’s history and for a good deal of the modern web’s plumbing. The cookie itself is a first-party tool. The tracking apparatus is what you get when a first-party tool is loaded from a third party, on enough pages, by enough networks, that the third party’s view of you is wider than any single publisher’s. Everything the standards bodies did over the next twenty-five years was an attempt to draw a line between those two uses without breaking the first one. If you have read the companion pieces on the history of web scraping or the history of robots.txt, the pattern will be familiar: a mechanism designed for cooperation gets repurposed at scale, and the standards bodies spend the next two decades retrofitting consent onto something that shipped without it.

1997-2000: the IETF tries, twice

The IETF took its first formal run at cookies with RFC 2109, published in February 1997. The document is short and unambiguous about the danger. It names third-party cookies as a privacy threat in those words, and it recommends that user agents not send cookies back to a server in an “unverifiable transaction” unless the user has been given a chance to allow it. In practice the rule meant a browser following RFC 2109 would not, by default, return a cookie to an ad server embedded inside a page the user navigated to for some other reason. The spec also introduced a Max-Age attribute as an alternative to the original Expires date and tried to tighten the rules around the Domain attribute.

1994 Netscape spec, Mosaic Netscape 0.9beta 1997 RFC 2109 — first IETF spec, blocks 3p by default 2000 RFC 2965 — Set-Cookie2, never adopted 2011 RFC 6265 — documents reality, allows 3p 2016 SameSite draft / Chrome 51 2020 Chrome 80 — SameSite=Lax becomes default *Four specifications across two decades. The two that took hold (the 1994 Netscape note and RFC 6265) described what browsers already did; the two that tried to lead behaviour from the front (2109's privacy default and 2965's Set-Cookie2) were ignored.*

The browsers ignored it. Netscape and Internet Explorer kept sending third-party cookies by default, because the advertising money was on the other side of the recommendation and a browser that broke ad targeting was a browser that lost a fight nobody at the time wanted to have. The IETF tried again with RFC 2965 in October 2000, which introduced a parallel header, Set-Cookie2, and a matching Cookie2 request header, intended to be a cleaner, versioned replacement for the Netscape-style header. It carried over the same privacy posture toward unverifiable transactions.

Set-Cookie2 went essentially unused. Sites kept emitting the original Set-Cookie because that was what every browser already parsed, and a header that only some clients understood was strictly worse than one they all did. By the late 2000s the situation was that the deployed reality (Netscape-style Set-Cookie, third-party cookies flowing freely) had almost nothing to do with the two RFCs that were supposed to govern it. There was a written standard, and there was the web, and they were different documents.

2011: RFC 6265 documents the world as it is

RFC 6265, published in April 2011, resolved the contradiction by surrendering to it. Where 2109 and 2965 had described how cookies should behave and watched browsers do something else, 6265 set out to describe what browsers actually did and to make that the standard. Adam Barth’s document obsoletes both earlier RFCs and deprecates Set-Cookie2 outright. It specifies the syntax and the algorithms for the Set-Cookie and Cookie headers as they were genuinely implemented, including the messy parts that real servers depended on.

On the privacy question, 6265 made the deployed reality official. The earlier RFCs had recommended blocking third-party cookies by default; 6265 says a user agent may implement whatever third-party policy it likes. The privacy default that the IETF had recommended in 1997 and that browsers had refused for fourteen years was now simply not part of the standard. The spec also nailed down the attributes that had accumulated over the years, Secure (send only over HTTPS), HttpOnly (hide from page JavaScript), Domain, Path, Expires, and Max-Age, and documented the precise, slightly insane rules a browser uses to decide whether a given cookie is “for” a given request.

Set-Cookie: sid=abc123; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=3600 name=value — the only required part Secure — HTTPS only HttpOnly — invisible to document.cookie SameSite — cross-site sending policy Path / Max-Age — scope and lifetime *A 2026 Set-Cookie header. Only name=value is mandatory; everything after the first semicolon is an attribute a server opts into, and most of them were retrofitted years after Montulli's original four fields.*

It is worth dwelling on what 6265 did not do, because the omission shaped the next fifteen years. It standardized the cookie as a transport with no opinion about who should be allowed to set one in a third-party context. That decision was punted back to the browser vendors. So the question of whether DoubleClick’s successor could follow you across the web stopped being a standards question and became a product question, settled differently by Safari, Firefox, and Chrome on their own schedules and for their own commercial reasons. The IETF had written down the cookie. It had not written down a privacy model. That was left for the implementers, and the implementer with the largest ad business got the loudest vote.

The security attributes, bolted on after the fact

Three of the attributes on a modern cookie exist because the original design had no security model at all, and each was added in response to a specific class of attack rather than as part of a coherent plan.

The Secure flag was the oldest of the three, present in spirit from early on: a cookie marked Secure is only sent over an encrypted connection, which keeps a session token off the wire where a network attacker could read it. It matters more now than it did in 1994 because more of the web is authenticated and almost all of it can be intercepted somewhere along the path. The companion work on the history of TLS and SSL covers the encryption layer that Secure leans on; without it, the flag is a promise the network can break.

HttpOnly came from Microsoft. Internet Explorer 6 Service Pack 1, released in 2002, introduced an attribute that told the browser to hide a cookie from client-side script. A cookie marked HttpOnly is not readable through document.cookie, which removes the single most common payoff of a cross-site scripting bug: stealing the victim’s session cookie and replaying it. Michael Howard, then in Microsoft’s Secure Windows Initiative, described the motivation plainly, that the majority of XSS attacks were after session cookies, so make the session cookie unreachable from script. It was a vendor extension years before any RFC blessed it, and it spread because it worked, which is the recurring pattern for everything good that happened to the cookie.

The two name prefixes, __Secure- and __Host-, came later still and are the cleverest of the lot because they need no new parsing machinery. A cookie whose name begins with __Host- is only accepted by the browser if it was set with Secure, with Path=/, and with no Domain attribute, which pins it to exactly one host and forbids a subdomain from writing a cookie that a parent domain will trust. The browser enforces the constraint by inspecting the name, so a server can demand the protection just by choosing a name, and an attacker who controls a sibling subdomain cannot forge a cookie that passes the check. For the threat models these defend against, the post on cookie security attributes goes field by field; the short version is that the prefix is a contract encoded in a string, which is an ugly trick that happens to work.

None of these touch the third-party problem. Secure, HttpOnly, and the prefixes harden a cookie against theft and forgery. They say nothing about whether a cookie should cross a site boundary in the first place. That question waited until SameSite.

2016-2020: SameSite and the cross-site boundary

The SameSite attribute is the first piece of the cookie that directly targets cross-site behaviour rather than confidentiality or integrity. It was proposed in an IETF draft around 2016, with the original work coming out of Google, and Chrome 51 shipped the first implementation the same year. The attribute takes three values and the names describe the behaviour reasonably well.

SameSite=Strict means the cookie is only attached to requests that originate from the same site, full stop. Follow a link from another site to yours and the Strict cookie does not ride along on that first navigation, which is why a Strict session cookie can log you out the moment you arrive from an external link. SameSite=Lax relaxes that one case: the cookie is withheld from cross-site subresource loads and cross-site POSTs, but it is sent on a top-level cross-site navigation, the ordinary act of clicking a link to the site. SameSite=None means the old behaviour, send the cookie in every context including third-party ones, and it is the value an ad network needs.

Request crosses a site boundary. Is the cookie sent? Strict Lax None top-level navigation (click a link) subresource / iframe / POST no no yes no yes yes (needs Secure) Since Chrome 80 (Feb 2020), a cookie with no SameSite attribute is treated as Lax. *The three SameSite modes reduce to one question per request: does this cookie cross a site boundary, and in what kind of request. None is the only value that preserves the third-party tracking case, and it now requires Secure.*

The structural change came with Chrome 80 in February 2020. Before that release, a cookie with no SameSite attribute behaved like None, sent everywhere, because that was the historical default and most cookies on the web carried no attribute at all. Chrome 80 flipped the default: a cookie that does not declare a SameSite value is now treated as SameSite=Lax. Cross-site sending stopped being the implicit behaviour and became something a server has to ask for by writing SameSite=None, and that request now only works if the cookie is also marked Secure. In one default change, the unmarked cookie went from a tracking-friendly default to a same-site-by-default one, and the burden of declaring a cross-site cookie shifted onto whoever actually wanted one.

The change was not clean. A pile of legacy single-sign-on flows depended on a cookie surviving a cross-site top-level POST, the kind of redirect-and-post dance that older identity providers used. Chrome added a temporary intervention, sometimes called Lax+POST, that lets a freshly set cookie (at most two minutes old) ride along on a top-level cross-site POST even under the Lax default, specifically to keep those SSO flows working while their owners migrated. It was always described as a transitional hack to be removed, and it is the kind of pragmatic ugliness that shows up whenever a default changes under a web that was built assuming the old one.

This same boundary, same-site versus cross-site, is the one that anti-bot vendors now lean on hard. The cookies that systems like Akamai Bot Manager’s _abck cookie and Cloudflare’s cf_clearance cookie issue live inside the same Set-Cookie machinery Montulli designed, with SameSite and Secure attributes set deliberately, and their whole value depends on a client returning the right cookie in the right context. The mechanism that started as a shopping-cart token is now the carrier for clearance tokens, bot scores, and session-binding state, which is a long way from remembering a pair of shoes.

2020-2025: the phase-out that wasn’t

For a stretch around the turn of the decade it looked as if the third-party cookie was actually going to die. Safari had been killing it incrementally through Intelligent Tracking Prevention since 2017, Firefox blocked known trackers by default, and in January 2020 Google announced that Chrome would phase out third-party cookies entirely within roughly two years, with a set of replacement APIs grouped under the Privacy Sandbox banner meant to deliver advertising’s core functions without per-user cross-site identifiers.

The two years became four, and the four became never. The deadline slipped repeatedly. On 22 July 2024 Google announced it would not unilaterally deprecate third-party cookies after all, replacing the deprecation with a planned user-choice prompt in Chrome that would let people decide for themselves. By April 2025 even that scaled-back prompt was dropped; Google said it would keep the existing cookie controls in Chrome settings and not introduce a new standalone prompt. The Privacy Sandbox APIs that were supposed to inherit the cookie’s job, Topics, Protected Audience, Attribution Reporting, were wound down in 2025, and Google retired the Privacy Sandbox brand while saying its privacy work would continue under other names.

The reason the phase-out collapsed is not mainly technical, though the replacement APIs genuinely could not match what third-party cookies did. The binding constraint was competition. The UK’s Competition and Markets Authority had spent years scrutinizing the plan precisely because the party removing the industry’s shared tracking identifier was also the largest seller of advertising and the owner of a browser with roughly two-thirds of the global market. Removing third-party cookies would have hurt every ad network that depended on them, including Google’s competitors, while Google’s own first-party data and logged-in user base would have carried on. A privacy improvement that happens to kneecap your rivals is hard to ship past a regulator, and it did not ship.

So as of 2026 the third-party cookie is still here, in Chrome, by default, after more than a decade of obituaries. What changed is everything around it. SameSite=Lax-by-default removed the casual cross-site cookie, the one that rode along without anyone declaring it. The cookies that remain in third-party contexts now have to announce themselves with SameSite=None; Secure, which makes them visible and blockable in a way the old unmarked default never was. Safari and Firefox block them regardless of what Chrome does. The third-party cookie did not die. It got labelled, cornered into a single declared mode, and left standing in the one browser whose owner had the most reasons not to remove it.

2025 and beyond: the spec finally catches up

The standards picture is finally consolidating, decades late. RFC 6265bis, the working-group draft that obsoletes 6265, reached revision 22 in December 2025 and sits in the RFC Editor’s queue waiting to be published as a Proposed Standard. It folds the pieces that grew up as separate drafts and vendor behaviours into one document: SameSite with its three modes, the __Secure- and __Host- name prefixes, and the modern algorithms for storing and retrieving cookies. When it publishes, the written standard will describe SameSite and the prefixes as first-class parts of the cookie rather than browser extensions stapled on after the fact, which is the first time since 1997 that the spec and the deployed web will genuinely agree on the privacy model.

Partitioning is the other live thread. CHIPS, defined in a Privacy Community Group specification and shipped in Chrome, adds a Partitioned attribute that ties a cross-site cookie to the top-level site it was first set under. A partitioned cookie set by an embed on site A is a different cookie from one the same embed sets on site B; the two cannot be joined, so the embed can keep per-site state (a logged-in widget, a saved preference) without becoming a cross-site identifier. It requires Secure and works alongside SameSite=None, and it is the cleanest answer anyone has produced to the original 1996 problem: keep the legitimate embedded-state use, break the cross-site-join use, and do it in the cookie layer rather than by removing third-party cookies outright. The companion post on CHIPS and partitioned cookies goes deeper; the relevant point here is that partitioning, not deprecation, is where the energy went once the deprecation plan died.

What the cookie’s history actually shows

The cookie is a thirty-two-year-old design that has outlasted three attempts to standardize it from the front and one serious attempt to kill it. The reason is the reason it shipped in the first place: it solves the stateless-HTTP problem cheaply, it requires nothing of the server but a header, and every browser already understands it. Every replacement proposed since, including the Privacy Sandbox APIs, has had to clear a bar the cookie cleared in 1994 by being simpler than the problem it solved. None of them did.

The recurring lesson across the four specifications is that browsers standardized what they were already doing and ignored what they were told to do. RFC 2109 and 2965 tried to legislate a privacy default and were ignored for fourteen years. RFC 6265 described the world as it was and was adopted immediately. SameSite-by-default succeeded where the earlier privacy recommendations failed for a mundane reason: it shipped as a browser default first and became a standard second, instead of the other way around. The cookie’s history is a long demonstration that on the web, the implementation is the specification, and the document that wins is the one that writes down what the implementations already agreed to do.

The detail that lands hardest is that the most-promised change never happened. The third-party cookie was declared dead by the company best positioned to kill it, on a public schedule, more than once, and in 2026 it is still the default in the browser most people use. The thing that finally constrained it was not a standards body or a privacy team. It was an antitrust regulator pointing out that the company removing the web’s shared tracking identifier would be the last one left holding a private one. Montulli built a token to remember a shopping cart. It became the substrate for surveillance, then for bot detection, then for an antitrust argument, and through all of it the header on the wire still reads the way it did in 1994.


Sources & further reading

Further reading