跪拜 Guibai
← All articles
Frontend · Chrome · JavaScript

Chrome's Declarative Permission Elements: <geolocation> and <usermedia> Replace the Generic <permission> Tag

By iDao技术魔方 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The move from JS-driven permission prompts to declarative HTML elements changes how web apps request geolocation and camera/microphone access, and it makes many existing tutorials and cached permission states actively harmful. Teams that ship conference, mapping, or voice features need to know which element names, events, and headers actually work in 2026 or their Chromium-built recovery flows will silently break.

Summary

Chrome's permission system has quietly moved from JS API calls to declarative HTML elements. The generic <permission> element, born as PEPC in Chrome 126, ran an Origin Trial through 143 and then got split into capability-specific elements: <geolocation> (Chrome 144) and <usermedia> (Chrome 151). Both work as data mediators: the browser handles the prompt, recovery, and stream or coordinate delivery, while the developer reads properties like position or stream and listens to stream/error/cancel events.

Old references remain a hazard. Names like listenforchanges, dismissible, and onpermissionstatuschange never existed in any spec, and onpromptaction is a plain Event with no detail field, so you still have to call navigator.permissions.query() after a prompt is answered. Permissions-Policy and iframe allow attributes intersect, not union, and the response header only executes in Chromium, so Firefox and Safari need the allow attribute. Chrome enables one-week silent blocking after three dismissed prompts and one-time grants since 116, making permission-state caching wrong from the start.

Migration guidance: add query() before every strong permission call, treat denied/prompt/hardware failure as separate branches, align Permissions-Policy headers and iframe allow attributes, and verify with DevTools Frames or element.allowsFeature(). Switch to dedicated elements only if your core users are Chromium, you rely on permission recovery flows, and you can maintain a dual path; otherwise, completing the query layer delivers immediate compatibility gains.

Takeaways
— The generic <permission> element (PEPC) ran an Origin Trial from Chrome 126 to 143; the draft has been superseded by HTML Permission Elements.
— Chrome 144 ships <geolocation> and Chrome 151 ships <usermedia>; both are data mediators, not simple prompt widgets.
— The names listenforchanges, dismissible, and onpermissionstatuschange do not exist in any spec IDL.
— The onpromptaction event is a plain Event with no detail property; you cannot read the permission result from it and must call query() instead.
— navigator.permissions.query() returns the aggregate of all security constraints for the current context; Permissions-Policy blocks will make it return denied without ever showing a prompt.
— Firefox supports query() for camera and microphone only since version 132; Safari supports notifications query since 16.4.
— idle-detection is a Permissions-Policy directive and a path used by IdleDetector.requestPermission(), but it is not on the MDN query() permission-name list.
— The <geolocation> and <usermedia> elements impose mandatory style constraints (minimum contrast, opacity 1, size limits, only 2D transforms) as part of the security model.
— Permissions-Policy response headers execute only in Chromium browsers; Firefox and Safari use the iframe allow attribute model, so write both.
— The intersection rule between Permissions-Policy and iframe allow means a parent header of microphone=() blocks any iframe allow setting.
— Chrome enables one-week silent blocking after three consecutive prompt dismissals and one-time grants from Chrome 116; do not cache permission state.
— LNA gates from Chrome 142, splits into local-network and loopback-network in 145, adds enterprise policy in 146, and extends to WebSocket and WebTransport in 147.
Conclusions

The Origin Trial numbers from Zoom, Immobiliare.it, and ZapImóveis showing 46% fewer camera/mic errors, 20% more geolocation success flows, and 54% recovery of previously blocked users validate the concept of putting requests in context, but they do not validate the generic single-tag form.

WebKit and Mozilla's rejection of the generic control pushed Chrome to capability-specific elements, meaning cross-browser support for the new declarative approach will come piecemeal and at different speeds.

The widespread reuse of invalid IDL names like listenforchanges suggests much of the Chinese tutorial landscape for permissions is still describing a dead draft, so code copied from it will break in current Chrome.

The forced style constraints on the new elements turn CSS transparency tricks into an attack surface; treating them as design suggestions is not just aesthetically wrong but a security violation.

The decision to keep query() as the source of truth after promptaction/error events reflects that a user can answer a prompt without actually changing permission state, so event handling must stay separated from state reads.

Concepts & terms
Page-Embedded Permission Control (PEPC)
The original name for Chrome's generic <permission> element, which attempted to handle all strong permissions through a single HTML tag. Its Origin Trial ended at Chrome 143 and it was replaced by capability-specific elements like <geolocation> and <usermedia>.
Permissions-Policy
HTTP response header that controls which browser features (such as camera, microphone, or geolocation) a page and its iframes are allowed to request. It works with a structured-header syntax and is enforced by Chromium browsers; Firefox and Safari primarily rely on the iframe allow attribute.
Local Network Access (LNA)
A Chrome feature that gates and then splits local-network permissions. It gates from Chrome 142, splits into local-network and loopback-network in 145, adds enterprise policy in 146, and expands to WebSocket and WebTransport in 147.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗