Testing

Permissions API: Browser Support, States, Limitations

The Permissions API works in Chrome 43+, Edge 79+, Firefox 46+, Opera 30+, Samsung Internet 4+, and Safari 16+. Learn the states, names, and limits.

Author

Prince Dewani

May 6, 2026

The Permissions API is a W3C JavaScript API that lets web pages query the state of permission-controlled features like geolocation, notifications, camera, and microphone through navigator.permissions.query(). It works in Chrome 43+, Edge 79+, Firefox 46+, Opera 30+, Samsung Internet 4+, and Safari 16+ on macOS and iOS, while Internet Explorer never supported it.

This guide covers what the Permissions API is, the browsers that support it, the permission names you can query, how to check support, and known issues.

What is the Permissions API?

The Permissions API is a JavaScript interface, edited by the W3C Web Application Security Working Group, that exposes permission state on navigator.permissions. A call to query returns a PermissionStatus object whose state is granted, denied, or prompt, and the object fires a change event when the user updates the setting.

Which browsers does the Permissions API support?

Every Chromium-based browser, Firefox, and Safari 16+ ship the Permissions API, putting global support near 96%. Internet Explorer and the legacy Android Browser left it out.

Loading browser compatibility data...

Permissions API compatibility in Chrome

Chrome supports the Permissions API from Chrome 43 on Windows, macOS, Linux, ChromeOS, and Android. The navigator.permissions object is exposed in top-level pages and in dedicated, shared, and service workers. Chrome 4 to 42 did not support it. Chrome ships the widest set of permission names, so a query that works in any other browser also works here.

Permissions API compatibility in Edge

Microsoft Edge supports the Permissions API from Edge 79, the first Chromium-based release, on Windows 10, Windows 11, and macOS. Pre-Chromium EdgeHTML 12 to 18 never added the API. Edge inherits every permission name Chrome ships, so query patterns line up across the two browsers.

Permissions API compatibility in Firefox

Firefox supports the Permissions API from Firefox 46 on Windows, macOS, Linux, and Android. Firefox accepts a smaller list of permission names than Chrome, with geolocation, notifications, push, persistent-storage, midi, screen-wake-lock, and storage-access mapped through query. Names that Chrome ships but Firefox does not, like camera and microphone, throw a TypeError.

Permissions API compatibility in Safari on macOS

Safari supports the Permissions API from Safari 16 on macOS Big Sur, Monterey, Ventura, Sonoma, and Sequoia. Safari 15.6 and earlier did not expose navigator.permissions. The Safari implementation only accepts camera, microphone, geolocation, and notifications as permission names; queries for push, clipboard, or background-sync throw a TypeError.

Permissions API compatibility in Safari on iOS and iPadOS

Safari on iOS and iPadOS supports the Permissions API from Safari 16. Older iOS releases up to iOS 15 did not expose navigator.permissions, so iPhones on those versions return undefined when a page touches the property. Chrome and Edge on iOS run on the WebKit engine, so they inherit the same Safari 16 floor.

Permissions API compatibility in Opera

Opera supports the Permissions API from Opera 30 on Windows, macOS, and Linux, and tracks every Chromium release after that. Opera Mobile supports it from Opera Mobile 80 on Android, while Opera Mini does not support it in any version because the proxy-based engine strips out modern permission UI.

Permissions API compatibility in Samsung Internet

Samsung Internet supports the Permissions API from Samsung Internet 4.0 on Galaxy phones and tablets running Android. Every release after 4.0 keeps the API on by default and follows Chromium for the supported permission names. Samsung Internet 1.0 to 3.0 did not support it.

Permissions API compatibility in Android Browser

Chrome for Android, Samsung Internet, and Firefox for Android together provide the Permissions API on most modern Android phones. The legacy stock Android Browser, last shipped with Android 4.4 KitKat, never added the API. Use a Chromium-based browser or Firefox 46+ for Android coverage.

Permissions API compatibility in Internet Explorer

Internet Explorer does not support the Permissions API in any version. The Trident engine never implemented navigator.permissions, and Microsoft has retired Internet Explorer. Move any permission-aware code to Chromium-based Edge or another modern browser for new work.

Note

Note: The Permissions API breaks across Safari, Firefox, and older mobile browsers. Test it on real browsers and OS with TestMu AI. Try TestMu AI free!

What permissions can you query with the Permissions API?

navigator.permissions.query accepts a PermissionDescriptor with a name field. Each browser ships its own subset of permission names, so feature-detect every name before relying on it.

  • geolocation: Supported in Chrome, Edge, Firefox, Opera, Samsung Internet, and Safari 16+. The most consistent permission name across every engine and the safest default for cross-browser tests.
  • notifications: Chrome, Edge, Firefox, Opera, and Samsung Internet support it on every platform. Safari 16+ accepts the name on macOS but the iOS implementation only returns a state for sites added to the home screen.
  • camera and microphone: Chromium browsers and Safari 16+ accept these names. Firefox throws a TypeError because Mozilla has not exposed them through navigator.permissions; use mediaDevices.getUserMedia and catch NotAllowedError as a fallback.
  • push: Chrome, Edge, Firefox, Opera, and Samsung Internet support it. Safari does not accept the push name because its push implementation is tied to web app manifests rather than the Permissions API.
  • clipboard-read and clipboard-write: Chromium browsers only. Firefox and Safari throw a TypeError; for those engines fall back to async-clipboard feature detection.
  • persistent-storage: Chrome, Edge, Firefox, Opera, and Samsung Internet. Safari does not accept it. Pair it with navigator.storage.estimate to plan offline storage flows.
  • background-sync, screen-wake-lock, midi: Chromium browsers and Firefox subset support these. Safari does not accept them, so wrap each call in try/catch when you ship cross-browser code.
  • local-fonts, window-management, compute-pressure: Recent Chromium-only names. Firefox and Safari throw a TypeError on every version, and they should be feature-detected behind a separate code path.
  • storage-access: Chrome, Edge, Firefox, and Safari 16.4+ accept this name as part of the Storage Access API. It is the most reliable cross-browser way to check if first-party storage is available inside a third-party iframe.
...

How do you check if a browser supports the Permissions API?

Run a two-step check at runtime: confirm navigator.permissions exists, then call query with the permission name you care about and read result.state. Wrap query in try/catch because unknown names throw a TypeError on Safari and Firefox.

  • Feature-detect navigator.permissions: Check for "permissions" in navigator before you call query, since older Safari and the legacy Android Browser skip the property entirely.
  • Call navigator.permissions.query: Pass a descriptor with a name field, like the geolocation descriptor, and await the returned promise. The promise resolves with a PermissionStatus object.
  • Read result.state: The PermissionStatus object exposes state as one of "granted", "denied", or "prompt". Map each state to UI behaviour without forcing a permission dialog.
  • Listen for change events: Attach result.onchange so the UI reacts when the user updates the site setting from the address bar or the OS privacy panel.
  • Catch TypeError for unsupported names: Safari throws when given names like push or clipboard-read, so wrap query in try/catch and fall back to the older feature-specific permission flow.

Paste the snippet below into the DevTools console. It walks four common names, prints the current state, and logs any change the user makes inside the same tab.

// Paste this into the DevTools console of any modern browser.
// It feature-detects navigator.permissions, then queries a few names safely.
async function checkPermissions() {
  if (!("permissions" in navigator)) {
    console.log("Permissions API is not supported in this browser.");
    return;
  }

  const names = ["geolocation", "notifications", "camera", "microphone"];
  for (const name of names) {
    try {
      const status = await navigator.permissions.query({ name });
      console.log(name + ":", status.state);

      status.onchange = () => {
        console.log(name + " changed to:", status.state);
      };
    } catch (err) {
      console.warn(name + " is not a recognised name in this browser:", err.message);
    }
  }
}

checkPermissions();

What are the known issues with the Permissions API?

The Permissions API ships in every modern engine, but the names, the worker surface, and the request flow drift across browsers. Plan around these gaps before you wire query into a production permission strategy.

  • Permission names are not portable: Each browser ships its own subset, so a name that works in Chrome can throw a TypeError in Safari or Firefox. Always feature-detect each name with try/catch.
  • Permissions.revoke is gone: Both Chrome and Firefox removed Permissions.revoke. Pages cannot programmatically clear a granted permission, so users have to revoke through site settings or by clearing site data.
  • Querying does not request: query never prompts the user. To actually request camera or microphone you still call getUserMedia, and to request notifications you still call Notification.requestPermission.
  • Safari subset is small: Safari 16+ accepts only camera, microphone, geolocation, and notifications. Push, clipboard, midi, and background-sync all throw TypeError, even on the latest macOS Sequoia and iOS 18 builds.
  • Secure-context only for many names: camera, microphone, and clipboard names are gated to HTTPS or localhost. Plain http:// pages get a SecurityError when they try to query these names.
  • Workers expose a different surface: WorkerNavigator.permissions is wired in Chromium and Firefox, but Safari does not expose navigator.permissions inside service workers. Plan permission checks on the main thread for cross-browser parity.
  • "prompt" hides past denials: A "prompt" state can mean the user has not been asked or that an earlier denial expired. The API does not separate the two, so keep a server-side flag if you need that distinction.
  • Iframe behaviour follows Permissions-Policy: Cross-origin iframes need a Permissions-Policy allowlist for camera, microphone, geolocation, and the other powerful names. Without the header the query state silently degrades to denied.

In my experience, the most surprising failure is forgetting that query never prompts. Calling navigator.permissions.query for the camera name on page load and reading "prompt" tricks people into thinking the user has been asked, when in fact getUserMedia still has to fire the dialog later.

...

Citations

All Permissions API version numbers and platform notes in this guide come from these primary sources:

Author

Prince Dewani is a Community Contributor at TestMu AI, where he manages content strategies around software testing, QA, and test automation. He is certified in Selenium, Cypress, Playwright, Appium, Automation Testing, and KaneAI. Prince has also presented academic research at the international conference PBCON-01. He further specializes in on-page SEO, bridging marketing with core testing technologies. On LinkedIn, he is followed by 4,300+ QA engineers, developers, DevOps experts, tech leaders, and AI-focused practitioners in the global testing community.

Open in ChatGPT Icon

Open in ChatGPT

Open in Claude Icon

Open in Claude

Open in Perplexity Icon

Open in Perplexity

Open in Grok Icon

Open in Grok

Open in Gemini AI Icon

Open in Gemini AI

Copied to Clipboard!
...

3000+ Browsers. One Platform.

See exactly how your site performs everywhere.

Try it free
...

Write Tests in Plain English with KaneAI

Create, debug, and evolve tests using natural language.

Try for free

Frequently asked questions

Did you find this page helpful?

More Related Hubs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests