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.

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>

Directives

The directive name identifies the browser feature to control. A non-exhaustive list of standardized directives:

  • accelerometer: device motion sensor
  • autoplay: media autoplay
  • camera: video capture
  • encrypted-media: Encrypted Media Extensions
  • fullscreen: fullscreen mode
  • geolocation: location access
  • gyroscope: orientation sensor
  • magnetometer: magnetic field sensor
  • microphone: audio capture
  • midi: Web MIDI API
  • payment: Payment Request API
  • picture-in-picture: PiP mode
  • sync-xhr: synchronous XMLHttpRequest
  • unload: unload event handlers
  • usb: WebUSB API

Allowlist values

The <allowlist> controls which origins use the feature:

  • *: all origins
  • (): disabled entirely
  • self: same origin only
  • "https://example.re": specific origin
  • (self "https://a.example.re"): multiple origins

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.

  1. Feature blocked in an iframe due to missing allow attribute. Even when the parent page permits a feature, embedded iframes need an explicit allow attribute 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.

  2. 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, use geolocation=(self). To allow a specific embedded origin as well, use geolocation=(self "https://maps.example.re"). The browser never prompts the user for a feature the policy has already denied.

  3. Wildcard * granting less than expected. Every policy-controlled feature accepts the * allowlist, which makes the feature available to the document and to any origin it delegates to. The wildcard does not skip user consent: features like camera or geolocation still trigger the normal permission prompt. Cross-origin iframes also still need the allow attribute from item 1 before the wildcard applies to them. Check the browser console for warnings about unrecognized or unsupported allowlist values.

  4. 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 around self and none (use () instead of 'none').

  5. Debugging with document.featurePolicy.allowsFeature(). In Chromium-based browsers, open the DevTools Console and run document.featurePolicy.allowsFeature('camera') to check whether a feature is allowed in the current context. This returns true or false. For iframe contexts, pass the origin as a second argument: document.featurePolicy.allowsFeature('camera', 'https://embed.example.re'). Firefox exposes document.featurePolicy only behind the dom.security.featurePolicy.webidl.enabled preference, so this debugging technique works by default in Chromium-based browsers.

See also

Last updated: August 11, 2026