Permissions-Policy is an HTTP response header that gives website owners fine-grained control over which browser features and APIs can be used on their pages, and crucially, which features embedded third-party content is allowed to access. If you have ever wondered how an ad inside an iframe might silently request access to your visitor's camera or microphone, Permissions-Policy is the mechanism designed to prevent exactly that.
The header was originally introduced under the name Feature-Policy. Browsers began shipping support for it around 2018, but the specification went through significant changes, and the header was eventually renamed to Permissions-Policy with a new syntax. Today, most modern browsers recognize the Permissions-Policy header, though some older browsers may still only understand the legacy Feature-Policy format. If you want maximum compatibility, you can send both headers, but Permissions-Policy is the one to prioritize going forward.
Which Browser Features Can Be Controlled
The list of features you can restrict through Permissions-Policy is surprisingly long, and it keeps growing as browsers add new capabilities. Here are the most relevant ones for WordPress site owners:
camera: controls access to the device's camera. Relevant if you run a membership site with video uploads or a plugin that offers webcam-based profile photos.microphone: controls access to audio recording. Voice search plugins, podcast recording tools, and live chat widgets sometimes request this.geolocation: controls access to the visitor's GPS or network-based location. Store locator plugins, map widgets, and location-aware content delivery may request this.payment: controls the Payment Request API, which lets websites trigger native browser payment dialogs. WooCommerce and other e-commerce plugins can use this for streamlined checkout.fullscreen: controls whether embedded content can request fullscreen mode. Video players, gallery lightboxes, and presentation plugins typically need this.autoplay: controls whether media elements can play automatically. This affects background video headers, auto-playing sliders, and embedded YouTube or Vimeo players.display-capture: controls screen sharing capabilities. This is mostly relevant for conferencing or support tools embedded on your site.usb: controls the WebUSB API. Rarely needed on typical WordPress sites, but sometimes used by specialized hardware integration plugins.bluetooth: controls Web Bluetooth access. Similar to USB, this is niche but worth restricting by default.interest-cohort: this was used to opt out of Google's FLoC tracking proposal. While FLoC has been replaced by the Topics API, many sites still send this directive.
How the Syntax Works
The Permissions-Policy header uses a straightforward syntax. Each feature is followed by an allowlist in parentheses. Empty parentheses mean the feature is completely disabled for everyone, including your own page:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()If you want to allow a feature for your own origin but block it for all embedded third-party content, you use the self keyword:
Permissions-Policy: camera=(self), geolocation=(self "https://maps.example.com")In this example, your own pages can access the camera, and geolocation is available to both your origin and a trusted maps provider. Every other embedded origin is blocked from using those features. You can also use * to allow all origins, but that defeats the purpose of setting the header in the first place.
How Third-Party Iframes Abuse Browser Permissions
The primary threat model behind Permissions-Policy is the embedded iframe. When you include an ad network, a social media widget, a chat tool, or any other third-party embed on your WordPress site, that embed runs inside an iframe with its own execution context. Without a Permissions-Policy header, the browser treats that iframe almost like a first-party page when it comes to feature access.
This means a poorly coded or outright malicious ad creative could call navigator.mediaDevices.getUserMedia() to request camera or microphone access. The browser would show a permission prompt to the visitor, but the prompt just says the site is requesting access. Most users would not realize the request is coming from an embedded ad rather than from the actual website they are visiting. If they click "Allow," the ad now has a live video or audio feed.
Geolocation abuse is even more subtle. Some ad networks have been caught requesting location data to build more detailed user profiles. Payment API abuse is less common but potentially more dangerous, as it could trigger misleading payment dialogs. By setting a strict Permissions-Policy, you cut off all these vectors at the browser level, regardless of what JavaScript the embed tries to run.
The Relationship to the Older Feature-Policy Header
If you have seen references to Feature-Policy and wondered whether it is the same thing: yes, essentially. Feature-Policy was the original name and used a slightly different syntax. Instead of camera=(self), the old format looked like camera 'self'. The Feature-Policy header was supported by Chrome, Firefox, and other browsers starting around 2018.
The W3C eventually redesigned the specification with a cleaner syntax and renamed it to Permissions-Policy. Chrome switched to the new header in version 88 (January 2021). Firefox followed later. As of today, Feature-Policy is considered deprecated. Most security scanners and tools (including InspectWP) check for the Permissions-Policy header specifically. If your server still sends the old Feature-Policy header, it will generally still work in browsers that support it, but you should plan to migrate to the new format.
WordPress-Specific Considerations
WordPress sites are particularly affected by Permissions-Policy because of how the plugin ecosystem works. A typical WordPress site might have 15 to 30 active plugins, and many of them inject iframes or load third-party scripts. Here are common scenarios where Permissions-Policy matters:
- Contact form plugins with file upload fields that offer camera capture on mobile devices.
- WooCommerce checkout pages that integrate with payment gateways via iframes.
- Google Maps embeds that request geolocation to show the user's position.
- Video conferencing plugins (for online courses or support) that need camera and microphone access.
- Ad management plugins that embed ad network iframes throughout your pages.
The right approach is to start with a restrictive policy that disables everything, then selectively enable features your site actually needs. This way, even if a plugin loads a third-party iframe you did not expect, the browser will block it from accessing sensitive features.
How to Set the Permissions-Policy Header in WordPress
You can add the header through your web server configuration or via a WordPress plugin. For Apache, you would add a line to your .htaccess file:
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=()"For Nginx, the equivalent goes into your server block:
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=()" always;Security plugins like HTTP Headers, Really Simple Security, or Perfmatters also offer UI-based controls for setting the Permissions-Policy header without touching server configuration files.
What InspectWP Checks
InspectWP analyzes whether your WordPress site sends a Permissions-Policy header in its HTTP responses. If the header is missing, the report flags this as a security concern because embedded third-party content (ads, widgets, iframes) may be able to access sensitive browser features like the camera, microphone, or geolocation without any restrictions. The report also shows the raw header value so you can verify which features are currently restricted.