Why the Referer header deserves your attention

Every HTTP request can carry an optional Referer header that tells the receiving server where the request came from—either the full page URL or just the origin. The Referrer-Policy header on the sending side controls exactly what gets exposed. For navigations and iframes, JavaScript can read the same data through document.referrer.

Referrer data is genuinely useful. Analytics platforms lean on it to attribute traffic, and site owners use it to understand user journeys. But when the full URL—including path and query string—crosses origins, it can silently leak private information. Tokens in URLs, personal identifiers, and capability URLs (links that grant access to protected resources) are all at risk if they end up in a Referer header sent to a third party.

The fix is a referrer policy that keeps the useful parts while limiting exposure. The widely recommended choice is strict-origin-when-cross-origin, which sends the full URL for same-origin requests but only the origin when the request goes cross-origin over a secure connection.

The eight policies and what they expose

You can pick from eight policies. Depending on the one you set, the Referer header (and document.referrer) will contain either no data at all, just the origin, or the full URL with path and query string.

Several policies behave conditionally, depending on request context—whether it's same-origin or cross-origin, and whether the destination is as secure as the origin. That context-awareness is valuable: it lets you keep rich referrer data inside your own site while restricting what goes to third parties or insecure origins.

Policy scope Policy name Referer: No data Referer: Origin only Referer: Full URL
Doesn't consider the request context no-referrer check
origin check
unsafe-url check
Security-focused strict-origin Request from HTTPS to HTTP Request from HTTPS to HTTPS
or HTTP to HTTP
no-referrer-when-downgrade Request from HTTPS to HTTP Request from HTTPS to HTTPS
or HTTP to HTTP
Privacy-focused origin-when-cross-origin Cross-origin request Same-origin request
same-origin Cross-origin request Same-origin request
Privacy and security-focused strict-origin-when-cross-origin Request from HTTPS to HTTP Cross-origin request
from HTTPS to HTTPS
or HTTP to HTTP
Same-origin request

A few nuances are easy to miss when evaluating these policies:

  • Policies that consider the scheme (strict-origin, no-referrer-when-downgrade, and strict-origin-when-cross-origin) treat HTTP→HTTP requests the same as HTTPS→HTTPS requests. They only care about security downgrades—a request that moves data from an encrypted origin to an unencrypted one. An HTTP→HTTP request is unencrypted throughout, so nothing is being downgraded.
  • Same-origin requests always carry the same scheme, so a security downgrade is impossible by definition.

Browser defaults are no longer a safe bet

If no policy is set, the browser applies its own default. Browsers have been moving toward stricter defaults over time, with strict-origin-when-cross-origin becoming the baseline in Chrome, Firefox, and Edge. Safari similarly settled on a strict default. But relying on defaults is a poor strategy for two reasons:

  • Defaults have historically differed between browsers, so a site's behavior can vary depending on the user agent.
  • Browsers keep tightening the screws—mechanisms like referrer trimming are already emerging—so the default you build around today may be stricter tomorrow.

Explicitly setting a privacy-enhancing policy puts you in control, removes cross-browser inconsistency, and lets you test against a policy you chose intentionally.

Setting a policy: page level, element level, request level

There are three places to configure referrer policy:

  • An HTTP header on the response.
  • A <meta> element in the page's HTML.
  • A per-request setting from JavaScript, like referrerPolicy in fetch().

The header and the meta element both operate at page level. The effective policy for any given element follows a priority order:

  1. Element-level policy (via the referrerpolicy attribute).
  2. Page-level policy (header or meta).
  3. Browser default.

This layering makes it straightforward to keep a strict site-wide policy while carving out exceptions. For instance, a page set to strict-origin-when-cross-origin can still allow a specific image request to use no-referrer-when-downgrade by adding a referrerpolicy attribute directly on that element.

Why strict-origin-when-cross-origin wins

The ideal policy delivers on three criteria—security, privacy, and usefulness:

  • Secure: On an HTTPS site, you never want URLs leaking into plain HTTP requests, where anyone on the network can read them. Policies like no-referrer-when-downgrade, strict-origin-when-cross-origin, strict-origin, and no-referrer all prevent this.
  • Privacy-enhancing: For cross-origin requests, no-referrer-when-downgrade exposes the full URL. strict-origin-when-cross-origin and strict-origin limit the leak to just the origin; no-referrer leaks nothing.
  • Useful: no-referrer and strict-origin withhold the full URL even for same-origin requests, which breaks internal referrer tracking. Only strict-origin-when-cross-origin keeps full URLs for same-origin traffic while staying strict cross-origin.

To set that policy globally, you can add a response header like Referrer-Policy: strict-origin-when-cross-origin from your server, or drop a matching <meta name="referrer"> tag into your HTML.

When a strict policy isn't enough

Occasionally a business need genuinely requires sending more referrer data to a specific third party—an embedded payment widget or a partner analytics service might need the full page URL. In those cases, take a progressive approach: keep strict-origin-when-cross-origin at the site level, then deliberately relax the policy for just the requests or elements that need it.

Element-level relaxation uses the referrerpolicy attribute:

<a href="https://partner.example" referrerpolicy="unsafe-url">Partner link</a>

Request-level relaxation is available through the fetch() API:

fetch('/api/data', { referrerPolicy: 'origin' });

Remember that Safari and WebKit may cap or trim referrer data for cross-site requests regardless of the policy you set, so exception routes should never rely on the full URL arriving intact.

One caution applies no matter which policy you pick: do not use the referrer for CSRF protection. Attackers can suppress or spoof the header. Use CSRF tokens as your primary defense and treat referrer checks as a secondary signal only.

Handling incoming referrers: what to expect

When your site receives a request with a Referer header or exposes document.referrer to scripts, remember that the data can contain private or identifying information. Treat it accordingly. More importantly, understand that you cannot rely on incoming referrer data being stable. The sending site controls its own referrer policy, so it may tighten or change that policy at any time. Browsers also increasingly default to strict-origin-when-cross-origin, which means you may only receive an origin rather than a full URL for cross-origin requests. Some browsers may also trim referrers to origins for cross-origin subresource requests outright, and the Referer you receive may contain more information than your use case requires.

If a core feature of your site depends on the referrer of an incoming cross-origin request, and you are no longer getting the part of the URL you need (either because the sender changed its policy or because it uses no policy and the browser default shifted), first determine exactly which part of the referrer you rely on:

  • Origin only? If you are reading the referrer from a script with top-level page access, use window.location.origin instead. For server-side checks, the Origin header or Sec-Fetch-Site header provides the origin or tells you whether the request is cross-origin, frequently enough on its own.
  • Other URL components (path, query parameters)? Consider passing the data as explicit request parameters. If you are in a top-level script, window.location.pathname may suffice; extract only the path and pass it as an argument so that potentially sensitive query-string data is not forwarded.
  • No direct alternative? Two options remain. First, you can redesign your system so that the requesting site (for example, site-one.example) explicitly provides the needed data in a configuration. This is more explicit, more privacy-preserving for the sender's users, and more future-proof, although it may require additional work for you or your users. Second, you can ask the sending site to set a per-element or per-request Referrer-Policy of no-referrer-when-downgrade. This is a fallback that may be less privacy-preserving for the sender's users and is not supported in every browser.

Security: CSRF and payment flows

Because a request emitter can always choose to send no referrer (and a malicious actor can spoof one), the Referer is never a reliable security boundary. For cross-site request forgery (CSRF) protection, rely primarily on CSRF tokens. Add SameSite cookies for defense in depth, and use headers such as Origin (available on POST and CORS requests) and Sec-Fetch-Site rather than the Referer when they are available.

The one industry area where referrer checking is still common is payment validation. A typical flow works like this: a user clicks a Buy button on online-shop.example/cart/checkout, the shop redirects the user to payment-provider.example, and the payment provider checks the incoming Referer against a merchant-supplied allowlist. If there is no match, the payment provider rejects the request.

If you are a payment provider using this model, treat the Referer check as a basic filter for naive attackers, not as a primary defense. A legitimate merchant can set a no-referrer policy that removes the header completely, so you cannot expect it to always be present. When it is present, check only for the origin of the requesting site. Your allowlist should contain only origins (for example, online-shop.example), never paths like online-shop.example/cart/checkout. By accepting either an absent Referer or a value that contains only the origin, you avoid breaking when the merchant changes its policy. After that basic origin check succeeds (or the header is absent), proceed to a stronger verification step.

For genuinely reliable payment verification, have the requesting site hash the request parameters with a unique key, then recompute the same hash on your side and accept the request only when it matches.

Note what happens when an HTTP merchant site with no referrer policy redirects to an HTTPS payment provider: no Referer is sent in the request to the HTTPS provider. Most browsers already default to strict-origin-when-cross-origin or no-referrer-when-downgrade, and Chrome's move to its new default does not change this downgrade behavior.