The Permissions-Policy HTTP response header lets you control which browser features and APIs are available on your page and — crucially — in any embedded iframes. It prevents malicious or compromised third-party scripts and embeds from accessing sensitive device capabilities such as the camera, microphone, or geolocation without your explicit permission.
What Problem Does It Solve?
Modern browsers expose powerful APIs to web pages: access to the camera and microphone, GPS location, device sensors, payment interfaces, and more. By default, a page can request any of these features, and so can any iframe embedded in it.
Consider an e-commerce site that embeds a third-party chat widget. Without Permissions-Policy, that widget could — if malicious or compromised — attempt to access the user's microphone or camera. Permissions-Policy lets you declare upfront that no iframe on your page should ever access those APIs, regardless of what the embed requests.
Permissions-Policy: camera=(), microphone=(), geolocation=()Relationship to Feature-Policy
Permissions-Policy is the standardised successor to the earlier Feature-Policy header. The rename happened in 2020 alongside a syntax change. If your site still sendsFeature-Policy, replace it with Permissions-Policy — modern browsers have dropped or will drop support for the old name.
| Old (Feature-Policy) | New (Permissions-Policy) |
|---|---|
Feature-Policy: geolocation 'none' | Permissions-Policy: geolocation=() |
Feature-Policy: camera 'self' | Permissions-Policy: camera=(self) |
Feature-Policy: microphone * | Permissions-Policy: microphone=* |
Header Syntax
The header uses a structured field format. Each feature is listed with its allowlist:
Permissions-Policy: feature1=(allowlist), feature2=(allowlist), ...Allowlist Values
| Allowlist | Meaning |
|---|---|
* | Any origin — the feature is allowed for the page and all iframes. |
(self) | Same origin only — the feature is allowed for the page itself but not cross-origin iframes. |
() | Nobody — the feature is blocked for the page and all iframes. |
("https://example.com") | Specific origin — allowed only for that origin and the page itself. |
(self "https://widget.example.com") | Same origin plus a specific third-party origin. |
Common Features
| Feature | What It Controls | Recommended Default |
|---|---|---|
camera | Access to device cameras via getUserMedia | () unless your site needs it |
microphone | Access to microphones via getUserMedia | () unless your site needs it |
geolocation | Access to the Geolocation API | () or (self) |
fullscreen | Use of the Fullscreen API | (self) |
payment | Access to the Payment Request API | () or (self) |
autoplay | Autoplay of audio and video | (self) |
usb | Access to USB devices via WebUSB | () |
bluetooth | Access to Bluetooth devices | () |
accelerometer | Access to the device accelerometer sensor | () |
gyroscope | Access to the device gyroscope sensor | () |
magnetometer | Access to the device magnetometer sensor | () |
midi | Access to MIDI devices | () |
picture-in-picture | Use of the Picture-in-Picture API for video | (self) |
screen-wake-lock | Prevent the screen from sleeping | (self) |
display-capture | Screen capture via getDisplayMedia | () |
xr-spatial-tracking | WebXR device access | () |
Recommended Starting Policy
For most websites that do not need device access, a conservative starting policy blocks all sensitive features:
Permissions-Policy: camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=(), autoplay=(self), usb=(), bluetooth=(), accelerometer=(), gyroscope=(), magnetometer=(), midi=(), display-capture=(), xr-spatial-tracking=()Controlling iframe Permissions
Permissions-Policy works in combination with the allow attribute on individual <iframe> elements. The page-level policy sets the maximum possible permissions; the iframe's allow attribute can further restrict (but never expand) what the embedded document receives.
<!-- Grant geolocation to a specific embed only -->
<iframe src="https://maps.example.com/widget"
allow="geolocation 'self' https://maps.example.com">
</iframe>geolocation entirely with geolocation=(), adding allow="geolocation" to an iframe will have no effect. The header takes precedence.Server Configuration
Nginx
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" always;Apache
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()"IIS (web.config)
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" />
</customHeaders>
</httpProtocol>
</system.webServer>Caddy
header Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()"Next.js
// next.config.mjs
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()',
},
],
},
];
},
};
export default nextConfig;Frequently Asked Questions
Does Permissions-Policy replace the iframe sandbox attribute?
They complement each other. The sandbox attribute restricts the iframe's scripting and navigation capabilities, while Permissions-Policy controls access to specific browser features and APIs. Both should be used together for maximum isolation of untrusted embeds.
What happens if I block a feature the page legitimately needs?
Calling a blocked API will result in a SecurityError or a permission denied response from the browser, depending on the API. Users will not see the browser's normal permission prompt for blocked features — the request is rejected before it reaches that stage.
Is Permissions-Policy supported in all browsers?
Permissions-Policy is supported in Chrome, Edge, and Opera. Firefox and Safari have partial support — some features are recognised, others are not. The older Feature-Policy header had different syntax and is being phased out. Where a feature is unsupported, the directive is simply ignored and the browser's default behaviour applies.
Should I combine Permissions-Policy with CSP?
Yes. Permissions-Policy controls device and browser API access; Content Security Policy controls resource loading (scripts, styles, images). They address different threat vectors and complement each other. Both should be in your security headers configuration.