Permissions-Policy header
Turns browser features such as camera, microphone, geolocation and payment off for your page and anything it embeds.
Updated 3 November 2026
Check your site's Permissions-Policy header
We send one normal request (following redirects) and grade the Permissions-Policy header on the final response.
Recommended value
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
| Value / directive | What it does |
|---|---|
| feature=() | Disabled for this page and all frames. |
| feature=(self) | Allowed for your own origin only. |
| feature=(self "https://maps.example") | Allowed for your origin and one named third party. Origins go in double quotes. |
| feature=* | Allowed everywhere. Rarely what you want. |
What it protects
Every iframe and third-party script on your page could ask the visitor for powerful permissions: camera, microphone, location, USB devices, payment. If an ad network or compromised widget does it, the prompt appears on your domain. Permissions-Policy lets you switch off what you never use, so those prompts can never appear.
Syntax
The header is a comma-separated list of feature=(allowlist) entries:
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(self "https://checkout.example")
() means nobody, self means your origin, quoted URLs add other origins. You can also delegate a feature to one iframe with the allow attribute: <iframe allow="geolocation">.
Permissions-Policy vs Feature-Policy
Feature-Policy was the earlier draft and used a different syntax (camera 'none'). Current browsers read Permissions-Policy. If you still send Feature-Policy, replace it rather than relying on it.
Which features to list
Disable what you do not use: camera, microphone, geolocation, payment, usb, serial, bluetooth, display-capture. Browsers log a console warning for feature names they do not recognise, which is harmless.
How to set Permissions-Policy
nginx
# inside your server { } block
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()" always;
Apache
# .htaccess or virtual host (needs mod_headers)
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
Laravel middleware
// app/Http/Middleware/SecurityHeaders.php
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$response->headers->set('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=(), usb=()');
return $response;
}
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\App\Http\Middleware\SecurityHeaders::class);
})
Express (Node.js)
app.use((req, res, next) => {
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=(), usb=()');
next();
});
// or: app.use(require('helmet')()) for a sensible default set
Cloudflare
Rules → Transform Rules → Modify Response Header → Create rule.
Match: all incoming requests (or your hostname).
Then: Set static → Header name: Permissions-Policy → Value: camera=(), microphone=(), geolocation=(), payment=(), usb=()
In nginx, an add_header inside a location block discards every add_header inherited from the server block. Repeat your security headers there, or use an include file. The always flag also sends the header on error responses.
Common mistakes
-
Using the old Feature-Policy syntax (
camera 'none') in a Permissions-Policy header. It does not parse. -
Leaving origins unquoted, as in
geolocation=(self https://maps.example). -
Disabling a feature your own checkout or video page needs. Allow
selfon those routes instead. -
Copying
interest-cohort=()from old guides. It was for FLoC, which Chrome dropped.
FAQ
What is the difference between Permissions-Policy and Feature-Policy?
Permissions-Policy is the current standard and uses feature=(allowlist) syntax. Feature-Policy was the earlier version with a different syntax.
Is Permissions-Policy required?
No, but it is a quick way to cut off camera, microphone and location prompts from embedded third-party content.
Related guides
Headers are one of 30+ things attackers check
The free StackShield scan also checks for exposed .env files, debug mode, leaked tooling, weak TLS and more, from the outside, in about a minute.
Run a free scan