Permissions-Policy
Unrestricted access to browser features like camera, microphone, and geolocation creates privacy and security risks. The Permissions-Policy response header controls which features a page and its embedded iframes are allowed to use.
Baseline: Limited availability
Chromium-based browsers and Firefox support the
Permissions-Policy header. Safari recognizes the
legacy Feature-Policy name for some directives
but does not implement Permissions-Policy syntax.
webstatus.dev
Usage
The Permissions-Policy response header restricts which browser features are allowed in the current frame. Each policy pairs a feature directive with an allowlist defining which Origins access the feature.
Permissions-Policy: <directive>=<allowlist>
Note
A recommended starting policy disables features
the site does not use:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=(). Security scanners flag missing
Permissions-Policy headers. Setting a minimal
policy resolves the finding without affecting
site functionality.
Note
The Permissions-Policy mechanism was previously known as Feature Policy.
Directives
The directive name identifies the browser feature to control. A non-exhaustive list of standardized directives:
accelerometer: device motion sensorautoplay: media autoplaycamera: video captureencrypted-media: Encrypted Media Extensionsfullscreen: fullscreen modegeolocation: location accessgyroscope: orientation sensormagnetometer: magnetic field sensormicrophone: audio capturemidi: Web MIDI APIpayment: Payment Request APIpicture-in-picture: PiP modesync-xhr: synchronous XMLHttpRequestunload: unload event handlersusb: WebUSB API
Note
The interest-cohort directive was used to block
Federated Learning of Cohorts (FLoC). Google
abandoned FLoC in 2022 and replaced the API with
the Topics API. The interest-cohort directive
has been removed from browser implementations.
Allowlist values
The <allowlist> controls which origins use the
feature:
*: all origins(): disabled entirelyself: same origin only"https://example.re": specific origin(self "https://a.example.re"): multiple origins
Note
The unload directive blocks unload event handlers
for the origin. Setting Permissions-Policy: unload=() prevents first-party code, third-party
scripts, and browser extensions from registering
unload handlers. This is significant for
back-forward cache (bfcache) performance because
unload handlers prevent the browser from caching
pages for instant back and forward navigation.
Chrome is gradually deprecating unload events
entirely, beginning with high-traffic sites and
expanding to all sites. Setting unload=() opts
into the deprecation immediately and guarantees
bfcache eligibility regardless of the rollout
schedule.
Example
In the following example, the server indicates the
geolocation feature shall be disabled in all
contexts.
Permissions-Policy: geolocation=()
In the following example, the server indicates the
encrypted-media feature shall be disabled for all
Origins except for report.example.re.
Permissions-Policy: encrypted-media=("https://report.example.re")
In the following example, the server indicates the
microphone feature shall be disabled for all
Origins except itself and those with
origin example.re.
Permissions-Policy: microphone=(self "https://example.re")
Blocking unload handlers to improve bfcache eligibility. This prevents third-party scripts and extensions from registering unload events degrading back-forward navigation performance.
Permissions-Policy: unload=()
Troubleshooting
Permissions-Policy violations appear silently in most cases, with the blocked feature returning a denied state or throwing an error without a visible browser prompt.
Feature blocked in an iframe due to missing
allowattribute. Even when the parent page permits a feature, embedded iframes need an explicitallowattribute to access the feature. Add the attribute to the iframe tag:<iframe src="..." allow="camera; microphone">. Without the attribute, the iframe receives a denied permission state regardless of the HTTP header policy.Geolocation, camera, or microphone not working after setting the policy. A policy like
Permissions-Policy: geolocation=()disables the feature for all origins, including the page itself. To allow the feature on the same origin only, usegeolocation=(self). To allow a specific embedded origin as well, usegeolocation=(self "https://maps.example.re"). The browser never prompts the user for a feature the policy has already denied.Wildcard
*not working for all features. Some features do not support the*allowlist value and are restricted to explicit origin lists. When*has no effect, specify each allowed origin individually. Check the browser console for warnings about unrecognized or unsupported allowlist values.Migrating from Feature-Policy to Permissions-Policy. The legacy Feature-Policy header uses a different syntax:
Feature-Policy: geolocation 'self'vs.Permissions-Policy: geolocation=(self). Browsers that support Permissions-Policy ignore Feature-Policy when both headers are present. Update the header name and convert the syntax: replace spaces with=, wrap origin lists in parentheses, and drop the single quotes aroundselfandnone(use()instead of'none').Debugging with
document.featurePolicy.allowsFeature(). In Chromium-based browsers, open the DevTools Console and rundocument.featurePolicy.allowsFeature('camera')to check whether a feature is allowed in the current context. This returnstrueorfalse. For iframe contexts, pass the origin as a second argument:document.featurePolicy.allowsFeature('camera', 'https://embed.example.re'). Firefox usesdocument.permissionsPolicyinstead ofdocument.featurePolicy.