The browser uses the Referer header to tell a server which page a request came from. It's behind analytics, hotlink protection and a surprising number of "works on my machine" bugs. This guide covers what it contains today, why it's often shorter than you expect, and how to set it when you need to test.
When you click a link on https://blog.example.com/post/42 to another site, the browser's request looks like this:
GET /pricing HTTP/1.1
Host: shop.example.org
Referer: https://blog.example.com/
The same goes for images, scripts, stylesheets and fetch() calls a page makes: each can carry the page's address. Fragments (#section) and any username or password in the URL are never included.
A typo in the 1996 HTTP specification. By the time anyone noticed, servers everywhere read Referer, so it stayed. The newer Referrer-Policy header, the JavaScript document.referrer property and the referrerpolicy attribute are all spelled correctly. Mixing them up is a classic bug: a server that reads Referrer gets nothing.
Since Chrome 85 (2020), and in Firefox and Safari too, the default policy is strict-origin-when-cross-origin. That means:
| Request goes to | Referer sent |
|---|---|
| The same origin (same scheme, host and port) | Full URL: https://blog.example.com/post/42?ref=nav |
Another origin on the same site (blog. → shop.example.com) | Origin only: https://blog.example.com/ |
| Another site, over https | Origin only: https://blog.example.com/ |
| Any site over plain http, from an https page | Nothing |
It can also be missing because the page set a stricter policy, the link has rel="noreferrer", the user typed the address or used a bookmark, or a privacy extension stripped it.
A site controls what its pages send with a response header or a meta tag:
Referrer-Policy: strict-origin-when-cross-origin
<meta name="referrer" content="no-referrer">
| Value | What gets sent |
|---|---|
no-referrer | Never anything |
same-origin | Full URL to your own origin, nothing elsewhere |
origin | Only the origin, everywhere |
strict-origin | Only the origin, and nothing on https→http |
strict-origin-when-cross-origin | Full URL on your own origin, origin elsewhere (even your other subdomains), nothing on https→http (the default) |
no-referrer-when-downgrade | Full URL everywhere except https→http (the old default) |
unsafe-url | Full URL, everywhere, including query strings. Avoid it: tokens in URLs leak this way. |
You can't set it from page JavaScript: Referer is a forbidden header, so fetch(url, { headers: { Referer: "..." } }) is silently ignored. The referrer option of fetch only accepts a URL on your own origin. Your options:
curl -e "https://partner.example.com/" https://api.example.com/image.png
curl -H "Referer: https://partner.example.com/" https://api.example.com/image.png
A header extension can set, replace or remove Referer on requests to one site, which is how you test hotlink protection, a partner-only embed, or an analytics filter in a real browser session.
Set, replace or remove any request header, Referer included, for all sites or only for URL patterns you pick, and switch it off with one click. It tells you whether the rule actually fired. No account, no tracking.
Referer is fine for analytics and for casual hotlink protection. It is not a security check: anyone can send any value from curl, and many real visitors send none at all because of the policies above. For access control, use a token. For protecting forms against cross-site requests, use SameSite cookies and a CSRF token, and check the Origin header, which browsers send on cross-site POSTs and which pages can't fake.
Related: add any custom header to requests in Chrome · change your user agent · X-Frame-Options and "refused to connect" · what CORS is.
More on this topic: Cache-Control header explained: max-age, no-cache, no-store and more · “Refused to load … violates the following Content Security Policy directive”: fixes · Mixed content error: “loaded over HTTPS, but requested an insecure resource” · ModHeader alternative