Permissions-Policy Header Behavior for AI Crawlers
Permissions-Policy is an HTTP response header that allows a site to declare which browser features its documents and embedded iframes may use. AI crawlers that perform headless renders inherit the same enforcement semantics as browsers, so a tight policy can silently break the hydration and content extraction that AI search engines depend on to cite a page.
TL;DR
Use Permissions-Policy to gate features such as geolocation, camera, microphone, clipboard-read, and the newer browsing-topics directive. Default-deny policies are safe for sensitive features but should leave script-execution adjacent features alone, because AI crawlers run headless renders before extracting content. Migrate any remaining Feature-Policy headers to Permissions-Policy syntax—per MDN's Permissions-Policy reference and the W3C Permissions Policy Working Draft, the new header is the successor and uses a structured-fields list grammar.
Definition
Permissions-Policy is an HTTP response header defined by the W3C Permissions Policy specification (Working Draft, October 2025). It supersedes the legacy Feature-Policy header and uses a structured-fields list grammar where each directive is a feature name followed by an allowlist:
Permissions-Policy: geolocation=(), camera=(self), browsing-topics=()
Each allowlist value can be * (any origin), self (same-origin), () (none), or one or more quoted origins. The header's policy applies to the document it returns and is inherited by embedded iframes unless the iframe carries its own allow attribute. A companion header, Permissions-Policy-Report-Only, exists for staged rollout and reports violations without enforcing them.
Permissions-Policy is similar in shape to Content Security Policy but controls browser-feature access rather than resource loading. Browsers that honor the policy will return a NotAllowedError from blocked APIs; non-supporting browsers ignore the header silently.
Why this matters
AI search engines and answer engines do not just fetch HTML. Most modern crawlers—including Googlebot, GPTBot, PerplexityBot, ClaudeBot, and Bing's crawlers—run a headless rendering pass to evaluate JavaScript and extract the rendered DOM. That headless renderer enforces Permissions-Policy the same way a normal browser does. A policy that disables a feature your hydration depends on (for example, an analytics SDK that reads navigator.userAgent data via the client-hints directive, or a third-party widget that relies on clipboard-read for embedded examples) can cause silent JavaScript errors that break extraction.
The practical effect is twofold: pages with overly restrictive Permissions-Policy settings can render an empty or partial DOM to the AI crawler, which translates into missing citations, and pages with too-permissive policies expose iframe content to features they should not have. The right answer is to reason about each directive on its merits, not to default-deny everything because security tooling suggests it.
Directive reference (AI-relevant subset)
| Directive | Default | AI crawler impact | Recommended policy |
|---|---|---|---|
| geolocation | () (deny) | Low — no AI crawler requests location. | Keep () unless your page needs it. |
| camera, microphone | () | Low — not used by crawlers. | Keep (). |
| clipboard-read, clipboard-write | () | Medium — some embedded code-sample widgets depend on these. | (self) if widgets need them, else (). |
| browsing-topics | * | High — controls Topics API access; crawlers that read topical signals are affected. | (self) for tighter control, () to opt out completely. |
| interest-cohort (FLoC) | * | Deprecated; safe to set (). | (). |
| language-detector, translator | * | Medium — used by experimental Translator/Language Detector APIs in the headless pass. | (self) if you use them, else (). |
| web-share | (self) | Low. | Keep default. |
| encrypted-media | (self) | Low. | Keep default unless you embed DRM iframes. |
| fullscreen | (self) | Low. | Keep default. |
| accelerometer, gyroscope, magnetometer | () | Low. | Keep (). |
The full directive list is enumerated by MDN's Permissions-Policy reference. Directives evolve—browsing-topics and language-detector were added relatively recently—so audit the active list against the W3C draft annually.
Migration from Feature-Policy
The legacy Feature-Policy header used a different syntax (Feature-Policy: geolocation 'none') and was deprecated by the W3C and Chrome in 2020. Both Scott Helme and HTTP Toolkit documented the migration. The structured-fields grammar in Permissions-Policy differs in three ways: feature names use hyphenation (geolocation vs geolocation), allowlists use parentheses with quoted origins, and combining multiple directives uses comma separation rather than semicolons. Keep Feature-Policy only if you still serve traffic to user agents that have not implemented the successor.
Practical application
A reasonable starter policy for a content site that wants to remain AI-search friendly:
Permissions-Policy: geolocation=(), camera=(), microphone=(), accelerometer=(), gyroscope=(), magnetometer=(), payment=(), usb=(), browsing-topics=(self), interest-cohort=()
A five-step rollout:
- Inventory features used. Audit your front-end and third-party widgets to list every browser feature they call.
- Stage with Permissions-Policy-Report-Only. Deploy the candidate policy in report-only mode and collect violation reports from your real browsers and your headless test pipeline.
- Run an AI-crawler simulation. Render the page in a headless Chromium with the new policy applied; confirm the DOM hydrates fully and your structured data renders.
- Promote to enforcing mode. Replace Permissions-Policy-Report-Only with Permissions-Policy.
- Re-validate quarterly. Re-audit when adding new third-party widgets, when the W3C publishes new directives, or when AI crawlers update their render stack.
Common mistakes
- Default-denying every directive. A blanket *=() style policy can disable features your own hydration relies on. Reason directive-by-directive.
- Forgetting iframe allowlists. Embedded
- Conflicting CSP and Permissions-Policy. CSP controls resource loading; Permissions-Policy controls feature access. Both can break a render; debug them independently in DevTools.
- Treating Permissions-Policy as anti-bot defense. It is not—non-browser crawlers can ignore it. Use Cloudflare AI Crawl Control or robots.txt for crawler-level access decisions.
- Stale Feature-Policy co-deployment. Sending both headers with conflicting policies leads to inconsistent enforcement across browsers.
FAQ
Q: Which Permissions-Policy directives most often block AI crawler rendering?
In practice the highest-risk directives are clipboard-read/clipboard-write (some embedded widgets rely on these), browsing-topics (when set to () it blocks Topics API access entirely), and language-detector (recent addition that affects Translator and Language Detector API consumers). Sensor-related directives (geolocation, camera, microphone, accelerometer) are almost never relevant to crawlers and can stay locked down.
Q: Do AI crawlers respect Permissions-Policy or ignore it?
Headless-render crawlers run a real browser engine and therefore enforce the policy the same way a user's browser would. Bare HTML fetchers that do not run JavaScript ignore it because it is a browser-feature gate, not an HTTP-level access control. Treat Permissions-Policy as a render-fidelity setting rather than an anti-scraping mechanism.
Q: How do I test Permissions-Policy impact on a headless rendering pipeline?
Use Chromium headless with the policy applied, capture the rendered DOM and console errors, and compare against a baseline render with no policy. Chrome DevTools' Application panel shows allowed and disallowed features per frame; the same view is available headlessly through the Chrome DevTools Protocol. Couple this with Permissions-Policy-Report-Only to surface real-browser violations.
Q: How does Permissions-Policy interact with Cloudflare AI Crawl Control?
They operate at different layers. Cloudflare AI Crawl Control gates which crawlers can access the page at all (per Cloudflare's permission-based AI crawler model), while Permissions-Policy gates which browser features the page's headless render can use. Use both: Cloudflare for access decisions, Permissions-Policy for render fidelity.
Q: Should I use Permissions-Policy-Report-Only in production?
Yes, during transitions. Pair it with Permissions-Policy for already-validated directives so existing protections remain enforcing while you stage new ones in report-only mode.
Sources
- MDN. "Permissions-Policy" header reference — verified 2026-05-04 — directive list and grammar. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Permissions-Policy
- W3C. "Permissions Policy" Working Draft, 6 October 2025 — verified 2026-05-04 — normative spec. https://www.w3.org/TR/permissions-policy/
- Chrome for Developers. "Control browser features with Permissions Policy" — verified 2026-05-04 — DevTools integration and migration. https://developer.chrome.com/docs/privacy-security/permissions-policy
- Scott Helme. "Goodbye Feature Policy and hello Permissions Policy," 2020-09-07 — verified 2026-05-04 — migration context. https://scotthelme.co.uk/goodbye-feature-policy-and-hello-permissions-policy/
- Cloudflare. "Cloudflare Just Changed How AI Crawlers Scrape the Internet," 2025 — verified 2026-05-04 — permission-based AI crawler model. https://www.cloudflare.com/press/press-releases/2025/cloudflare-just-changed-how-ai-crawlers-scrape-the-internet-at-large/
Related Articles
404 Page AI Crawler Handling: Avoiding Citation Loss During Migrations
Migration playbook for keeping AI citations during URL changes — hard 404 vs soft 404, 410 Gone, redirect chains, sitemap cleanup, and refetch monitoring.
Accept-Encoding (Brotli, Gzip) for AI Crawlers
Specification for serving Brotli, gzip, and zstd to AI crawlers via Accept-Encoding negotiation: which bots support which codecs, fallback rules, and Vary handling.