Skip to content

The Cookie Store API

document.cookie is a synchronous API designed in the mid-1990s. It has three well-known friction points:

  1. Parsing is manual — reading a specific cookie requires splitting and looping.
  2. Writes are string-based — you build a cookie string by hand.
  3. No change events — there is no way to observe when another tab or the server changes a cookie.

The Cookie Store API solves all three with a clean, Promise-based interface.

The Cookie Store API ships in Chrome and Edge (Chromium-based browsers). Firefox does not support it yet. Always feature-detect before using it.

Returns a Promise that resolves to a CookieListItem object or null if the cookie does not exist:

const cookie = await cookieStore.get('theme');
if (cookie) {
console.log(cookie.name); // 'theme'
console.log(cookie.value); // 'dark'
}

The returned object also includes domain, path, expires, secure, sameSite, and httpOnly properties.

Accepts a name/value string pair or an options object:

// Simple form
await cookieStore.set('theme', 'dark');
// Options form — recommended for control over attributes
await cookieStore.set({
name: 'theme',
value: 'dark',
maxAge: 86400,
sameSite: 'lax',
});

Returns a Promise that resolves when the cookie is written.

await cookieStore.delete('theme');

Returns a Promise that resolves when the cookie is deleted. This is equivalent to setting Max-Age=0.

const allCookies = await cookieStore.getAll();
allCookies.forEach(c => console.log(c.name, c.value));

Unlike document.cookie, this returns a proper array of objects — no string parsing required.

The Cookie Store API allows you to listen for cookie changes reactively:

cookieStore.addEventListener('change', event => {
event.changed.forEach(c => {
console.log('Cookie changed:', c.name, '=', c.value);
});
event.deleted.forEach(c => {
console.log('Cookie deleted:', c.name);
});
});

event.changed is an array of cookies that were set or updated. event.deleted is an array of cookies that were removed. This works across tabs for cookies that are not scoped to a single tab.

Because browser support is incomplete, always feature-detect and fall back to document.cookie:

async function getTheme() {
if ('cookieStore' in window) {
const c = await cookieStore.get('theme');
return c ? c.value : null;
} else {
// document.cookie fallback
var pairs = document.cookie.split('; ');
for (var i = 0; i < pairs.length; i++) {
var p = pairs[i].split('=');
if (p[0] === 'theme') return decodeURIComponent(p[1]);
}
return null;
}
}
Browser Storage
OptionBenefitCost
Cookie Store APIMuch shorter, more readable code — await cookieStore.get() instead of splitting a string yourself, plus a reactive change event to listen toNot supported in Firefox — you must feature-detect and always write a document.cookie fallback, doubling the code for the same logic
document.cookieWorks in every browser, no fallback neededA synchronous string API you must parse yourself every time, with no built-in change event
  • Calling cookieStore.get()/.set() without feature-detecting first — the code breaks immediately in Firefox, since cookieStore doesn’t exist on window.
  • Forgetting that every Cookie Store API method is async — writing code as if the value comes back synchronously gets you a Promise object instead of the real value; always await it.
  • Assuming the change event behaves identically across every browser and situation — this event’s cross-tab behavior isn’t fully standardized across implementations yet, so test it directly before relying on it as core logic.
What does cookieStore.get(name) return when the cookie exists?
Which browser does NOT yet support the Cookie Store API?
How do you listen for cookie changes using the Cookie Store API?