JavaScript Navigator permissions Property

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Baseline

What You’ll Learn

navigator.permissions is a read-only property that returns a Permissions object — the entry point to the Permissions API. Learn query(), the granted / prompt / denied states, MDN’s geolocation example, change listeners, five examples, and try-it labs.

01

Kind

Read-only property

02

Returns

Permissions

03

Baseline

Widely available

04

Main method

query()

05

States

granted · prompt · denied

06

Use

Permission-aware UX

Introduction

Powerful browser features — location, camera, notifications, and more — need user permission. Calling those APIs blindly can surprise users with prompts or fail silently after a denial.

navigator.permissions gives you a Permissions object so you can ask what the status is before (or after) you request a feature. MDN’s classic example checks geolocation and only shows a map when access is granted.

💡
Query is not always a request

permissions.query() reports the current status. The browser usually shows a permission prompt when you call the feature API itself (for example getCurrentPosition). Design UX for all three states.

Understanding the permissions Property

Reading navigator.permissions does not return a Boolean. It returns a Permissions object. From there you call query({ name: "..." }) and get a PermissionStatus whose state is one of:

  • granted — permission is allowed; you can use the feature.
  • prompt — the browser may ask the user when you request it.
  • denied — blocked; offer an alternative path, do not nag.
  • Read-only entry point — you do not assign to navigator.permissions.
  • Baseline — Widely available (MDN, since September 2022).

📝 Syntax

General form of the property:

JavaScript
navigator.permissions

Value

  • A Permissions object used to query permission status.

Common patterns

JavaScript
// Feature-detect, then query (MDN-style):
if (navigator.permissions) {
  navigator.permissions.query({ name: "geolocation" }).then((result) => {
    if (result.state === "granted") {
      // showMap();
    } else if (result.state === "prompt") {
      // showButtonToEnableMap();
    }
    // Do nothing special if denied.
  });
}

⚡ Quick Reference

GoalCode
Get Permissions objectnavigator.permissions
Feature detect"permissions" in navigator
Query a permissionnavigator.permissions.query({ name: "geolocation" })
Read statusresult.state"granted" | "prompt" | "denied"
Listen for changesresult.addEventListener("change", …)
Writable?No (read-only property)
Status (MDN)Baseline Widely available

🔍 At a Glance

Four facts to remember about navigator.permissions.

Returns
Permissions

API entry point

Baseline
widely

Since Sept 2022

Key method
query()

Async status

Best for
UX branching

Before sensitive APIs

📋 permissions.query() vs Calling the Feature

permissions.query()Feature API (e.g. geolocation)
PurposeRead current permission statusActually use the capability
Typical prompt?Usually noMay show a permission dialog
Return valuePermissionStatus PromisePosition / stream / etc.
Best forDecide whether to show a button or mapFetch the real data after consent
Use together?Yes — query first for UX, then call the feature when appropriate

Examples Gallery

Examples follow MDN navigator.permissions patterns. Prefer Try It Yourself. Some permission name values differ by browser — always catch errors.

📚 Getting Started

Detect the API and run MDN’s geolocation query.

Example 1 — Feature Detection

Check whether permissions exists before calling query().

JavaScript
const supported = "permissions" in navigator;
console.log(supported ? "permissions available" : "permissions missing");
Try It Yourself

How It Works

Modern browsers expose the property. Always detect before chaining .query().

Example 2 — MDN Geolocation Query

Branch UI based on granted vs prompt (and ignore denied).

JavaScript
async function checkGeoPermission() {
  if (!navigator.permissions) {
    console.log("Permissions API missing");
    return;
  }
  const result = await navigator.permissions.query({ name: "geolocation" });
  if (result.state === "granted") {
    console.log("granted — showMap()");
  } else if (result.state === "prompt") {
    console.log("prompt — showButtonToEnableMap()");
  } else {
    console.log("denied — do not nag");
  }
}

checkGeoPermission();
Try It Yourself

How It Works

This mirrors MDN’s example with async/await and a clear message for each state.

📈 Practical Patterns

Handle all states, listen for changes, and query safely.

Example 3 — Map Every State to UX Copy

Build a short status string for a settings or map panel.

JavaScript
async function geoStatusMessage() {
  if (!navigator.permissions) return "Permissions API not available";
  const { state } = await navigator.permissions.query({ name: "geolocation" });
  const messages = {
    granted: "Location allowed — you can show the map.",
    prompt: "Location not decided yet — show an Enable button.",
    denied: "Location blocked — explain how to re-enable in settings."
  };
  return messages[state] || ("Unknown state: " + state);
}

geoStatusMessage().then((msg) => console.log(msg));
Try It Yourself

How It Works

Keep copy friendly for denied — users often must change browser site settings manually.

Example 4 — Listen for change

PermissionStatus can fire change when the user updates the decision.

JavaScript
async function watchGeoPermission() {
  if (!navigator.permissions) {
    console.log("Permissions API missing");
    return;
  }
  const status = await navigator.permissions.query({ name: "geolocation" });
  console.log("initial: " + status.state);
  status.addEventListener("change", () => {
    console.log("changed: " + status.state);
  });
}

watchGeoPermission();
Try It Yourself

How It Works

Useful for live UI: hide the Enable button when the user grants access in browser settings.

Example 5 — Safe Query Helper

Wrap query() so unsupported permission names fail gracefully.

JavaScript
async function queryPermission(name) {
  if (!navigator.permissions || !navigator.permissions.query) {
    return { ok: false, reason: "api-missing" };
  }
  try {
    const status = await navigator.permissions.query({ name });
    return { ok: true, name, state: status.state };
  } catch (err) {
    return {
      ok: false,
      reason: "query-failed",
      message: String(err && err.message ? err.message : err)
    };
  }
}

queryPermission("geolocation").then((info) => {
  console.log(JSON.stringify(info));
});
Try It Yourself

How It Works

Browsers disagree on which permission names are valid. A try/catch keeps demos and production code resilient.

🚀 Common Use Cases

  • Maps / store finders — show Enable Location only when state is prompt.
  • Camera / mic apps — check status before opening a capture UI (where supported).
  • Notification opt-in — avoid asking again after denied.
  • Settings panels — display current permission state with clear next steps.
  • Diagnostics — include permission states in support debug reports.

🧠 How navigator.permissions Works

1

Read the entry point

Access navigator.permissions to get a Permissions object.

Permissions
2

Call query()

Pass a descriptor like { name: "geolocation" }.

query()
3

Read PermissionStatus.state

Branch on granted, prompt, or denied.

state
4

Call the feature API

When appropriate, use geolocation / media / etc. and handle errors.

📝 Notes

  • Baseline Widely available (MDN, since September 2022).
  • Not Deprecated, Experimental, or Non-standard — no status banner required.
  • Read-only; use Permissions.query() on the returned object.
  • Supported permission name values vary by browser — wrap queries in try/catch.
  • Related: geolocation, pdfViewerEnabled, mediaDevices, Window.

Universal Browser Support

navigator.permissions is Baseline Widely available across modern browsers (MDN: since September 2022). Individual permission names can still differ — feature-detect and catch query errors.

Baseline · Widely available

Navigator.permissions

Query permission status for permission-aware UX. Pair with the real feature API (geolocation, media, and so on) when you need the capability itself.

Universal Widely available
Google Chrome Full support · Desktop & Mobile
Full support
Mozilla Firefox Full support · Desktop & Mobile
Full support
Apple Safari Full support · modern Safari
Full support
Microsoft Edge Full support · Chromium
Full support
Opera Full support · Modern versions
Full support
Internet Explorer Not a Baseline target for Permissions API
Unavailable
permissions Excellent

Bottom line: Detect navigator.permissions, query safely, branch on granted/prompt/denied, and never nag after denial.

Conclusion

navigator.permissions is the Baseline entry point to the Permissions API. Query status with query(), branch on granted / prompt / denied, listen for change when helpful, and call the real feature API only when your UX is ready.

Continue with platform, geolocation, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Feature-detect before calling query()
  • Handle granted, prompt, and denied
  • Wrap queries in try/catch for unsupported names
  • Explain how to re-enable permissions after denial
  • Listen for change when UI should stay in sync

❌ Don’t

  • Nag users after denied
  • Assume every permission name works in every browser
  • Treat query() as a substitute for the feature API
  • Try to assign to navigator.permissions
  • Hide critical flows behind a single permission without a fallback

Key Takeaways

Knowledge Unlocked

Five things to remember about permissions

Baseline Permissions entry point — query, then branch UX.

5
Core concepts
🔎 02

Method

query()

API
🎯 03

States

granted / prompt / denied

UX
🔁 04

Events

status change

Live
05

Status

Baseline

Modern

❓ Frequently Asked Questions

It is a read-only Navigator property that returns a Permissions object — the entry point to the Permissions API for querying (and in some cases updating) permission status for covered browser features.
No. MDN marks navigator.permissions as Baseline Widely available (since September 2022). It is not Deprecated, Experimental, or Non-standard.
Call navigator.permissions.query({ name: "geolocation" }) (or another supported name). It returns a Promise that resolves to a PermissionStatus with a state of granted, prompt, or denied.
granted means the feature may run without asking again. prompt means the browser may ask the user. denied means access is blocked — do not keep prompting; show an alternative UX.
Usually no — query() reports the current status. The actual request often happens when you call the feature API (for example getCurrentPosition). Always handle denial gracefully.
No. The property is read-only. You use methods on the returned Permissions object, such as query().
Did you know?

MDN’s geolocation sample deliberately does nothing when permission is denied. That is intentional UX: after a hard no, keep showing alternative content instead of opening another prompt loop.

Learn platform Next

Baseline platform string and ⌘ vs Ctrl shortcut hints.

platform →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful