Permissions-Policy Explained
Part of our guide to HTTP Security Headers Explained: The Complete Guide.
The Permissions-Policy header lets you declare exactly which browser features a page and its embedded iframes are allowed to use, and which origins may use them. With one header you can switch off the camera, microphone, geolocation, or payment APIs for your whole site, shrinking both your privacy footprint and your attack surface. It belongs in the same toolkit as the other HTTP security headers explained that harden a site at the response level.
Browsers expose a long list of powerful capabilities, and a compromised script or a sketchy third-party widget can try to reach them. Permissions-Policy is your gatekeeper. It works hand in hand with a content policy, which is why it pairs naturally with the rest of the HTTP security headers explained guide and with CSP explained, the header that governs what scripts can load in the first place.
What it controls
The header governs access to features the user would generally want a say in. Common ones include the camera, microphone, geolocation, payment request API, fullscreen, screen wake lock, accelerometer and other motion sensors, autoplay, and clipboard access. The W3C Permissions Policy specification defines the feature names and the allowlist model, and the OWASP Secure Headers project recommends locking down anything your site does not actively need.
The principle is simple: deny by default, then grant only what a page truly uses. A blog has no business requesting the microphone, so it should say so explicitly.
Allowlist syntax
Each directive is a feature name followed by an allowlist in parentheses. The tokens inside decide who may use the feature.
selfpermits the feature for your own origin.- A quoted origin like
"https://maps.example.com"permits a specific external origin. *permits every origin, including embedded iframes. Use this sparingly.- An empty list, written as
(), permits no one and disables the feature.
You combine directives with commas. A worked example:
Permissions-Policy: geolocation=(self), camera=(), microphone=(), payment=(self "https://pay.example.com"), fullscreen=(self)
That policy lets the page itself use geolocation and fullscreen, fully disables the camera and microphone, and allows payment for the page plus one trusted payment origin. Anything not listed falls back to the browser default for that feature.
It governs iframes too
A key point that catches people out: the policy applies to frames you embed, not just your top-level page. If you set camera=(), an embedded ad or widget cannot quietly prompt the user for camera access through your site. To grant a specific feature to a specific embed, name that origin in the allowlist and, for some features, set the matching allow attribute on the iframe element itself. This nesting model is one of the main reasons the header exists.
It replaced Feature-Policy
Permissions-Policy is the successor to Feature-Policy. If you still ship a Feature-Policy header, treat it as legacy. The newer header uses the structured allowlist syntax shown above instead of the older space-separated origin lists, and it is the version current browsers track. Migrating is usually a matter of rewriting your directives into the new form and dropping the deprecated header.
Common directives at a glance
| Directive | Controls | Disable for all |
|---|---|---|
| camera | Video input devices | camera=() |
| microphone | Audio input devices | microphone=() |
| geolocation | Location access | geolocation=() |
| payment | Payment Request API | payment=() |
| fullscreen | Fullscreen requests | fullscreen=() |
| autoplay | Media autoplay | autoplay=() |
| accelerometer | Motion sensor data | accelerometer=() |
| usb | WebUSB device access | usb=() |
Building a policy is a short process. Inventory the features your pages and embeds genuinely use, set those to self or a named origin, set every other relevant feature to (), then ship the header and watch for console warnings about blocked calls.
After deploying, verify the browser receives the header exactly as written, since a misconfigured directive silently does nothing. The guide on how to check security headers covers how to read back the live value and spot typos before they reach production.
Curious which features a site currently allows? Scan any domain's response headers free at domainintel.app and get a full Permissions-Policy breakdown instantly.
Frequently asked questions
What does Permissions-Policy do?
It controls access to powerful browser features such as camera, microphone, geolocation, payment, and fullscreen, both for the page itself and for any iframes it embeds. You declare an allowlist of origins permitted to use each feature.
What replaced Feature-Policy?
Permissions-Policy is the renamed and updated successor to the older Feature-Policy header. The syntax changed to a structured allowlist format, and Feature-Policy is now deprecated.
How do I disable a feature for everyone?
Give the feature an empty allowlist. Writing geolocation=() blocks geolocation for the page and every embedded frame, since no origin is permitted to use it.