Permissions-Policy
Send `Permissions-Policy: camera=(), microphone=(), geolocation=()` to deny features your site does not use — including to any third party you embed.
Send this header. There is no meaningful downside for a typical site.
What it does
Permissions-Policy declares which browser capabilities — camera, microphone, geolocation, payment, and a long tail of others — may be used by your page and by anything you embed. Denying a feature means the API is unavailable rather than merely prompting, so a third-party script cannot even ask.
The value of that is mostly about frames. Your own code presumably does not call `getUserMedia` by accident; a tag manager, an ad frame or a vendor widget might, and a permission prompt that appears on your domain is attributed to you by the user. An explicit deny list makes the answer "no" before anyone is asked.
The syntax is where teams lose time. It replaced `Feature-Policy` and changed grammar in the process: allowlists are parenthesised lists rather than space-separated tokens, `()` means deny-all, `*` means allow everywhere, and `self` appears without quotes — unlike CSP, where quoting `'self'` is required. Examples on the web are frequently the old Feature-Policy syntax, which current browsers ignore.
What to send
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()Deny what you do not use, and be specific about what you do. If your own page needs geolocation, `geolocation=(self)` permits your origin while still denying every frame you embed. Note that `interest-cohort` targeted a since-abandoned proposal — it is harmless to keep but no longer does anything, and is a good marker for a config that has not been revisited.
Directives and values
Deny the feature to everyone, including your own origin. The empty allowlist.
Allow your own origin only. Embedded third-party frames are denied.
Allow your origin plus a named origin. Origins are quoted; `self` is not.
Allow everywhere, including all embedded frames. Rarely what you want.
The three worth denying by default on any site that does not use them — they are the ones that produce a user-facing prompt attributed to your domain.
Hardware and payment APIs. Almost always safe to deny outright.
Lower-risk features, but common candidates for restricting to `self` so embedded content cannot take over the viewport.
Common mistakes
- Using Feature-Policy syntax. `Permissions-Policy: geolocation 'self'` is the old grammar and is ignored. The current form is `geolocation=(self)` — parentheses, no quotes around `self`, quotes around origins.
- Quoting self. CSP requires `'self'` with quotes; Permissions-Policy requires `self` without them. Mixing the two conventions is the single most common cause of a policy that parses to nothing.
- Forgetting that a deny applies to your own page too. `camera=()` denies the camera to your own origin as well. If your product has a video feature on one route, that route needs `camera=(self)` rather than the blanket deny.
- Assuming it replaces the permission prompt for your own features. It governs availability, not consent. A user still sees the browser permission prompt for a feature you have allowed — the header only decides whether asking is possible at all.
Browser support
Good in Chromium-based browsers. Firefox and Safari support a subset of features and ignore directives they do not implement, so treat it as defence in depth rather than a guarantee. Unknown feature names are ignored rather than invalidating the whole header, which makes it safe to list features not every browser knows.
Frequently asked questions
What is the difference between Permissions-Policy and Feature-Policy?
Permissions-Policy is the renamed and re-specified successor. Beyond the name, the syntax changed: allowlists are now parenthesised (`geolocation=(self)`) rather than space-separated (`geolocation 'self'`), and `self` is unquoted. Browsers ignore the old syntax, so a copy-pasted Feature-Policy example does nothing.
How do I deny all features I do not use?
List each one with an empty allowlist: `Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()`. There is no wildcard that denies everything, so the list has to be explicit.
Does Permissions-Policy apply to iframes?
Yes, and that is its main value. A feature you deny cannot be used by embedded third-party content, so a vendor widget or ad frame cannot trigger a camera or location prompt that the user will attribute to your domain.
Why is self written without quotes?
Because Permissions-Policy uses structured-field syntax, where `self` is a bare token and origins are quoted strings. CSP uses its own grammar where `'self'` is quoted. The two headers genuinely differ, and mixing them produces a policy the browser discards.
The free Security Headers Checker reads Permissions-Policy from a live response and grades it alongside every other header on this reference — no account needed.
For the longer treatment, read Advanced HTTP Security Headers: A Deep Dive in the Learning Center.
Related headers
Controls how much of your URL is sent to other sites. The default leaks more than most teams expect.
The most powerful and most misconfigured security header. Most deployed policies provide no XSS protection at all.
Severs the link between your page and windows that opened it. Required for cross-origin isolation — and it breaks popup flows.