Storage · Concept
Partitioned cookies (CHIPS)
Published Updated
Cookies Having Independent Partitioned State (CHIPS) lets a server opt one cookie into
partitioned storage with the Partitioned attribute on Set-Cookie, so an embedded third party
gets a separate cookie jar on every top-level site that embeds it. The cookie still works for
an embedded chat widget or map on a given site, and stops working as a cross-site identifier,
because the jar set under retail.example is not readable under news.example.
How it works
Section titled “How it works”A partitioned cookie is double-keyed. The browser stores it under the pair of the host that set
it and a partition key, which is the site (scheme plus registrable domain) of the top-level page
the browser was showing when the request that set the cookie started. A cookie set by
support.chat.example while embedded on https://retail.example is keyed
{("support.chat.example"), ("https", "retail.example")}; the same embed on another site gets
an empty jar and sets its own cookie there (Cookies Having Independent Partitioned State,
privacysandbox.google.com).
Attribute requirements
Section titled “Attribute requirements”The attribute is accepted only together with Secure, so it is HTTPS-only by construction, and
the __Host- prefix is recommended so the cookie is bound to one hostname rather than to the
registrable domain. SameSite=None is what allows the cookie to be sent in a third-party context
at all; without it the cookie would be omitted from embedded requests regardless of partitioning.
Set-Cookie: __Host-session=5f2b; Secure; Path=/; SameSite=None; Partitioned;A cookie that omits Partitioned is unpartitioned and falls under whatever third-party-cookie
policy the browser applies: blocked by default in Firefox’s strict mode and in Safari, and subject
to Chrome’s user settings.
Limits and partitions
Section titled “Limits and partitions”Chrome stores at most 180 cookies per partition and caps the partition at 10 KB per embedded site; a widget that sets many small cookies on a busy top-level site hits the count limit first. Each top-level site is a separate partition, so the same widget embedded on a thousand sites holds a thousand jars, each independently subject to the limits.
Relationship to Firefox State Partitioning
Section titled “Relationship to Firefox State Partitioning”Firefox partitions every third-party cookie and storage API by top-level site in Enhanced Tracking Protection’s strict mode and in private windows, with no attribute required, and partitions network state (HTTP cache, DNS, connection pools) permanently (State Partitioning, developer.mozilla.org). CHIPS is the opt-in that behaves the same in each engine, which is why the attribute is the portable choice even where default partitioning exists.
Support
Section titled “Support”The attribute shipped in Chrome 114 after an origin trial from Chrome 100 to 116, in Firefox 141,
and in Safari 26.2 (BCD http.headers.Set-Cookie.Partitioned). An engine that does not recognise
Partitioned ignores the attribute and stores the cookie unpartitioned, which is why the
Secure and SameSite=None requirements matter: they are what keeps the fallback cookie usable.
Examples
Section titled “Examples”One example sets the cookie from the embedded server; the other inspects partition state from script where the browser allows it.
Setting a partitioned session cookie from an embedded service
Section titled “Setting a partitioned session cookie from an embedded service”The server of the embedded origin sets the cookie on the response to the first request from the iframe. Nothing in the embedding page changes.
// Express handler on support.chat.exampleapp.get('/widget/session', (req, res) => { res.setHeader( 'Set-Cookie', '__Host-chat=9b1f; Secure; Path=/; SameSite=None; Partitioned; Max-Age=86400' ); res.json({ ok: true });});On the next request from the same iframe on the same top-level site the cookie is present; on a different top-level site the server sees no cookie and starts a fresh session, which is the intended behaviour.
Reading partition state from the Cookie Store API
Section titled “Reading partition state from the Cookie Store API”document.cookie returns name=value pairs only, so script cannot tell a partitioned cookie
from an unpartitioned one through it. The Cookie Store API (Chrome 87, Firefox 140, Safari 18.4)
exposes a partitioned boolean on each cookie.
async function partitionedCookies() { if (!('cookieStore' in window)) { return null; // no Cookie Store API: partition state is not observable from script } const cookies = await window.cookieStore.getAll(); return cookies.filter((cookie) => cookie.partitioned);}A null result is the signal to rely on the server’s view instead: the server can log whether
the __Host- cookie arrived and under which Sec-Fetch-Site value.
See also
Section titled “See also”- Cookies Having Independent Partitioned State (CHIPS) (privacysandbox.google.com)
- Cookies Having Independent Partitioned State specification (ietf.org)
- Partitioned cookies (developer.mozilla.org)
- Storage Access API
- localStorage and sessionStorage
- Eviction and best-effort storage
Specifications
| Specification | Status |
|---|---|
| None. | |