Permissions-Policy: turning browser features off by default
Permissions-Policy decides which browser features a page and its frames may use, so a third party embed cannot silently reach for the camera, the microphone or geolocation.
At a glance
- Direction
- Response header. Individual frames can be further restricted with an allow attribute.
- Defined in
- Permissions Policy (W3C). It replaced the Feature-Policy header.
- When absent
- Each feature falls back to its own default allowlist, which for most powerful features is the document origin.
- Disable a feature
- feature=() with empty parentheses, which is an empty allowlist
- Allow your own origin
- feature=(self)
- Syntax note
- Origins are quoted strings, self is not quoted, and features are separated by commas.
- In the headers checker
- Graded on presence. It does not audit individual feature allowlists.
In detail
The header is a comma separated list of feature names, each followed by an allowlist in parentheses. An empty list turns the feature off for the document and everything it embeds. The token self means the document origin only, a quoted URL adds one specific origin, and the star token allows everyone, which is almost never what you want for a feature such as microphone.
The point is defence against code you did not write. An advertisement iframe, a chat widget or an embedded map inherits your page's permissions unless a policy says otherwise, and a permission prompt raised by a third party script still carries your site's name. Disabling every feature the application does not use costs one header line and removes that whole class of surprise.
The syntax deliberately differs from the Feature-Policy header it replaced. Feature-Policy separated features with semicolons and wrote origins unquoted; Permissions-Policy uses commas and quotes origins as strings. Sending both is harmless if they agree, but copying old Feature-Policy syntax into the new header produces a value the browser cannot parse and therefore ignores.
Feature names track browser capabilities rather than a stable registry, so a name your browser does not recognise is skipped silently instead of invalidating the policy. That makes the header safe to over-specify: listing a feature some browser has not implemented does not affect the rest of the list.
Examples
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()Permissions-Policy: geolocation=(self "https://maps.partner.example"), camera=()<iframe src="https://maps.partner.example/embed" allow="geolocation"></iframe>The frame attribute can only narrow what the page level policy already permits, never widen it.
Things that catch people out
- Semicolons between features are Feature-Policy syntax. In Permissions-Policy the separator is a comma, and the wrong one makes the whole header unparseable.
- Origins must be quoted and self must not be. Writing geolocation=('self') is invalid; geolocation=(self) is correct.
- A frame can never gain a feature the parent policy denies, so debugging a broken embed means checking the top level header before the allow attribute.
Try it: HTTP Headers Checker
Check a live URL or paste headers you already have. It grades six security headers from A+ to F and lists every other header the response returned.
HTTP Headers Checker
LOCAL · Browser-OnlyView HTTP response headers for any URL
Enter any website URL to fetch and analyze its HTTP response headers. We'll automatically add https:// if needed.
Why Check Security Headers?
Security headers protect your website against common attacks like XSS, clickjacking, and MIME sniffing. They're set by your web server and cost nothing to implement. Missing security headers are one of the most common findings in security audits.
Related HTTP headers
All http headers →Content-Security-Policy: directives, sources and reporting
How CSP directives are matched, what default-src actually falls back to, why unsafe-inline defeats the point of a policy, and how nonces and hashes work.
Cross-Origin-Embedder-Policy: require-corp and credentialless
What require-corp demands from every subresource, how credentialless relaxes it, and why enabling COEP is what breaks third party images and embeds.
Referrer-Policy: controlling what the Referer header leaks
Every Referrer-Policy value compared, what modern browsers do when the header is missing, and why URLs with tokens in them leak to third parties without it.
X-Frame-Options: DENY, SAMEORIGIN and clickjacking
What DENY and SAMEORIGIN do, why ALLOW-FROM never worked, and how CSP frame-ancestors supersedes this header while it is still worth sending.
X-XSS-Protection: a legacy header and why it is off
What the browser XSS auditor did, why Chrome and Edge removed it, why 0 is now the recommended value, and what to send in its place.
Cross-Origin-Opener-Policy: isolating your browsing context
What COOP severs between your page and the windows it opens, how same-origin differs from same-origin-allow-popups, and its part in cross-origin isolation.
Tools for this
- HTTP Headers Checker Free online HTTP headers checker - view HTTP response headers for any URL
- HTTP Request Builder Free online HTTP request builder - build and test HTTP requests with custom headers and body