What is document.cookie?
I’ve used cookies as a web developer for many years,
but never understood them in detail.
In this post, I look at the
Cookies are client-side storage.
Cookies were the first client-side storage available in the browser.
They have three main use-cases:
sessions, preferences, and tracking.
Nowadays, there are three more client-side storage APIs:
Arguably, cookies are obsoleted by these newer APIs,
but you still need to know about cookies,
because they won’t go away any time soon!
You can view cookies for this website, jameshfisher.com, in Google Chrome by opening:
Developer tools > Application > Storage > Cookies >
There, you’ll see two or three cookies.
Cookies have a bunch of standard attributes.
A fundamental one is the name.
You’ll see cookies on this page called
These cookies were set by Google Analytics,
which I use to track visitors to this website.
Many sites use Google Analytics,
and if you view the cookies on those sites,
you’ll also see
they are standard names used by Google.
> document.cookie "_ga=GA1.2.12345.67890; _gid=GA1.2.111111.222222"
Rather oddly, the cookies come back as a string! The form is roughly as follows. We’ll revisit this when we look at how cookies are transferred over HTTP.
cookieString ::= cookie [ "; " cookieString ] cookie ::= name "=" value
You can set some cookies yourself!
From the console, assign a new cookie to
which sets the cookie
bgcolor to the value
> document.cookie = "bgcolor=mintcream"; > document.cookie "_ga=GA1.2.12345.67890; _gid=GA1.2.111111.222222; bgcolor=mintcream"
Yes, this API is pretty weird!
Formatted strings as arguments,
formatted strings as return values,
and a horrible abuse of assignment.
The reasons are lost to the dark ages of the browser.
Google seem to be designing a better replacement API,
but it’s early days, so we’re stuck with
Assigning to cookies is not much use unless we can access them.
Let’s say we want to use the value of
bgcolor to style the page.
To do so, we have to parse out the cookie and extract the value,
> document.body.style.backgroundColor = document.cookie.split(';').filter(c => c.startsWith(' bgcolor=')).split('=')
If you think this API is bad so far, just wait: it only gets worse from here!
Your browser stores lots of cookies. but in each tab, only some of those cookies are used. On this page, only two or three cookies are used. Two cookie attributes determine whether the cookie is used: the cookie’s domain and the cookie’s path. Together, the domain and path are called the cookie’s “scope”.
For the Google Analytics cookies,
the domain value is
and the path value is
The cookie’s domain and path are matched against the full URL of this page,
The cookie’s domain
.jameshfisher.com matches the URL’s domain
and the cookie’s path
/ matches the URL’s path
so the cookie is used on this page.
The cookie’s domain
.jameshfisher.com is really a domain suffix:
it matches the domain
or any subdomains such as
And the cookie’s path
/ is really a path prefix:
it matches all paths!
Notice, though, that the
does not have the domain
it has the domain
jameshfisher.com, without a leading dot.
This only matches the domain
jameshfisher.com - no subdomains!
So a cookie domain beginning with
. is a domain suffix;
otherwise, it’s a fully qualified domain.
bgcolor got the domain
because the default cookie domain is the domain of the current page.
bgcolor available to subdomains,
you can set the
domain explicitly to
;domain=.jameshfisher.com to the assignment:
> document.cookie = "bgcolor=mintcream;domain=.jameshfisher.com"; > document.cookie "_ga=GA1.2.12345.67890; _gid=GA1.2.111111.222222; bgcolor=mintcream; bgcolor=mintcream"
But what’s this?
We now have two cookies called
By checking the cookies listed in developer tools,
you can see the two cookies:
jameshfisher.com, and another for
If you consider the browser’s cookies as a big relational table,
the unique key is (domain, path, name).
We have two cookies:
and second, (
It was not obvious from the value of
document.cookie that those two cookies had different domains.
Those cookie attributes are omitted entirely in
and no access to any other attributes such as the domain or path!
Let’s say we wanted the cookie to be exposed to subdomains,
so we want to delete the cookie for
But there is no explicit API for cookie deletion!
Instead, we have to use another cookie attribute:
All cookies have an expiry time,
and we delete a cookie by setting its expiry time to the past!
We can do this by appending
;expires=Thu, 01 Jan 1970 00:00:01 GMT to the cookie.
Let’s do that for the cookie for
> document.cookie = "bgcolor=mintcream;domain=jameshfisher.com;expires=Thu, 01 Jan 1970 00:00:01 GMT"; > document.cookie "_ga=GA1.2.12345.67890; _gid=GA1.2.111111.222222; bgcolor=mintcream"
Back to one
bgcolor cookie: all looks good!
But wait ... if you check the developer tools,
you’ll see that we deleted the wrong cookie!
We asked to delete the cookie for
but instead the cookie for
.jameshfisher.com is gone!
It turns out,
if you explicitly specify the domain when setting a cookie,
this always means a domain suffix.
So even if you specify
this gets interpreted as
(I told you this API was bad.)
The only way to delete the cookie for
is by omitting the
domain attribute entirely,
allowing it to fall back to the default domain taken from the current page:
> document.cookie = "bgcolor=mintcream;expires=Thu, 01 Jan 1970 00:00:01 GMT"; > document.cookie "_ga=GA1.2.12345.67890; _gid=GA1.2.111111.222222"
For both of our cookies, the path was
you can check this in developer tools.
But where did this path come from?
Because we didn’t set the cookie’s path explicitly,
it defaulted to the directory of the current page.
The full URL of this page is
The full path is
The directory of this path is
So this cookie matches the current page,
plus anything else I published on 2018-12-22
(of which there is nothing).
More by Jim
- Your syntax highlighter is wrong
- Granddad died today
- The Three Ts of Time, Thought and Typing: measuring cost on the web
- I hate telephones
- The sorry state of OpenSSL usability
- The dots do matter: how to scam a Gmail user
- My parents are Flat-Earthers
- How Hacker News stays interesting
- Project C-43: the lost origins of asymmetric crypto
- The hacker hype cycle
- The inception bar: a new phishing method
- Time is running out to catch COVID-19
- A probabilistic pub quiz for nerds
- Smear phishing: a new Android vulnerability