Notifications · Concept
The notification permission model
Published Updated
In one line: Notification.permission reports one of three states —
default, granted, or denied — and per MDN, code should only call
Notification.requestPermission() in response to a real user gesture, never on load.
The three states
Section titled “The three states”Per MDN’s Notification.permission reference:
default— the user has not made a choice yet; the browser treats this the same asdenieduntil the user grants permission.granted— the user accepted; on desktop the page may construct notifications with theNotificationconstructor (per MDN, most mobile browsers throw instead, and expectServiceWorkerRegistration.showNotification()).denied— the user refused; notifications will not be displayed.
Requesting permission from a user gesture
Section titled “Requesting permission from a user gesture”Per MDN’s Using the Notifications API guide, permission should be requested
in response to a user gesture such as a click, and browsers are increasingly
disallowing requests that aren’t — MDN names Firefox 72+ and Safari as
browsers that already enforce this. Ask in response to that gesture, not on load:
document.getElementById('enable-notifications').addEventListener('click', async () => { if (!('Notification' in window)) { // Fallback: the Notification API doesn't exist in this browser at all. return; } const permission = await Notification.requestPermission(); if (permission !== 'granted') { // Fallback: user declined (or dismissed) the prompt — don't proceed as if granted. return; } await showEnabledNotification();});
async function showEnabledNotification() { // Per MDN, most mobile browsers expose `Notification` but throw a // TypeError from its constructor, expecting // `ServiceWorkerRegistration.showNotification()` instead — so route // through a registered service worker when one is available rather than // assuming the constructor works everywhere permission was granted. const registration = 'serviceWorker' in navigator ? await navigator.serviceWorker.getRegistration() : undefined; if (registration) { await registration.showNotification('Notifications enabled'); return; } try { new Notification('Notifications enabled'); } catch { // Fallback: no service worker registration and the constructor threw // (e.g. most mobile browsers) — nothing more to show without a // registered service worker. }}After a denial, stop asking
Section titled “After a denial, stop asking”MDN’s own requestPermission() example code comments that once a user has
denied notifications, “there is no need to bother them any more” — don’t call
requestPermission() again on a schedule hoping for a different answer.
MDN’s own Using the Notifications API guide takes a lighter approach and
keeps its enable button visible after a denial, so the user has a chance to
change their mind later; either way, the request itself should not repeat
automatically.
Push subscriptions are not exclusively behind a service worker
Section titled “Push subscriptions are not exclusively behind a service worker”Per the Push API spec, a PushManager is available on both Window and
ServiceWorkerRegistration: a Window’s PushManager has a null associated
service worker registration, while a ServiceWorkerRegistration’s PushManager
is tied to that registration. The spec also defines window-accessible push
subscriptions and lets a declarative push message display a notification
without going through a page’s own script. Requesting a push subscription via
subscribe() is its own permission flow, distinct from the Notification
permission described above.
Where it is supported
Section titled “Where it is supported”Per MDN’s browser-compat data, Notification.permission and
requestPermission() are Limited availability — not Baseline, because
they don’t work the same way in some widely-used browsers. Desktop support is
broad (Chrome 32+, Edge 14+, Firefox 22+, Safari 7+), and Chrome, Firefox, and
Samsung Internet on Android support the permission property and
requestPermission() just as fully. WebView on Android has no support for
the permission API at all. Safari on iOS only exposes this to a web app the
user has added to the Home Screen (16.4+), not to ordinary browser tabs.
Requesting permission only from a user gesture is guidance MDN gives and some
browsers already enforce, rather than a spec requirement.
Note that the separate Notification() constructor has its own Android
restrictions on some browsers that are out of scope for this compatibility
table, since they don’t apply to the permission property or
requestPermission() documented here.
See The Notifications API and Web Push for the per-browser availability of the APIs this permission gates.
Practical checklist
Section titled “Practical checklist”- Only call
requestPermission()from inside a user gesture handler, never on page load. - Treat
defaultthe same as “not permitted yet” — don’t assume a request will succeed. - Once
Notification.permissionisdenied, don’t callrequestPermission()again on a schedule hoping for a different answer. - Feature-detect
'Notification' in windowin page code before touching the API — per MDN,Notification.permissionis also reachable from Web Workers, which have nowindow. - Don’t assume push subscription requires an active service worker registration — the Push API also defines a window-scoped path.
Where to go next
Section titled “Where to go next”Specifications
| Specification | Status |
|---|---|
| Notification.permission / requestPermission() | WHATWG living standard |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 32 | medium | source | — |
| Chrome (Android) | Yes | 42 | medium | source | — |
| Edge (Desktop) | Yes | 14 | medium | source | — |
| Firefox (Desktop) | Yes | 22 | medium | source | — |
| Firefox (Android) | Yes | 22 | medium | source | — |
| Safari (macOS) | Yes | 7 | medium | source | — |
| Safari (iOS) | Partial | 16.4 | medium | source | 1 |
| Samsung Internet | Yes | 4.0 | medium | source | — |
| WebView (Android) | No | — | medium | source | 2 |
- Only for web apps added to the Home Screen; not available to ordinary browser tabs.
- Not supported per MDN browser-compat data.