completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Cookies

Learn how browser cookies store small values, travel with requests, and use attributes like Expires, Max-Age, SameSite, Secure, and HttpOnly.

By the end, you’ll be able to
  • 01
    Read and write cookies safelyWrite, change, and delete a cookie with document.cookie, encode its value, and read it back without mixing up the value and its rules.
  • 02
    Choose the right rulesSay what Max-Age, Expires, Path, Domain, SameSite, Secure, and HttpOnly each do, and when you need them.
  • 03
    Pick the right place for dataDecide whether a piece of data belongs in a cookie, in localStorage, or nowhere in the browser.

Cookies in one minute

A cookie is a small piece of text that the browser saves for one website. It has a name and a value, written like theme=dark.

A few words first. A server is the computer that sends you a website. A request is a message the browser sends to a server, for example to get a page or an image. A header is a short line of extra information on a request or on the server's answer.

Here is what makes cookies special. The browser sends a saved cookie back to its website by itself, on every request that matches the cookie's rules. You don't write any code for that. Sites use this for:

  • remembering that you are signed in,
  • remembering your language,
  • remembering whether you said yes to tracking.

Because cookies travel with requests, keep them small. Browsers allow about 4 KB (about 4,000 characters) per cookie, and the exact limit changes from browser to browser. Cookies are for short values, not for big data.

Real-life analogyA cookie is like a hand stamp at an event

At an event, staff stamp your hand once. When you come back in, they look at the stamp. A cookie works the same way. The server gives the browser a value once. The browser shows that value again on later requests.

In real life: Staff stamp your hand at the door
In JavaScript: The server sends Set-Cookie: session=abc
In real life: The stamp stays on your hand
In JavaScript: The browser saves the cookie
In real life: You show the stamp when you come back in
In JavaScript: The browser sends Cookie: session=abc with matching requests
In real life: Staff see the stamp and let you in
In JavaScript: The server knows your browser again
Left: a window called browser that stores a card, session=abc. Right: a window called server. Arrow 1, Set-Cookie, goes from the server to the browser. Arrow 2, Cookie, goes from the browser back to the server on the next request.browsersession=abcstoredserverknows yourbrowser again1. Set-Cookie2. Cookie
1. The server sends the cookie once, in a Set-Cookie header. 2. The browser stores it and sends it back in a Cookie header on later requests to that site.

The table below lists four words you will meet in every section. Each row names one idea, says what it is, and says why it matters.

Four cookie ideas used in this lesson
IdeaWhat it isWhy it matters
ValueThe name=value text, like theme=dark.This is the part JavaScript can read, unless the cookie is HttpOnly.
AttributesRules written after the value, like Max-Age, Path, SameSite, and Secure.They decide how long the cookie lasts and when it is sent. You can't read them back with document.cookie.
Sent by itselfThe browser adds matching cookies to requests without your code.Good for staying signed in. Bad for big data, which would travel every time.
Who can read itPage JavaScript can read normal cookies. It can't read HttpOnly cookies.Never put a secret in a cookie that JavaScript can read.

A cookie's lifetime is one of its rules. This code writes the same cookie two ways: one with an end date, one with a number of seconds.

Two ways to say how long a cookie lastsPop out in the code editor (opens in a new tab)JavaScript
const expires = new Date("2030-01-01T00:00:00Z").toUTCString();
const byDate = "session=short; Expires=" + expires + "; Path=/";
const bySeconds = "session=short; Max-Age=3600; Path=/";

console.log(byDate.includes("Expires="));
console.log(bySeconds.includes("Max-Age=3600"));

Line 2 uses Expires= with a date. Line 3 uses Max-Age=3600, which means 3,600 seconds (one hour) from now. Lines 5 and 6 both print true, because each string contains the rule we checked for. You will learn both rules in the lifetime section.

In the rest of this lesson you will write real test cookies on this site, read them back, try the SameSite rules, and learn when a cookie is the wrong place for your data.

Expires and Max-Age: how long a cookie lasts

LIFETIME

A cookie with no Expires and no Max-Age is a session cookie. The browser may throw it away when you close the browser. To choose the lifetime yourself, add one of these rules. Each row of the table is one rule, with an example and what it does.

Rules that set how long a cookie lasts
RuleExampleWhat it does
Max-AgeMax-Age=3600The cookie lasts 3,600 seconds from now. If a cookie has both rules, this one wins.
ExpiresExpires=Wed, 21 Oct 2030 07:28:00 GMTThe cookie lasts until that exact date and time.
DeleteMax-Age=0Write the same cookie again with zero seconds left. The browser removes it.

For Expires, the date must be in the format the web uses. date.toUTCString() gives you that format. If dates feel shaky, look back at the Date and time lesson. In most app code, Max-Age is easier, because it is just a number of seconds.

To delete a cookie, repeat its Path and Domain

Path says which pages of the site get the cookie, like /app. Domain says which web addresses get it. Two cookies can share a name if their Path or Domain is different. So a cookie for /app is not the same cookie as one for /. To delete one, write the same name, the same Path and Domain, and Max-Age=0.

Deleting with the wrong path misses the cookiePop out in the code editor (opens in a new tab)JavaScript
const appCookie = "theme=dark; Path=/app";
const deleteRoot = "theme=; Max-Age=0; Path=/";
const deleteApp = "theme=; Max-Age=0; Path=/app";

console.log(appCookie.includes("Path=/app"));
console.log(deleteRoot === deleteApp);

Line 1 is a cookie made for Path=/app. Lines 2 and 3 are two delete writes. They differ only in the path, but they point at different cookies. Line 6 prints false: the two writes are not the same. Only line 3 removes the /app cookie. In a real app, keep the code that creates a cookie next to the code that deletes it, so both use the same path.

Real-life analogyCookie rules are like the rules printed on a hand stamp

A hand stamp can say "today only" or "main hall only". Cookie rules do the same job. They decide when and where the browser may use the value.

In real life: Good for today only
In JavaScript: Expires or Max-Age
In real life: Good only in one hall
In JavaScript: Path and Domain
In real life: Checked only at the guarded door
In JavaScript: Secure
In real life: Visitors can't see it, only staff
In JavaScript: HttpOnly

SameSite: when another site starts the request

SIMULATOR

Two pages are on the same site when they share the main web address, like www.example.com and shop.example.com. A request is cross-site when a page on a different site starts it, for example a link or a form on other.com that goes to example.com.

SameSite is a rule that says whether the browser sends the cookie on cross-site requests. It helps stop CSRF (cross-site request forgery). In CSRF, a bad site tries to make your browser send a request to a site where you are signed in. If your sign-in cookie goes along, the request looks like it came from you.

SameSite has three values:

  • Strict: send the cookie only on same-site requests.
  • Lax: send it on same-site requests, and also when you follow a normal link from another site. A normal link is a GET request that opens a whole new page. If a cookie has no SameSite rule, most browsers today treat it like Lax.
  • None: send it on cross-site requests too. Browsers require Secure with it. Browsers may still block it in some cases, as you'll see below.
Left: another site has a normal link to your site. The SameSite=Lax cookie is sent. Right: another site submits a POST form to your site. The SameSite=Lax cookie is blocked.link (GET)from another siteSameSite=Laxsentform (POST)from another siteSameSite=Laxblocked
Both requests start on another site. With SameSite=Lax, the browser sends the cookie when you follow a normal link, but not with a POST form.
The browser decides whether a cookie goes with a cross-site requestPop out in the code editor (opens in a new tab)JavaScript
const requestCookie = "session=abc123";
const requestType = "cross-site image";

console.log(requestType + ": " + requestCookie);
console.log("Browser policy still decides whether it is sent");

This code only prints two lines. It shows the situation: an image from another site, and a cookie that could go with it. Whether the cookie is really sent is up to the browser, not your code.

A third-party cookie is a cookie for a site other than the one in the address bar. For example, a page on news.com shows an image from ads.com, and the request for the image carries an ads.com cookie. Browsers block or limit these more and more, mostly to stop tracking. SameSite=None; Secure is needed to allow them, but it does not promise that every browser will send the cookie.

SameSite simulator
ResultCookie blocked
SameSiteLax
RequestA POST form on another site
Try it yourself

Blocked. Lax keeps the cookie off POST forms, iframes, images, and fetch calls from another site. This helps stop CSRF.

A simple copy of the usual SameSite rules. Real browsers also block many third-party cookies, so a tracking cookie may be blocked even when this says sent.

Secure and HttpOnly: how a cookie travels and who can read it

SAFETY

Secure and HttpOnly do two different jobs:

  • Secure: the browser sends the cookie only over HTTPS, the locked, encrypted kind of web address. Some browsers make an exception for localhost while you test, so in real apps think of Secure as "HTTPS only".
  • HttpOnly: page JavaScript cannot read the cookie at all. It is still sent with requests.

A server sets these rules with a Set-Cookie header, one header per cookie. Here are two:

Two cookies set by the serverHTTP
Set-Cookie: session=abc123; Path=/; HttpOnly; Secure; SameSite=LaxSet-Cookie: widget_id=public; Path=/; Secure; SameSite=None

Line 1 is a sign-in cookie, session. It has HttpOnly, so scripts can't read it. Line 2, widget_id, has no HttpOnly, so scripts can read it. It also has SameSite=None, so it can go with cross-site requests.

Left: the browser stores two cookies. session=abc123 has HttpOnly. widget_id=public has no HttpOnly. An arrow goes from widget_id=public to a window called page script, where document.cookie shows only widget_id=public. The session cookie is hidden.stored by the browsersession=abc123HttpOnlywidget_id=publicno HttpOnlypage scriptdocument.cookiewidget_id=publicsession: hidden
The browser stores both cookies from the two headers. Page JavaScript sees only widget_id. The HttpOnly session cookie is hidden from it.
JavaScript cannot create an HttpOnly cookie

Only a server can set HttpOnly. If you write document.cookie = "session=abc; HttpOnly", you don't get a hidden cookie. Send sign-in tokens from the server with a Set-Cookie header. Never put a secret in a cookie that JavaScript can read.

That is why sign-in cookies are usually set by the server, not by page code. With HttpOnly; Secure; SameSite=Lax, the browser keeps sending the sign-in cookie, and page scripts can't read it.

Where you'll use cookies

SORTER

To decide, ask one question: does the server need this small value with each request?

  • If yes, a cookie may fit.
  • If only your JavaScript needs it, localStorage or sessionStorage (the next lesson) is often better.
  • If the value is a real secret, keep it out of the browser.
A cookie that remembers the themePop out in the code editor (opens in a new tab)JavaScript
const themeCookie = "theme=" + encodeURIComponent("dark")
  + "; Max-Age=31536000; Path=/; SameSite=Lax";

console.log(themeCookie);
// In a browser page: document.cookie = themeCookie;

A theme (light or dark colors) is a good cookie when the server must pick the colors for the very first page, before your JavaScript runs. The rules in this cookie:

  • Max-Age=31536000 keeps it for one year, written in seconds.
  • Path=/ sends it to every page of the site.
  • SameSite=Lax keeps it off most cross-site requests.

If only your JavaScript reads the theme after the page loads, use localStorage instead. Then the theme is not sent with every request.

Every request carries the cookies

Matching cookies go with every request, not just page requests. Images, scripts, and style files carry them too. So keep a cookie to a short ID or a small yes/no flag. About 4 KB per cookie is a common limit, but it changes from browser to browser, and all the headers of one request together have a limit too.

Cookie, localStorage, or neither?
  • A session ID that shows who is signed in
  • A dark mode choice used only after the page loads
  • A secret API key for a paid service
  • The user's yes or no to tracking, which the server must follow
  • A large shopping cart with many product details
  • A secret key the server uses to sign CSRF tokens
Try it yourself
0 of 6 correct

Drag each piece of data to the safest place to keep it.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common misconceptions

Most cookie bugs mix up the value, the rules, and the headers
  • "Writing to document.cookie replaces all cookies." It writes one cookie. The others stay.
  • "I can read the rules later." A read shows only name=value pairs, never rules like Path.
  • "Setting an empty value deletes a cookie." An empty value is still a cookie. Delete it with Max-Age=0 or an Expires date in the past.
  • "Secure hides a cookie from JavaScript." HttpOnly hides it. Secure only means "send over HTTPS".
  • "SameSite is all the CSRF protection I need." It helps a lot, but real apps also check requests on the server, for example with special tokens.
  • "Cookies are a good place for secrets." Only a server-set HttpOnly cookie should hold a sign-in token. Never keep secret API keys anywhere the browser can read.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the decoded value

Read the starter code. Object.fromEntries turns a list of [name, value] pairs into an object. What exact text does the code print?

Starter codePop out in the code editor (opens in a new tab)JavaScript
const raw = "cf_demo_theme=dark; cf_demo_name=Ada%20Lovelace";
const cookies = Object.fromEntries(
  raw.split("; ").map((pair) => pair.split("=").map(decodeURIComponent))
);
console.log(cookies.cf_demo_name);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeWrite the delete string

    Which rule, written as name=value, goes into the write that deletes this cookie?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    document.cookie = "cf_demo_theme=dark; Path=/";
    // Now delete the same cookie.

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind the bug: a sign-in token set from JavaScript

      This app saves a sign-in token from JavaScript. Explain what is wrong. Then write the safer Set-Cookie header the server should send.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      document.cookie = "token=secret.jwt.value; Max-Age=3600; Path=/; Secure";
        Exercise 4 · PracticeSameSite prediction

        A different site sends a POST form to your app. Your sign-in cookie has SameSite=Lax. Is the cookie sent or blocked?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        // Cross-site POST form with SameSite=Lax
        console.log("blocked");

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeChoose where to keep a theme

          Your server shows the first page in dark colors before any of your JavaScript runs. Pick a cookie or localStorage for the theme, and say why.

            Check your understanding

            7 QUESTIONS
            Cookies quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does writing to document.cookie do?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const raw = "theme=dark; name=Ada%20Lovelace";
              const pairs = raw.split("; ").map((pair) => pair.split("="));
              console.log(decodeURIComponent(pairs[1][1]));

              Choose an answer to see the explanation.

            3. Question 3 of 7A cookie has both Expires and Max-Age. Which one wins?

              Choose an answer to see the explanation.

            4. Question 4 of 7A POST form on another site sends a request to your site. Which SameSite value lets the cookie go along?

              Choose an answer to see the explanation.

            5. Question 5 of 7Which cookie rule stops JavaScript from reading the cookie?

              Choose an answer to see the explanation.

            6. Question 6 of 7This code acts out a cookie read: it keeps only the text before the first semicolon. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const write = "theme=dark; Max-Age=3600; Path=/; SameSite=Lax";
              const readable = write.split(";")[0];
              console.log(readable);

              Choose an answer to see the explanation.

            7. Question 7 of 7When is the Cookie Store API a better fit than document.cookie?

              Choose an answer to see the explanation.

            Key takeaways

            • A cookie is a small name=value text that the browser saves and sends back to its site.
            • Reading document.cookie gives all readable cookies as one string. Writing to it sets one cookie.
            • Max-Age wins over Expires. To delete, write the cookie again with Max-Age=0 and the same name, path, and domain.
            • SameSite decides whether the cookie goes with cross-site requests. None needs Secure.
            • Secure means "send over HTTPS only". HttpOnly means "JavaScript can't read it".
            • Check that the Cookie Store API exists before you use it, and keep a backup.

            Final definition: a cookie is a small piece of text the browser saves for a site and sends back with matching requests. Its rules decide how long it lasts, where it goes, and who can read it. JavaScript can set some rules; only the server can set all of them.

            Up next: localStorage and sessionStorage.

            CompleteFrontend Clear concepts. Working examples.