Permissions-Policy
Discover how Permissions-Policy controls browser features and API access for enhanced security.
Permissions-Policy (formerly Feature-Policy) is a HTTP header that allows you to control which browser features and APIs can be used by your website and any embedded content. This helps reduce your attack surface and protects user privacy.
Why Control Browser Features?#
Modern browsers expose powerful APIs including camera, microphone, geolocation, payment processing, USB access, and more. While these APIs enable rich user experiences, they also create attack surface. If your website does not use the camera, there is no reason for third-party scripts or iframes on your page to have access to it. Permissions-Policy lets you explicitly disable features you do not need.
- Third-party scripts embedded via ads or analytics could access sensitive browser APIs
- Malicious iframes can request permissions that appear to come from your domain
- Disabling unused features reduces your attack surface and protects user privacy
- The header replaces the older Feature-Policy header with an improved syntax
Permissions-Policy was previously called Feature-Policy. The new header uses a different syntax (structured headers format). Most browsers now support Permissions-Policy, though some older versions only recognize Feature-Policy.
How Permissions-Policy Works#
The header uses a structured syntax where each directive controls a specific browser feature. For each feature, you specify an allowlist of origins that can use it. Empty parentheses () mean no origin is allowed, (self) means only your own origin, and you can list specific trusted domains.
- Each feature is controlled independently with its own allowlist
- Empty parentheses () disable the feature for all origins including your own
- (self) allows the feature only for your own origin
- You can list specific external origins that should have access
- The * wildcard allows all origins (defeats the purpose for most features)
# Syntax breakdown
Permissions-Policy: feature-name=(allowlist)
# Examples
camera=() # Disabled for everyone
camera=(self) # Only your origin
camera=(self "https://meet.example.com") # Your origin + specific domain
camera=* # All origins (not recommended)Common Features to Control#
There are dozens of features you can control with Permissions-Policy. Here are the most commonly configured ones and when you should enable or disable them.
- camera, microphone: Disable unless your app uses video/audio features
- geolocation: Disable unless your app needs location services
- payment: Disable unless you use the Payment Request API
- usb, bluetooth, serial: Disable unless you have specific hardware integration needs
- autoplay: Control whether media can auto-play on your pages
- fullscreen: Usually safe to allow for self, restrict for third-party iframes
- interest-cohort: Disable to opt out of Google's Federated Learning of Cohorts (FLoC)
Implementation Guide#
Start by disabling all features your site does not use, then selectively enable what you need. This deny-by-default approach provides the strongest security posture.
# Apache (.htaccess)
Header always set Permissions-Policy "\
camera=(), microphone=(), geolocation=(), \
payment=(), usb=(), interest-cohort=()"
# Nginx
add_header Permissions-Policy \
"camera=(), microphone=(), geolocation=(),
payment=(), usb=(), interest-cohort=()" always;
# Node.js / Express
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'camera=(), microphone=(), geolocation=(), ' +
'payment=(), usb=(), interest-cohort=()');
next();
});Permissions-Policy and Iframes#
One of the most valuable uses of Permissions-Policy is controlling what embedded iframes can do. Even if a third-party iframe requests camera or microphone access, Permissions-Policy can block it at the document level. You can also use the iframe allow attribute for per-element control.
The HTTP header sets the outermost boundary. The iframe allow attribute can further restrict (but not expand) what the header allows. This layered approach gives you both site-wide defaults and per-element granularity.
<!-- Allow camera only for a specific iframe -->
<iframe src="https://meet.example.com"
allow="camera; microphone"
sandbox="allow-scripts allow-same-origin">
</iframe>
<!-- The header-level policy still applies as an outer boundary -->
<!-- If the header says camera=(), the iframe allow attribute cannot override it -->Best Practices#
Follow these guidelines for an effective Permissions-Policy configuration that balances security with functionality.
- Start with all sensitive features disabled and only enable what your application needs
- Use (self) rather than * for features your site uses to prevent third-party access
- Audit third-party scripts and iframes to understand what permissions they require
- Test your policy in a staging environment before deploying to production
- Review and update your policy when adding new third-party integrations
- Use the Permissions Policy Generator tool to build your policy visually
Implementation Examples#
Block All Features
Permissions-Policy: camera=(), microphone=(), geolocation=()Disables camera, microphone, and geolocation for all origins
Explanation: Empty parentheses () mean no origins are allowed to use these features, providing maximum privacy.
Allow for Self Only
Permissions-Policy: camera=(self), microphone=(self)Allows features only for your own origin
Explanation: The 'self' keyword refers to your own domain. Third-party embedded content cannot access these features.
Allow Specific Domains
Permissions-Policy: camera=(self "https://trusted-video.com")Allows features for your site and specific trusted domains
Explanation: You can specify multiple origins that are allowed to use sensitive browser features.
Key Directives#
camera
Controls access to camera API
camera=()microphone
Controls access to microphone API
microphone=()geolocation
Controls access to geolocation API
geolocation=()payment
Controls access to payment request API
payment=(self)References#
Test Your Permissions-Policy Configuration
Scan your site to check if Permissions-Policy is properly configured.