Parsing and Deleting Browser Cookies With JS
A complete tutorial on parsing and deleting browser cookies with JavaScript. Covers cookie string parsing, regex-based extraction, URL-decoded cookie values, deleting cookies with matching attributes, bulk deletion, cookie expiration detection, building a cookie parser class, and advanced cookie management utilities.
document.cookie returns a flat string of key-value pairs. Parsing this string correctly, handling encoded values, and deleting cookies with matching attributes requires careful utility code. This guide covers robust parsing, targeted deletion, and building a production-ready cookie toolkit.
For setting cookies and understanding attributes, see how to manage cookies in JS complete tutorial.
Understanding the Cookie String
// document.cookie returns a semicolon-separated string
console.log(document.cookie);
// "username=parth; theme=dark; lang=en; prefs=%7B%22font%22%3A16%7D"
// Important: only name=value pairs are visible
// Attributes (path, domain, expires, etc.) are NOT included in the string
// HttpOnly cookies are NOT includedParsing All Cookies
Simple Parser
function parseCookies(cookieString = document.cookie) {
if (!cookieString) return {};
return cookieString.split("; ").reduce((cookies, pair) => {
const separatorIndex = pair.indexOf("=");
if (separatorIndex === -1) {
cookies[pair.trim()] = "";
return cookies;
}
const key = decodeURIComponent(pair.slice(0, separatorIndex).trim());
const value = decodeURIComponent(pair.slice(separatorIndex + 1).trim());
cookies[key] = value;
return cookies;
}, {});
}
const cookies = parseCookies();
console.log(cookies);
// { username: "parth", theme: "dark", lang: "en", prefs: '{"font":16}' }Robust Parser With Edge Cases
function parseRobust(cookieString = document.cookie) {
const cookies = new Map();
if (!cookieString || cookieString.trim() === "") {
return cookies;
}
// Split on "; " but handle malformed strings
const pairs = cookieString.split(/;\s*/);
for (const pair of pairs) {
if (!pair) continue;
const eqIndex = pair.indexOf("=");
if (eqIndex === -1) {
// Cookie with no value
cookies.set(pair.trim(), "");
continue;
}
const name = pair.slice(0, eqIndex).trim();
let value = pair.slice(eqIndex + 1).trim();
// Remove surrounding quotes if present
if (value.startsWith('"') && value.endsWith('"')) {
value = value.slice(1, -1);
}
try {
cookies.set(decodeURIComponent(name), decodeURIComponent(value));
} catch {
// Malformed URI encoding, store raw
cookies.set(name, value);
}
}
return cookies;
}
const cookieMap = parseRobust();
console.log(cookieMap.get("theme")); // "dark"
console.log(cookieMap.has("username")); // trueExtracting a Single Cookie
By Name Lookup
function getCookie(name) {
const encoded = encodeURIComponent(name);
const pairs = document.cookie.split("; ");
for (const pair of pairs) {
const eqIndex = pair.indexOf("=");
const key = eqIndex === -1 ? pair : pair.slice(0, eqIndex);
if (key === encoded || decodeURIComponent(key) === name) {
return eqIndex === -1
? ""
: decodeURIComponent(pair.slice(eqIndex + 1));
}
}
return null;
}
console.log(getCookie("theme")); // "dark"
console.log(getCookie("missing")); // nullRegex-Based Extraction
function getCookieRegex(name) {
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const match = document.cookie.match(
new RegExp(`(?:^|;\\s*)${escaped}=([^;]*)`)
);
if (!match) return null;
return decodeURIComponent(match[1]);
}
console.log(getCookieRegex("username")); // "parth"Typed Cookie Getters
function getCookieAsNumber(name, fallback = 0) {
const value = getCookie(name);
if (value === null) return fallback;
const num = Number(value);
return Number.isNaN(num) ? fallback : num;
}
function getCookieAsBoolean(name, fallback = false) {
const value = getCookie(name);
if (value === null) return fallback;
return value === "true" || value === "1";
}
function getCookieAsJSON(name, fallback = null) {
const value = getCookie(name);
if (value === null) return fallback;
try {
return JSON.parse(value);
} catch {
return fallback;
}
}
// Usage
const fontSize = getCookieAsNumber("fontSize", 16);
const darkMode = getCookieAsBoolean("darkMode", false);
const prefs = getCookieAsJSON("prefs", { sidebar: true });Deleting Cookies
Basic Deletion
function deleteCookie(name, path = "/") {
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=${path}`;
}
deleteCookie("theme");Deletion With All Matching Attributes
function deleteCookieFull(name, options = {}) {
const parts = [`${encodeURIComponent(name)}=`, "max-age=0"];
// Must match the original path
parts.push(`path=${options.path || "/"}`);
// Must match the original domain
if (options.domain) {
parts.push(`domain=${options.domain}`);
}
if (options.secure) {
parts.push("secure");
}
if (options.sameSite) {
parts.push(`samesite=${options.sameSite}`);
}
document.cookie = parts.join("; ");
}
// Delete a cookie that was set on a specific domain
deleteCookieFull("tracking", {
path: "/",
domain: ".example.com",
secure: true,
sameSite: "none",
});Why Deletion Fails
| Reason | Explanation | Fix |
|---|---|---|
| Wrong path | Cookie was set with path=/app but you deleted with path=/ | Match the original path |
| Wrong domain | Cookie was set with domain=.example.com | Specify the same domain |
| HttpOnly cookie | Cannot be accessed or deleted via JS | Must delete server-side |
| Secure on HTTP | Secure cookies require HTTPS | Use HTTPS or remove Secure flag |
Bulk Cookie Operations
function deleteAllCookies(path = "/") {
const cookies = parseCookies();
for (const name of Object.keys(cookies)) {
deleteCookie(name, path);
}
return Object.keys(cookies).length;
}
function deleteByPrefix(prefix, path = "/") {
const cookies = parseCookies();
let count = 0;
for (const name of Object.keys(cookies)) {
if (name.startsWith(prefix)) {
deleteCookie(name, path);
count++;
}
}
return count;
}
function deleteByPattern(pattern, path = "/") {
const cookies = parseCookies();
const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern);
let count = 0;
for (const name of Object.keys(cookies)) {
if (regex.test(name)) {
deleteCookie(name, path);
count++;
}
}
return count;
}
// Delete all cookies
const deleted = deleteAllCookies();
console.log(`Deleted ${deleted} cookies`);
// Delete all analytics cookies
deleteByPrefix("_ga");
// Delete cookies matching a pattern
deleteByPattern(/^(utm_|_ga|_gid)/);Cookie Parser Class
class CookieParser {
constructor() {
this.cache = null;
this.cacheSource = null;
}
parse(cookieString = document.cookie) {
// Cache parsed result if source string hasn't changed
if (cookieString === this.cacheSource && this.cache) {
return this.cache;
}
const result = {};
if (!cookieString) {
this.cache = result;
this.cacheSource = cookieString;
return result;
}
const pairs = cookieString.split(/;\s*/);
for (const pair of pairs) {
const eqIndex = pair.indexOf("=");
if (eqIndex === -1) continue;
const name = pair.slice(0, eqIndex).trim();
let value = pair.slice(eqIndex + 1).trim();
if (value.startsWith('"') && value.endsWith('"')) {
value = value.slice(1, -1);
}
try {
result[decodeURIComponent(name)] = decodeURIComponent(value);
} catch {
result[name] = value;
}
}
this.cache = result;
this.cacheSource = cookieString;
return result;
}
get(name) {
return this.parse()[name] ?? null;
}
has(name) {
return name in this.parse();
}
names() {
return Object.keys(this.parse());
}
values() {
return Object.values(this.parse());
}
entries() {
return Object.entries(this.parse());
}
count() {
return Object.keys(this.parse()).length;
}
invalidateCache() {
this.cache = null;
this.cacheSource = null;
}
toJSON() {
return this.parse();
}
toString() {
return document.cookie;
}
}
// Usage
const parser = new CookieParser();
console.log(parser.get("theme")); // "dark"
console.log(parser.has("username")); // true
console.log(parser.names()); // ["username", "theme", "lang"]
console.log(parser.count()); // 3
// After setting a new cookie, invalidate cache
document.cookie = "newCookie=value; path=/";
parser.invalidateCache();
console.log(parser.count()); // 4Cookie Consent Helper
class CookieConsent {
constructor(consentCookieName = "cookie_consent") {
this.consentKey = consentCookieName;
this.categories = ["necessary", "analytics", "marketing", "preferences"];
}
getConsent() {
const raw = getCookie(this.consentKey);
if (!raw) return null;
try {
return JSON.parse(raw);
} catch {
return null;
}
}
setConsent(categories) {
const consent = {
categories,
timestamp: new Date().toISOString(),
version: "1.0",
};
document.cookie = [
`${this.consentKey}=${encodeURIComponent(JSON.stringify(consent))}`,
`max-age=${365 * 86400}`,
"path=/",
"samesite=lax",
"secure",
].join("; ");
// Remove cookies for denied categories
this.enforceDenials(categories);
}
hasConsent(category) {
const consent = this.getConsent();
if (!consent) return category === "necessary";
return consent.categories.includes(category);
}
enforceDenials(allowed) {
const denied = this.categories.filter((c) => !allowed.includes(c));
const cookieCategoryMap = {
analytics: /^(_ga|_gid|_gat|__utm)/,
marketing: /^(_fbp|_fbc|fr|__adroll)/,
preferences: /^(lang|theme|sidebar)/,
};
for (const category of denied) {
const pattern = cookieCategoryMap[category];
if (pattern) {
deleteByPattern(pattern);
}
}
}
revokeAll() {
this.setConsent(["necessary"]);
}
}
const consent = new CookieConsent();
consent.setConsent(["necessary", "preferences"]);
console.log(consent.hasConsent("analytics")); // falseRune AI
Key Insights
- Split on "; " then on first "=": Cookie values can contain
=characters; always split on the first occurrence only - Always decode with decodeURIComponent: Cookie names and values may be percent-encoded; wrap decoding in try/catch for malformed strings
- Match path and domain when deleting: The browser identifies cookies by name + path + domain; mismatched attributes create new entries instead of removing existing ones
- HttpOnly cookies are invisible to JS: They do not appear in
document.cookieand cannot be deleted client-side; manage them server-side only - Cache parsed results: Parsing
document.cookieon every access is wasteful; cache the result and invalidate when cookies change
Frequently Asked Questions
Why does document.cookie not show all my cookies?
How do I parse cookies from a Set-Cookie header in Node.js?
Can I detect when a cookie has expired?
Why does deleting a cookie sometimes not work?
How do I delete all cookies for the current site?
Conclusion
Robust cookie parsing requires handling URL encoding, quoted values, missing values, and malformed strings. Cookie deletion demands matching the original path and domain attributes. Build utility classes like CookieParser and CookieConsent to encapsulate complexity. For setting cookies with proper attributes, see how to manage cookies in JS complete tutorial. For client-only storage alternatives, see JS localStorage API guide and JS sessionStorage API guide.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.