Tags: web-dev analytics concept
Cookies
Date: 2026-08-16
A small string the browser stores and sends back on every matching request. The attributes decide who can read it, how long it survives, and whether it works cross-site — and getting them wrong is either a security hole or a broken checkout.
What it is
A cookie is a name-value pair stored by the browser and attached automatically to subsequent HTTP requests matching its domain and path.
The automatic attachment is the whole point and the whole problem: it’s what makes sessions work without any application code, and it’s what makes cross-site request forgery possible.
server → browser Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
browser → server Cookie: session=abc123 (on every matching request)
The attributes
| Attribute | Does | Get it wrong and |
|---|---|---|
Expires / Max-Age | Sets lifetime. Absent → session cookie, deleted on browser close | Users are logged out, or logged in forever |
Domain | Which hosts receive it. example.com includes subdomains | Leaks to every subdomain including third-party-hosted ones |
Path | Which paths receive it | Rarely useful; not a security boundary |
Secure | HTTPS only | Sent in clear over HTTP |
HttpOnly | Invisible to document.cookie | Any XSS on your site steals the session |
SameSite | Cross-site sending behaviour | See below |
Partitioned | Separate jar per top-level site (CHIPS) | Embedded third-party contexts break |
HttpOnly and Secure on any session cookie, always. A session cookie readable by JavaScript turns a single XSS bug into full account takeover.
SameSite
The attribute that breaks things when changed, and the one worth understanding properly.
| Value | Sent on cross-site requests? |
|---|---|
Strict | Never — including when following a link from another site |
Lax | Only on top-level navigations using GET |
None | Always. Requires Secure |
Strict on a session cookie means a user arriving from a Google result appears logged out, then logged in after any internal navigation — a confusing bug that reads as a session problem. Lax is the sensible default for sessions.
None is required for genuine cross-site use — embedded widgets, payment iframes, third-party analytics. Since it must be paired with Secure, and browsers are increasingly restricting third-party cookies regardless, it’s a diminishing option. See Browser Privacy Restrictions.
First-party and third-party
The distinction is about context, not who set it:
- First-party — the cookie’s domain matches the site in the address bar
- Third-party — it doesn’t. An analytics or ad cookie read while you’re on someone else’s site
The same cookie can be either, depending on where the user currently is. This is the mechanism behind cross-site tracking, and therefore the thing every browser privacy change has targeted.
Limits worth knowing
- ~4KB per cookie, and browsers cap the number per domain. Exceeding it silently drops cookies rather than erroring
- Sent on every matching request. A page with 30 subresources on your domain sends the whole cookie payload 30 times. Large cookies are a real upload cost on mobile — this is a good reason to keep application state in Client Storage instead
- No cookie is set for
localhostwithSecurein some configurations, which is a recurring development-only confusion
Setting them
Server-side, in a response header:
Set-Cookie: id=abc; Max-Age=31536000; Secure;
HttpOnly; SameSite=LaxClient-side, in JavaScript:
document.cookie =
"pref=dark; max-age=31536000; path=/; SameSite=Lax"These are not equivalent in lifetime. Safari’s tracking prevention caps cookies set via document.cookie at seven days, while server-set cookies keep the expiry the server gave them. That single difference is why analytics tools increasingly recommend server-side cookie setting — see Browser Privacy Restrictions.
Practical
- Sessions:
HttpOnly; Secure; SameSite=Lax, server-set - Analytics identifiers: server-set where you can, for lifetime rather than security
- Consent state: first-party, long-lived, and readable by JavaScript so the tag layer can gate on it — Consent Management
- Never put personal data in a cookie. It travels on every request and is readable by anything with access to the domain — PII in Analytics
- Audit what’s set. DevTools → Application → Cookies. Most retail sites carry cookies nobody can identify the owner of, which is both a performance cost and a compliance problem