In short
JavaScript cookies are small pieces of text a website stores in the browser and sends to the server with every request. Learn how to create, read and delete cookies with document.cookie, set expiry, path and SameSite, and when to use localStorage instead. What are cookies?
JavaScript cookies are small pieces of text a website stores in the browser and sends to the server with every request. Learn how to create, read and delete cookies with document.cookie, set expiry, path and SameSite, and when to use localStorage instead.
What are cookies?
A cookie is a small piece of text (up to about 4 KB) that a website saves in your browser, as a name=value pair. The special thing about cookies is that the browser sends them back to the server automatically with every request to that site. That is how a website "remembers" you are logged in when you move from page to page.
A real-life comparison: a cookie is like the cloakroom ticket you get at a theatre. You show it every time you come back, and the staff know which coat is yours.
Cookies are used for:
- Sessions: keeping you logged in, remembering your shopping cart.
- Preferences: language, theme, "don't show this banner again".
- Tracking: analytics and advertising (this is where privacy rules apply).
How to create a cookie with document.cookie
In JavaScript, cookies live in document.cookie. It is a strange property: when you assign to it, you add or update one cookie, not replace them all.
document.cookie = "theme=dark";
document.cookie = "language=en";
console.log(document.cookie);
// Output: theme=dark; language=en
Even though we assigned twice, both cookies are kept. Reading document.cookie gives one string with all cookies for this page, separated by "; ". Without any extra settings, these are session cookies: they disappear when the browser is closed.
Cookie values must not contain ;, , or spaces safely, so wrap any user text with encodeURIComponent():
const city = "São Paulo; Brazil";
document.cookie = `city=${encodeURIComponent(city)}`;
console.log(document.cookie);
// Output: theme=dark; language=en; city=S%C3%A3o%20Paulo%3B%20Brazil
Note: Run these examples on a real web page served over
http://orhttps://(for examplehttp://localhost). Cookies are not saved on pages opened directly from a file (file://) in most browsers.
Cookie attributes: expires, max-age, path, SameSite and Secure
After the name=value part you can add attributes, separated by ;. They tell the browser how long to keep the cookie and when to send it.
| Attribute | Example | What it does |
|---|---|---|
max-age | max-age=86400 | Keep for this many seconds (86400 = 1 day) |
expires | expires=Fri, 31 Dec 2027 23:59:59 GMT | Keep until this date (UTC string) |
path | path=/ | Which pages can see the cookie; / means the whole site |
domain | domain=example.com | Share with subdomains like shop.example.com |
SameSite | SameSite=Lax | Whether the cookie is sent from other sites (Strict, Lax, None) |
Secure | Secure | Only send over HTTPS |
HttpOnly | (server only) | JavaScript cannot read the cookie at all |
// Remember the theme for 30 days on the whole site
const thirtyDays = 60 * 60 * 24 * 30;
document.cookie = `theme=dark; max-age=${thirtyDays}; path=/; SameSite=Lax; Secure`;
// The same with expires and a Date
const expiryDate = new Date(Date.now() + thirtyDays * 1000);
document.cookie = `theme=dark; expires=${expiryDate.toUTCString()}; path=/; SameSite=Lax; Secure`;
console.log(document.cookie);
// Output (example): theme=dark
Reading document.cookie only ever shows name=value pairs. The attributes are stored by the browser but never returned to JavaScript. max-age is simpler than expires because you do not need a date; if both are given, max-age wins.
A few rules worth knowing:
- SameSite=Lax is the default in modern browsers: the cookie is sent when the user clicks a link to your site, but not with hidden requests from other sites. This protects against an attack called CSRF.
SameSite=Nonemust always come withSecure. - Secure cookies are only saved and sent on HTTPS pages (browsers treat
localhostas secure too). - HttpOnly can only be set by the server with a
Set-Cookieheader. JavaScript cannot create, read or delete such cookies. This is exactly why login cookies should beHttpOnly: even if an attacker injects a script, they cannot steal the session.
Common mistake: Setting a cookie with
path=/and trying to delete it withoutpath=/. A cookie is identified by its name plus its path and domain. To update or delete it, you must use the same path and domain as when you created it.
Helper functions to set, get and delete cookies
Working with that one long string is clumsy, so most projects use three small helper functions:
function setCookie(name, value, days = 7) {
const maxAge = days * 24 * 60 * 60;
document.cookie =
`${encodeURIComponent(name)}=${encodeURIComponent(value)}; ` +
`max-age=${maxAge}; path=/; SameSite=Lax`;
}
function getCookie(name) {
const cookies = document.cookie ? document.cookie.split("; ") : [];
for (const cookie of cookies) {
const [key, ...rest] = cookie.split("=");
if (decodeURIComponent(key) === name) {
return decodeURIComponent(rest.join("="));
}
}
return null; // not found
}
function deleteCookie(name) {
// A max-age of 0 tells the browser to remove it now
document.cookie = `${encodeURIComponent(name)}=; max-age=0; path=/; SameSite=Lax`;
}
setCookie("username", "Maya Lopez", 30);
console.log(getCookie("username")); // Output: Maya Lopez
console.log(getCookie("nothing")); // Output: null
deleteCookie("username");
console.log(getCookie("username")); // Output: null
setCookie encodes the name and value and saves the cookie for a number of days. getCookie splits the string into "name=value" pieces, splits each piece at the first = (the ...rest part keeps any = signs inside the value), and returns the matching value or null. deleteCookie overwrites the cookie with an empty value and max-age=0, which tells the browser to throw it away. You can check the results in DevTools under Application (Chrome, Edge) or Storage (Firefox), in the Cookies section.
Here is a practical use, a "dismiss banner" that stays hidden for 90 days:
<!DOCTYPE html>
<html lang="en">
<body>
<div id="banner" style="background: #fff3cd; padding: 12px;">
New: free delivery on orders over €30!
<button id="closeBanner">Close</button>
</div>
<script>
const getCookie = (name) =>
document.cookie.split("; ").find((c) => c.startsWith(name + "="))?.split("=")[1] ?? null;
const banner = document.querySelector("#banner");
if (getCookie("bannerClosed") === "yes") {
banner.hidden = true;
}
document.querySelector("#closeBanner").addEventListener("click", () => {
banner.hidden = true;
document.cookie = `bannerClosed=yes; max-age=${60 * 60 * 24 * 90}; path=/; SameSite=Lax`;
});
</script>
</body>
</html>
Open the page (on http://localhost), close the banner and reload: it stays hidden. Delete the cookie in DevTools and reload: it comes back. The short getCookie arrow function uses optional chaining ?. so it returns null safely when the cookie is missing.
Cookies vs localStorage: which should you use?
You learned about localStorage in the Saving Data lesson. Both store small strings in the browser, but they solve different problems:
| Cookies | localStorage | |
|---|---|---|
| Size limit | About 4 KB per cookie | About 5 MB per site |
| Sent to the server? | Yes, with every request | No, stays in the browser |
| Expiry | You choose (max-age / expires) or end of session | Never, until deleted |
| Readable by JavaScript? | Yes, unless HttpOnly | Always |
| API | One awkward string (document.cookie) | Simple methods (setItem, getItem) |
| Best for | Logins and data the server needs | Preferences and data only your page needs |
A simple rule: if the server needs the value on every request (like a session ID), use a cookie, ideally an HttpOnly one set by the server. If only your JavaScript needs it (like a theme or a draft), use localStorage: it is bigger, easier and does not slow down every request.
Privacy, consent and cookie banners
Cookies can be used to follow people across websites, so many laws regulate them. In the European Union and the UK, for example, rules like the GDPR and ePrivacy laws say you must ask for consent before setting cookies that are not strictly necessary, such as analytics or advertising cookies. Cookies that the site truly needs to work, like a login session or a shopping cart, usually do not need consent. Similar laws exist in other places too.
Tip: Store as little as possible, never put passwords or personal details in a cookie, and do not load analytics or ad scripts until the user has said yes. If you are building a real business site, check the rules that apply in your country.
Practice exercise
Build a "visit counter" that uses cookies. When the page loads, read a cookie named visits with your getCookie helper, turn it into a number (default 0), add 1, save it back for 365 days with setCookie, and show "You have visited this page 5 times". Add a "Reset" button that calls deleteCookie("visits") and updates the text.
Hint: use Number(getCookie("visits") ?? 0) + 1, and remember to serve the page from http://localhost so the cookie is saved.
Key takeaways
- Cookies are small
name=valuestrings that the browser sends to the server with every request. - Assigning to
document.cookieadds or updates one cookie; reading it returns all of them as one string. - Use
max-ageorexpiresfor lifetime,path=/for the whole site,SameSite=LaxandSecurefor safety;HttpOnlycan only be set by the server. - Delete a cookie by setting
max-age=0with the same name, path and domain. - Use cookies for data the server needs,
localStoragefor data only your page needs, and ask for consent before non-essential cookies.