How to Set the Permissions-Policy Header

Permissions-Policy controls which browser APIs (camera, microphone, geolocation, etc.) are accessible to your page and embedded iframes. This guide shows how to configure it on all major servers and platforms.


The Permissions-Policy header controls which browser features and APIs — camera, microphone, geolocation, and others — can be used by your page and by any embedded iframes. Setting it explicitly blocks features you do not use, preventing malicious or compromised third-party embeds from silently accessing sensitive device capabilities.

Choosing Your Policy

Build your policy by listing each feature with an allowlist. Start with everything blocked and open up only what your application genuinely needs:

Allowlist SyntaxMeaning
feature=()Block entirely — nobody can use this feature
feature=(self)Allow for your own origin only — not embedded iframes
feature=*Allow for all origins
feature=(self "https://widget.example.com")Allow for your origin plus a specific third-party

Recommended Starting Policy

http
Permissions-Policy: camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=(), autoplay=(self), usb=(), bluetooth=(), accelerometer=(), gyroscope=(), magnetometer=(), display-capture=()

Adjust fullscreen and autoplay to () if your site does not use those features either.

Nginx

nginx
server { listen 443 ssl; server_name example.com; add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" always; # ... rest of config }
bash
sudo nginx -t && sudo systemctl reload nginx

Apache

apache
<VirtualHost *:443> <IfModule mod_headers.c> Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" </IfModule> </VirtualHost>

Or in .htaccess:

apache
<IfModule mod_headers.c> Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" </IfModule>
bash
sudo a2enmod headers && sudo systemctl reload apache2

IIS (web.config)

xml
<system.webServer> <httpProtocol> <customHeaders> <add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" /> </customHeaders> </httpProtocol> </system.webServer>

Caddy

Command
example.com { header Permissions-Policy "camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()" # ... rest of config }

Cloudflare (Transform Rules)

  1. Go to RulesTransform RulesModify Response Header.
  2. Add a rule with Operation: Set, Header name: Permissions-Policy.
  3. Enter your policy as the value.
  4. Deploy the rule.

Next.js

javascript
// next.config.mjs const nextConfig = { async headers() { return [ { source: '/(.*)', headers: [ { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()', }, ], }, ]; }, }; export default nextConfig;

Granting Permissions to Specific iframes

If you need a specific embedded widget to access a feature you have blocked globally, you can grant it via the allow attribute on the individual <iframe> element. The page-level Permissions-Policy sets the ceiling — the iframe allow attribute can only restrict further, not expand beyond it.

html
<!-- Allow geolocation only for this specific embed --> <iframe src="https://maps.example.com/embed" allow="geolocation 'src'" ></iframe>
Policy InheritanceIf your Permissions-Policy header blocks geolocation=(), adding allow="geolocation" to an iframe has no effect. The header takes precedence. To allow geolocation in an iframe, your page-level policy must permit at least geolocation=(self) or a specific origin.

Verifying the Header

bash
curl -I https://example.com | grep -i permissions # Expected: permissions-policy: camera=(), microphone=(), ...

Or use the ShowDNS Security Headers Scanner.

Related Articles