Permissions-Policy Header Generator
Build a correct Permissions-Policy HTTP
header. Allowlist or block 30+ browser features (camera, microphone, geolocation,
clipboard, USB, payment, fullscreen…) and copy ready-to-paste Nginx, Apache, Express, or
CDN snippets.
Quick Presets
Features (33)
Sensors
accelerometer
Motion sensor data.
ambient-light-sensor
Ambient light reading.
gyroscope
Device gyroscope data.
magnetometer
Magnetic field data.
Media
camera
Access to camera devices.
microphone
Access to microphones.
autoplay
Auto-playing audio/video.
display-capture
Screen capture / getDisplayMedia().
encrypted-media
Encrypted Media Extensions (DRM).
fullscreen
Element.requestFullscreen().
picture-in-picture
Picture-in-picture for video.
speaker-selection
Choose which audio output to use.
screen-wake-lock
Keep the screen on with Wake Lock API.
Identity
geolocation
navigator.geolocation.
idle-detection
Idle Detection API.
publickey-credentials-create
WebAuthn credential creation.
publickey-credentials-get
WebAuthn credential retrieval.
otp-credentials
WebOTP API for SMS one-time passwords.
Storage
clipboard-read
Read from the clipboard.
clipboard-write
Write to the clipboard.
storage-access
Storage Access API for cross-site cookies.
Hardware
usb
WebUSB device access.
serial
Web Serial API.
hid
WebHID API.
midi
Web MIDI API.
gamepad
Gamepad input.
battery
Battery Status API.
xr-spatial-tracking
WebXR head/hand tracking.
window-management
Multi-screen Window Management API.
Other
payment
Payment Request API.
web-share
navigator.share().
browsing-topics
Topics API for interest-based ads.
cross-origin-isolated
Cross-origin isolation (SharedArrayBuffer).
Output
Header Value
accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()
Full HTTP Header
Permissions-Policy: accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()
Nginx
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()" always;
Apache (.htaccess)
Header set Permissions-Policy "accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()"
Express / Node.js
res.setHeader('Permissions-Policy', 'accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()');Cloudflare Page Rule
# Cloudflare Page Rule / Transform Rule Permissions-Policy: accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()
HTML <meta> tag
<meta http-equiv="Permissions-Policy" content="accelerometer=(), ambient-light-sensor=(), gyroscope=(), magnetometer=(), camera=(), microphone=(), autoplay=(), display-capture=(), encrypted-media=(), fullscreen=(), picture-in-picture=(), speaker-selection=(), screen-wake-lock=(), geolocation=(), idle-detection=(), publickey-credentials-create=(), publickey-credentials-get=(), otp-credentials=(), clipboard-read=(), clipboard-write=(), storage-access=(), usb=(), serial=(), hid=(), midi=(), gamepad=(), battery=(), xr-spatial-tracking=(), window-management=(), payment=(), web-share=(), browsing-topics=(), cross-origin-isolated=()" />
About the Permissions-Policy Header Generator
The Permissions-Policy Header Generator builds the HTTP Permissions-Policy response header — the W3C-standard way to allow, restrict, or completely block specific
browser features on your site and any iframes embedded within it. Each known feature is
exposed as a four-state toggle (Block / Self / All / Custom origins) and the final header
updates live as you change it.
Permissions-Policy is a defense-in-depth
security and privacy header. It does not prevent malicious code from running, but it does let you tell the browser "even if some script tries to call navigator.geolocation or open the camera, deny
that access at the platform level." It is also the only practical way to neuter cookieless
tracking surfaces like browsing-topics and interest-cohort across your entire site.
This generator runs entirely in your browser. Nothing is uploaded — your feature list, origins, and tweaks stay on your device.
Allowlist Cheat Sheet
| Allowlist | Meaning |
|---|---|
| () | Empty allowlist — feature is fully disabled, including for the page itself. |
| (self) | Allowed only on the document's own origin (and same-origin iframes). The most common safe default. |
| * | Allowed for every origin, including any iframe. Use sparingly — equivalent to "no restriction." |
| (self "https://x.com") | Allowed for the page itself plus the listed origins. Origins must be quoted strings. |
How to Use the Permissions-Policy Header Generator
- Pick a Quick Preset matching your site type (lock-down baseline, marketing site, WebRTC app, maps app), or build a header from scratch.
- For each feature, click one of the four mode pills: Block () empties the allowlist, Self restricts to the page's own origin, All (*) opens it to every origin, and Custom lets you list specific origins.
- When you choose Custom, type a space- or comma-separated list of origins
in the input that appears below — for example
self https://maps.google.com. The tool quotes origins automatically. - Watch the Header Value banner update live. Use the All Block / All Self / Reset buttons at the top to apply a single mode to every feature in one click.
- Copy the value or pick a server-specific snippet (Nginx
add_header, ApacheHeader set, Expressres.setHeader, Cloudflare Page Rule, or HTML<meta>). - Verify the live header in DevTools → Network → your document → Response Headers, or in
chrome://settings/content's per-site permissions UI.
Frequently Asked Questions
What is the difference between () and not
listing the feature at all?
() explicitly disables the feature for
everyone, including the top-level document. Omitting the feature falls back to the
browser's default policy, which for most features is self — meaning the page can use it but
cross-origin iframes cannot. If you really want to opt out, use ().
Permissions-Policy vs Feature-Policy — which one do I send?
Feature-Policy is the deprecated 2018-era
predecessor. It used a different syntax (geolocation 'none' instead of geolocation=()). All modern
browsers honour Permissions-Policy — send only that. Don't send both, and never send Feature-Policy by itself.
Does the HTML <meta> tag actually
work?
Partially. A <meta http-equiv="Permissions-Policy"> tag is honoured by Chromium-based browsers but only supports allowlists that don't
include cross-origin URLs (so self works, "https://example.com" does not). The HTTP
response header is the only fully-supported delivery mechanism — use <meta> only as a fallback when you
cannot change server config.
What about iframe allow= attributes?
Iframes use a related but different mechanism: <iframe allow="camera; microphone"> grants those features to the embedded document, but only up to the limits set by the
parent page's Permissions-Policy. The header is the upper bound; the iframe attribute is the per-frame opt-in. This generator
produces the parent header — once that allows self, you can hand specific iframes the
ability to use the feature via allow.
What is browsing-topics and should I
block it?
Topics is part of Chrome's Privacy Sandbox — it lets sites infer interest categories
about the user. Many sites disable it via browsing-topics=() to opt out of contributing data to advertisers. The "Lock everything down" preset
blocks it by default.
Why is my getUserMedia() failing after I
added the header?
The most common reason: you set camera=() or microphone=() instead of camera=(self). The empty allowlist blocks
the feature even on your own origin. Switch to Self for any feature your top-level page actually uses.
Is data sent to a server?
No. The generator runs entirely in your browser; everything you type stays on your device. There is no signup, no telemetry, and no upload.