Referrer Policy in .htaccess
Every time a user clicks a link, submits a form, or a page loads a resource like an image or script, the browser sends a Referer header (yes, it is intentionally misspelled in the HTTP specification) to the destination server. This header contains the URL of the page that initiated the request. While this information is useful for analytics and navigation, it can also leak sensitive data like search queries, private URL paths, user IDs, tokens, and internal application structure to third-party sites.
This guide explains what the Referer header reveals, walks through each available Referrer-Policy value, and helps you choose the right policy for your site.
What the Referer Header Exposes
When a user on your page https://example.com/account/settings?token=abc123 clicks a link to https://external-site.com, the browser sends this header with the request:
Referer: https://example.com/account/settings?token=abc123
The external site now knows:
- The user came from
example.com. - The user was on an account settings page.
- There is a
tokenparameter with the valueabc123.
This information leaks in multiple scenarios:
| Scenario | What Gets Exposed |
|---|---|
| User clicks an external link | Full page URL including path and query string |
| Page loads a third-party image or script | Full page URL to the image/script host |
| Page loads a third-party analytics pixel | Full page URL to the analytics provider |
| HTTPS page links to an HTTP page | Full page URL sent over an unencrypted connection |
| Search results page links to external sites | Search query in the URL |
| Password reset page loads external resources | Reset token in the URL |
| Admin panel loads third-party libraries | Internal admin URL structure |
The risks are tangible:
- Security tokens in URLs can be stolen by third parties.
- Internal URL structure reveals how your application is organized, which helps attackers map your site.
- User activity is trackable across sites through referrer data.
- Private content paths (like
/admin/users/123/edit) expose the existence of resources and user IDs. - Search queries reveal what users are looking for, which may include sensitive information.
Without a Referrer-Policy header, the browser's default behavior varies, but most modern browsers default to strict-origin-when-cross-origin. Older browsers may send the full URL in all cases. Setting an explicit policy ensures consistent behavior across all browsers.
Referrer-Policy Values
The Referrer-Policy header accepts several values, each controlling how much referrer information is shared. The values range from sharing everything to sharing nothing.
no-referrer
<IfModule mod_headers.c>
Header always set Referrer-Policy "no-referrer"
</IfModule>
Never sends any referrer information. The Referer header is completely omitted from all requests, whether same-origin or cross-origin, HTTPS or HTTP.
| From | To | Referer Sent |
|---|---|---|
https://example.com/page | https://example.com/other | (none) |
https://example.com/page | https://external.com | (none) |
https://example.com/page | http://external.com | (none) |
Pros:
- Maximum privacy. No information leaks whatsoever.
- Simplest to reason about.
Cons:
- Your own analytics lose all referrer data, making it impossible to track internal navigation paths.
- Third-party analytics (Google Analytics, etc.) cannot attribute traffic sources.
- Some anti-CSRF mechanisms that rely on the
Refererheader will break. - Affiliate tracking and partner attribution stop working.
no-referrer provides the strongest privacy protection, but the impact on analytics is significant. Most sites that depend on understanding traffic sources cannot use this value without losing important data. Consider strict-origin-when-cross-origin as a balanced alternative.
same-origin
<IfModule mod_headers.c>
Header always set Referrer-Policy "same-origin"
</IfModule>
Sends the full referrer URL for same-origin requests. Sends nothing for cross-origin requests.
| From | To | Referer Sent |
|---|---|---|
https://example.com/account | https://example.com/dashboard | https://example.com/account |
https://example.com/search?q=secret | https://example.com/results | https://example.com/search?q=secret |
https://example.com/page | https://external.com | (none) |
https://example.com/page | http://example.com/page | (none) (different scheme) |
Use case: Applications that need full internal referrer data for their own analytics and navigation tracking but want zero information leakage to external sites. This is a good choice for intranet applications, admin panels, and applications with sensitive URL structures.
strict-origin
<IfModule mod_headers.c>
Header always set Referrer-Policy "strict-origin"
</IfModule>
Sends only the origin (scheme + host, no path or query) for same-security-level requests. Sends nothing when navigating from HTTPS to HTTP.
| From | To | Referer Sent |
|---|---|---|
https://example.com/account?id=42 | https://example.com/dashboard | https://example.com/ |
https://example.com/page | https://external.com | https://example.com/ |
https://example.com/page | http://external.com | (none) |
http://example.com/page | http://external.com | http://example.com/ |
The key behavior: the path and query string are always stripped. Only the origin (like https://example.com/) is sent. And when the request would downgrade security (HTTPS to HTTP), nothing is sent at all.
Use case: When you want third-party sites to know traffic came from your domain (for SEO attribution and analytics) without revealing which specific page the user was on.
strict-origin-when-cross-origin
<IfModule mod_headers.c>
Header always set Referrer-Policy "strict-origin-when-cross-origin" "expr=%{CONTENT_TYPE} =~ m#text\/(css|html|javascript)|application\/pdf|xml#i"
</IfModule>
Sends the full URL for same-origin requests. Sends only the origin for cross-origin same-security requests. Sends nothing for HTTPS-to-HTTP downgrades.
| From | To | Referer Sent |
|---|---|---|
https://example.com/search?q=test | https://example.com/results | https://example.com/search?q=test |
https://example.com/page | https://external.com | https://example.com/ |
https://example.com/page | http://external.com | (none) |
This is the recommended default for most websites. It provides the best balance:
- Your own site gets full referrer data for internal analytics and navigation tracking.
- External sites learn that traffic came from your domain but not which specific page.
- No data is sent over insecure connections.
The content type expression expr=%{CONTENT_TYPE} =~ m#text/(css|html|javascript)|application/pdf|xml#i limits the header to responses that can initiate navigation or load sub-resources. There is no reason to add referrer policies to images, fonts, or binary downloads.
Other Values
Several additional values exist for specialized use cases:
no-referrer-when-downgrade
Header always set Referrer-Policy "no-referrer-when-downgrade"
Sends the full URL for all requests except when navigating from HTTPS to HTTP. This was the browser default behavior before strict-origin-when-cross-origin became the standard.
| From | To | Referer Sent |
|---|---|---|
https://example.com/page?id=42 | https://external.com | https://example.com/page?id=42 |
https://example.com/page?id=42 | http://external.com | (none) |
This value leaks full URL paths and query strings to external HTTPS sites. It is generally not recommended because strict-origin-when-cross-origin provides better privacy with minimal downside.
origin
Header always set Referrer-Policy "origin"
Always sends only the origin, for both same-origin and cross-origin requests, regardless of protocol security.
| From | To | Referer Sent |
|---|---|---|
https://example.com/page?id=42 | https://example.com/other | https://example.com/ |
https://example.com/page | http://external.com | https://example.com/ |
Note that unlike strict-origin, this sends the origin even on HTTPS-to-HTTP downgrades, which is less secure.
origin-when-cross-origin
Header always set Referrer-Policy "origin-when-cross-origin"
Sends the full URL for same-origin requests. Sends only the origin for cross-origin requests, regardless of protocol security.
| From | To | Referer Sent |
|---|---|---|
https://example.com/page?id=42 | https://example.com/other | https://example.com/page?id=42 |
https://example.com/page | https://external.com | https://example.com/ |
https://example.com/page | http://external.com | https://example.com/ |
Similar to strict-origin-when-cross-origin but without the HTTPS-to-HTTP protection. The "strict" variant is preferred.
unsafe-url
# NOT RECOMMENDED
Header always set Referrer-Policy "unsafe-url"
Sends the full URL (origin, path, and query string) for every request, regardless of the destination or protocol security. As the name suggests, this is unsafe.
| From | To | Referer Sent |
|---|---|---|
https://example.com/page?token=xyz | http://external.com | https://example.com/page?token=xyz |
Never use unsafe-url unless you have a very specific reason and fully understand the risks. It sends complete URLs, including sensitive query parameters, over insecure connections to any destination. This is the most privacy-hostile setting available.
Quick Comparison Table
| Policy | Same-Origin | Cross-Origin (HTTPS→HTTPS) | Cross-Origin (HTTPS→HTTP) |
|---|---|---|---|
no-referrer | (none) | (none) | (none) |
same-origin | Full URL | (none) | (none) |
strict-origin | Origin only | Origin only | (none) |
strict-origin-when-cross-origin | Full URL | Origin only | (none) |
no-referrer-when-downgrade | Full URL | Full URL | (none) |
origin | Origin only | Origin only | Origin only |
origin-when-cross-origin | Full URL | Origin only | Origin only |
unsafe-url | Full URL | Full URL | Full URL |
Choosing the Right Policy
The right policy depends on your site's requirements. Here is a decision framework:
For Most Websites
<IfModule mod_headers.c>
Header always set Referrer-Policy "strict-origin-when-cross-origin" "expr=%{CONTENT_TYPE} =~ m#text\/(css|html|javascript)|application\/pdf|xml#i"
</IfModule>
strict-origin-when-cross-origin is the right default for the vast majority of websites. It preserves full referrer data for your own analytics, shares only the origin with external sites (so they know traffic came from your domain), and never leaks data over insecure connections.
For Privacy-Focused Applications
<IfModule mod_headers.c>
Header always set Referrer-Policy "same-origin"
</IfModule>
Healthcare portals, financial applications, legal services, and any site where URL paths might reveal sensitive information about the user. External sites receive no referrer data at all, while internal navigation tracking still works.
For Maximum Privacy (Activist Sites, Whistleblower Platforms)
<IfModule mod_headers.c>
Header always set Referrer-Policy "no-referrer"
</IfModule>
When any referrer leakage is unacceptable and analytics data is not a priority.
For Sites That Depend on Referrer Attribution
<IfModule mod_headers.c>
Header always set Referrer-Policy "no-referrer-when-downgrade"
</IfModule>
Affiliate programs, content networks, and advertising platforms where partner sites need to see the full referring URL for attribution. Use only if the URLs on your site do not contain sensitive information.
Combining with Other Security Headers
The Referrer-Policy header is part of a broader security header strategy. Here is how it fits alongside other headers:
<IfModule mod_headers.c>
# Referrer control
Header always set Referrer-Policy "strict-origin-when-cross-origin" "expr=%{CONTENT_TYPE} =~ m#text\/(css|html|javascript)|application\/pdf|xml#i"
# HTTPS enforcement
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
# XSS and injection protection
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'"
# Clickjacking protection
Header always set X-Frame-Options "DENY" "expr=%{CONTENT_TYPE} =~ m#text/html#i"
# MIME sniffing prevention
Header always set X-Content-Type-Options "nosniff"
</IfModule>
Each header addresses a different aspect of security. Referrer-Policy controls information leakage through navigation. HSTS enforces encrypted connections. CSP restricts resource loading. X-Frame-Options prevents clickjacking. X-Content-Type-Options stops MIME sniffing. Together, they form a comprehensive defense-in-depth strategy.
Setting a Referrer-Policy is a simple, low-risk improvement that every website should make. The strict-origin-when-cross-origin value works well as a default for nearly all sites, protecting user privacy while preserving the referrer data you need for analytics and internal tracking. Review your URL structure for sensitive data, choose the appropriate policy level, and add the header alongside your other security configurations.