Permission-Policy example
Complete guide to implementing Permissions-Policy (formerly Feature-Policy) headers for controlling browser features and enhancing privacy.
What is Permissions-Policy?
Permissions-Policy allows you to control which browser features and APIs can be used on your website, preventing misuse of powerful features like camera, microphone, geolocation, etc.
Basic Syntax
Header always set Permissions-Policy "feature-name=(allowed-origins)"
Common Features
Deny All Features
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Allow for Self Only
Permissions-Policy: camera=(self), microphone=(self), geolocation=(self)
Allow for Specific Domains
Permissions-Policy: camera=(self "https://trusted-domain.com")
Complete Feature List
Sensors & Hardware
Permissions-Policy: accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=()
Media Devices
Permissions-Policy: camera=(), microphone=(), speaker-selection=(), display-capture=()
Location & Motion
Permissions-Policy: geolocation=(), screen-wake-lock=()
Payments & Identity
Permissions-Policy: payment=(), identity-credentials-get=()
Connectivity
Permissions-Policy: usb=(), serial=(), bluetooth=(), hid=()
Other Features
Permissions-Policy: fullscreen=(self), picture-in-picture=(self), autoplay=(self)
Real-World Examples
Strict Security (Block Everything)
Header always set Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"
Standard Website
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Video Conferencing Site
Permissions-Policy: camera=(self), microphone=(self), display-capture=(self), fullscreen=(self), speaker-selection=(self)
E-Commerce Site
Permissions-Policy: payment=(self), geolocation=(self), camera=(), microphone=()
Gaming/VR Site
Permissions-Policy: fullscreen=(self), gamepad=(self), xr-spatial-tracking=(self), accelerometer=(self), gyroscope=(self)
Feature Descriptions
| Feature | Description |
|---|---|
accelerometer |
Device acceleration sensor |
ambient-light-sensor |
Ambient light detection |
autoplay |
Autoplay media |
camera |
Camera access |
display-capture |
Screen sharing/capture |
fullscreen |
Fullscreen mode |
geolocation |
GPS location |
gyroscope |
Device rotation sensor |
magnetometer |
Compass sensor |
microphone |
Microphone access |
midi |
MIDI device access |
payment |
Payment Request API |
picture-in-picture |
PiP video mode |
speaker-selection |
Audio output selection |
usb |
USB device access |
web-share |
Web Share API |
xr-spatial-tracking |
VR/AR tracking |
Implementation
Apache (.htaccess)
<IfModule mod_headers.c>
Header always set Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
</IfModule>
Nginx
add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always;
IIS (web.config)
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Permissions-Policy" value="accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" />
</customHeaders>
</httpProtocol>
</system.webServer>
Testing
Check in Browser DevTools
- Open DevTools (F12)
- Go to Console tab
- Attempt to use a blocked feature
- You'll see permission denied errors
Test Geolocation
navigator.geolocation.getCurrentPosition(
position => console.log(position),
error => console.error('Blocked by Permissions-Policy')
);
Test Camera
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => console.log('Camera allowed'))
.catch(error => console.error('Camera blocked'));
Legacy Feature-Policy
Older browsers used Feature-Policy instead:
Header always set Feature-Policy "camera 'none'; microphone 'none'; geolocation 'none'"
Note: Use both headers for maximum compatibility:
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Feature-Policy "camera 'none'; microphone 'none'; geolocation 'none'"
Iframe Integration
Control features in embedded iframes:
<iframe src="https://example.com" allow="camera; microphone"></iframe>
Best Practices
- Block Unnecessary Features - Only allow what you need
- Be Specific - Use
selfinstead of*when possible - Test Thoroughly - Ensure legitimate features still work
- Document Allowed Features - Keep track of why each feature is allowed
- Review Regularly - Remove permissions for deprecated features
Common Configurations
Blog/News Site
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Corporate Website
Permissions-Policy: accelerometer=(), camera=(), geolocation=(self), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Social Media Platform
Permissions-Policy: camera=(self), microphone=(self), geolocation=(self), fullscreen=(self), picture-in-picture=(self)
Security Headers Combination
Combine with other security headers:
Header always set Content-Security-Policy "default-src 'self'"
Header always set Permissions-Policy "camera=(), microphone=()"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=31536000"
Checking Your Configuration
Test your headers at:
Additional Resources
Related Security Headers
- Content-Security-Policy - Control content sources
- X-Frame-Options - Clickjacking protection
- Referrer-Policy - Control referrer information