Headers
Why it matters A single request can tell a third party who you are (a cookie), where you were (the page you came from), roughly where you live (your language) and what device you use. Knowing exactly which headers carry what lets you audit a site, write a blocker, and check that the privacy signals you switched on are really being sent.
Go back to the letter picture. The headers are the notes written on the envelope. Most are harmless sorting instructions, but some are like writing your name, your last address and your home town on the outside, where everyone who handles the letter can read them. This lesson is about spotting those.
The headers that matter for privacy
| Header | What it says | Why a tracker cares |
|---|---|---|
Cookie | the cookies the browser has for this server | an ID that recognises you on every visit |
Referer | the page that made the request | where you were when the request was sent |
User-Agent | browser, version and system | one ingredient of a fingerprint |
Accept-Language | your preferred languages | a fingerprint ingredient and a hint about where you live |
Origin | the site that sent a form or a fetch | which site you were on |
Sec-Fetch-Site | same-origin, same-site, cross-site or none | tells a server it is being called from another site (useful for defence too) |
Sec-GPC | 1 when Global Privacy Control is on | a request not to sell or share your data |
DNT | 1 for Do Not Track | an older request not to be tracked |
Referer: the header naming the page a request came from. It is spelled with one r in the middle, a typo from the 1990s that stuck. Modern browsers by default send only the site's origin (for example https://shopa.example/) to other sites, not the full address (checked October 2026).
Global Privacy Control (GPC): a browser setting that adds Sec-GPC: 1 to every request, asking sites not to sell or share your personal data. Some browsers turn it on by default or in a privacy mode; it is a request, not a block.
Do Not Track is the older cousin of GPC. Very few sites ever honoured it and some browsers have dropped the setting, but some still send it (checked October 2026), so your code should still read it.
Two rules that trip people up
Names ignore case. Cookie, cookie and COOKIE are the same header. HTTP/2 and HTTP/3 even send every name in lower case. So compare names with .lower() and keep values exactly as written.
Headers can repeat. A response often carries several Set-Cookie lines, one per cookie. That is why the last lesson kept a list of pairs instead of a dict, which would quietly drop all but one. For most headers, HTTP says repeated values can be joined with ", ", so we do that when we report them.
A common misconception
"Only cookies identify me." A cookie is the most direct ID, but User-Agent plus Accept-Language plus your IP address already narrows you down a lot, and the Referer tells the tracker where you were even with no cookie at all. That is why a blocker cares about whole requests, not only cookies.
Try it In DevTools, Network tab, click a request to an image or script on another site and read its Request Headers. Is there a Cookie? What does Referer say, the full page address or only the site? Then search the headers for Sec-GPC to see whether your browser sends it.
In other languages
JavaScript:
// In a service worker or server, the Headers object ignores case for you:
const ua = request.headers.get("user-agent"); // same as "User-Agent"
const gpc = request.headers.get("Sec-GPC") === "1";
const cookies = request.headers.get("Cookie") ?? "";PHP:
// PHP puts request headers in $_SERVER, upper-cased with HTTP_ in front
$referer = $_SERVER['HTTP_REFERER'] ?? null;
$gpc = ($_SERVER['HTTP_SEC_GPC'] ?? '') === '1';C#:
// ASP.NET Core: header lookups ignore case
var gpc = Request.Headers["Sec-GPC"] == "1";
var lang = Request.Headers.AcceptLanguage.ToString();Recap
- Cookie, Referer, User-Agent, Accept-Language, Origin and Sec-Fetch-Site are the headers that tell a server most about you.
- Sec-GPC: 1 and DNT: 1 are your browser asking not to be tracked or sold; only the value 1 counts.
- Header names ignore case and headers can repeat, so look them up with lower case and collect every value.
header_lines(raw) is given. Write get_all(raw, name): every value of that header in order, ignoring case ([] if missing). Write tracking_headers(raw): a dict of lower-case name to value for each name in TRACKING_HEADERS that appears, with repeated values joined by ", ". Write opt_out_signals(raw): {"gpc": ..., "dnt": ...}, each True only when that header is present with the value "1".
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.