Builder decision rules
The rules the Permissions-Policy builder follows to turn feature reports into grants, flag noise and third-party scripts, and write the header value.
Last update:
The Permissions-Policy builder suggests every grant from rules you can check. Knowing them tells you when to trust a default and when to overrule it.
From a report to a grant
The builder reads two report types. Each report names a feature and who asked for it, and the builder turns that into the grant that would allow it:
| Browser reported | Suggested grant |
|---|---|
| A Permissions-Policy violation: one of your pages used the feature | self |
A potential-permissions-policy-violation: an iframe from another origin asked for the feature in its allow attribute | The frame's origin, such as "https://pay.example.com", flagged From frame |
A potential violation from a frame with no origin (a relative src or a srcdoc frame), or from your own origin | self |
The builder grants origins, not full URLs. A frame from https://pay.example.com/checkout?step=2 becomes a grant to https://pay.example.com.
Both report types can be forged by anyone who knows your endpoint. A feature name the header grammar does not allow, or a frame src that is not a plain http or https origin, never becomes a row, so it cannot reach a generated header.
Frames and potential violations
An iframe asks for a feature in its allow attribute. The browser reports that request as a potential violation, which the Permissions Policy reports page shows in its Potential view:
<iframe src="https://video.example.com/embed/42" allow="fullscreen; autoplay"></iframe>This frame produces one row under fullscreen and one under autoplay, both for https://video.example.com. Delegating a feature takes both halves: the header grants it to the frame's origin, and the iframe keeps naming it in allow. For the header and attribute model, refer to the iframe allow attribute. When you grant a feature to a frame origin, the deploy step shows Frames need their allow attribute too as a reminder.
Third-party scripts
For a feature your own pages used, the reports name the script that made each call. The builder sorts each script into one of three groups: your own code (served from your website's origin), another origin's script, or a browser extension.
When every call came from another origin's script or an extension, the self row is flagged Third-party script and starts rejected. Granting the feature to self would hand it to that script too, because a script runs with the permissions of the page that loads it. When at least one call came from your own code, the row starts granted.
Noise
Noise is a reported row that your site does not need. The builder flags a row as noise in either of these cases:
- It has fewer than 10 reports in the period.
- Every call behind it came from a browser extension, which runs on the visitor's machine, not on your site.
The details panel also notes when only one browser reported a row while your site sees several, but that signal never makes a row noise on its own. Only Chromium browsers send these reports, so most sites see a single browser.
Noise starts rejected, but it is only a default. A rarely used page, such as a yearly campaign, can report a feature fewer than 10 times and still need it. Check the Noise filter before you deploy.
Starting presets
Browsers never report the Permissions-Policy a page was served with, so the builder cannot detect the policy you send today. It starts from one of these:
| Starting policy | Value |
|---|---|
| Deny every listed feature (default) | Every feature of the catalog set to () |
| Payment page baseline | payment=(self) and publickey-credentials-get=(self), every other catalog feature set to () |
| Allow camera and microphone | camera=(self), microphone=(self), and fullscreen=(self), every other catalog feature set to () |
| Your own policy | The value you paste, up to 16,384 characters |
A grant from the starting policy stays granted, even when the reports flag it. The review then adds what your site was reported using.
When you paste your own policy
The builder reads the value as a Permissions-Policy header value, without the header name:
- Every feature it sets is kept, including features outside the catalog.
- In each allowlist, it keeps
self,src,*, and plainhttporhttpsorigins, and drops anything else. - It drops parameters such as
report-to, and ignores a member that is notfeature=allowlist. - A catalog feature your policy does not set keeps the browser default, unless the reports or your decisions add it.
A pasted policy lives only in the open page. After a reload, the builder falls back to Deny every listed feature.
Feature catalog
The builder lists 25 features, the ones broadly shipped and meaningful to lock down. The presets set all of them, so the header denies every one you do not grant:
| Feature | What it lets a page do |
|---|---|
accelerometer | Read the motion sensor behind tilt and shake gestures |
autoplay | Start video and audio without the visitor pressing play |
browsing-topics | Share the interests the browser inferred from the visitor's history with ad scripts (the Topics API) |
camera | Use the device's camera, once the visitor allows it |
clipboard-read | Read what the visitor copied to the clipboard |
clipboard-write | Write to the clipboard, as a Copy button does |
display-capture | Capture the screen or a window, as screen sharing does |
encrypted-media | Play DRM-protected video or audio through Encrypted Media Extensions |
fullscreen | Show an element full screen, such as a video player or a gallery |
gamepad | Read game controllers |
geolocation | Read the visitor's location, once they allow it |
gyroscope | Read the device's orientation sensor |
idle-detection | Detect when the visitor is idle or has locked the screen |
local-fonts | List and use the fonts installed on the visitor's device |
magnetometer | Read the device's compass sensor |
microphone | Use the device's microphone, once the visitor allows it |
midi | Talk to MIDI devices such as music keyboards |
payment | Open the browser's own checkout sheet (the Payment Request API) |
picture-in-picture | Play a video in a floating window above other apps |
publickey-credentials-get | Sign the visitor in with a passkey or a security key |
screen-wake-lock | Keep the screen on, such as while a boarding pass is shown |
serial | Talk to serial devices plugged into the computer |
storage-access | Let embedded third-party content ask for access to its own cookies |
usb | Talk to USB devices plugged into the computer |
xr-spatial-tracking | Run virtual and augmented reality sessions (WebXR) |
A reported feature outside the catalog gets its own group in the review table too, after the catalog features. It ends up in the header either granted or as ().
How the header is written
The builder writes the policy as one comma-separated line:
- Features come in catalog order, then any other feature in alphabetical order, so the header reads the same from any start.
- A feature with nothing granted is written
(), which denies it everywhere, including in frames. selfcomes first in an allowlist, then each origin in double quotes.- A feature granted to
*is written*alone, whatever else it lists. - No
report-toparameter is written. The reports go to thedefaultendpoint of theReporting-Endpointsheader, which the builder declares next tocentralcsp.
For example, a policy that grants payment to your pages and to a payment frame, and denies the rest, reads like this, shortened here to five features:
Permissions-Policy-Report-Only: accelerometer=(), autoplay=(), browsing-topics=(), camera=(), payment=(self "https://pay.example.com")The real header lists every catalog feature. For the full example, refer to Get started.
Periods and limits
The builder reads up to the last 30 days of reports. A website that sends a very large volume of reports is limited to 7 days at a time.
On such a website, the Period step says This website sends a lot of reports, so the builder reads only its last 7 days, and the 14 days and 30 days options are hidden. If a period holds more reports than the builder can read in time, the page shows This period holds too many reports to analyze in time. Pick a shorter period. Pick fewer days and continue.
The API applies the same rules. The Build a recommended Permissions-Policy endpoint defaults to the last 7 days and covers up to 30. Without a starting policy, it starts from Deny every listed feature. Each user can call it 10 times per minute. Refer to the API reference.
Next steps
Review table
The Permissions-Policy builder review table decides which features your pages and frames may use. Columns, flags, defaults, filters, and details.
Overview
Generate a Connection-Allowlist header from the reports browsers send. Start from your own origin, allow the destinations you recognize, then deploy.