Add push notifications
Published
Outcome: your server can reach the user with a message even when the app is not in the foreground. Per MDN, the Push API gives web applications the ability to receive messages pushed to them from a server, whether or not the web app is in the foreground — or even currently loaded — and per MDN the service worker is started as necessary to handle an incoming push message.
Two separate APIs are involved, and they are easy to confuse. Push is the transport: per
MDN, it delivers the message to the worker’s push event. Notifications are the display:
per MDN, the worker reacts to the message by, for example, displaying a notification with
ServiceWorkerRegistration.showNotification().
Browser & ecosystem support
Section titled “Browser & ecosystem support”Per MDN, the Push API is Baseline “widely available” — well established across many
devices and browser versions, and available across browsers since March 2023. Per MDN,
PushManager.subscribe() is available only in secure contexts (HTTPS) in some or all
supporting browsers. Notification.requestPermission() is the weaker link: per MDN, that
static method is not Baseline, because it does not work in some of the most widely
used browsers.
-
Have an active service worker. Per MDN, for an app to receive push messages it has to have an active service worker; once it is active, it can subscribe using
PushManager.subscribe(). If you do not have one yet, start with Getting started. -
Ask for permission from a user gesture. Per MDN,
Notification.requestPermission()returns a promise that fulfills withgranted,denied, ordefault, and the request should be made in response to user interaction. Per MDN, when the value isdefaultthe user’s decision is unknown and the application will act as if permission was denied. -
Subscribe, also from a user gesture. Per MDN,
subscribe()calls should be done in response to a user gesture such as clicking a button — not only as best practice, but because browsers are moving to disallow notifications not triggered by a user gesture, and MDN names Firefox as already doing this from version 72. -
Send the subscription to your server. Per MDN, the resulting
PushSubscriptionincludes everything the application needs to send a push message: an endpoint and the encryption key needed for sending data. -
Handle
pushin the worker and show something. Per MDN, incoming push messages are delivered to thepushevent handler, which can react by displaying a notification usingServiceWorkerRegistration.showNotification().
Feature detection and fallback
Section titled “Feature detection and fallback”Per MDN, ServiceWorkerRegistration.pushManager is the entry point into using push
messaging and returns a reference to the PushManager interface — so test for that
interface before offering the subscribe UI at all:
async function subscribeToPush(applicationServerKey) { if (!('PushManager' in window)) { // No push support: keep the subscribe UI hidden and fall back to whatever // in-app channel you already have (an inbox view, an email digest). return null; }
const permission = await Notification.requestPermission(); if (permission !== 'granted') return null;
const registration = await navigator.serviceWorker.ready; return registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey, });}Per MDN, applicationServerKey is a Base64-encoded string or ArrayBuffer containing an
ECDSA P-256 public key that the push server uses to authenticate your application server;
if specified, all messages from your application server must use the VAPID authentication
scheme and include a JWT signed with the corresponding private key. Per MDN, that key is
not the same ECDH key used to encrypt the data.
In the worker, turn the message into a notification:
self.addEventListener('push', (event) => { const body = event.data ? event.data.text() : 'You have a new message.'; event.waitUntil(self.registration.showNotification('New message', { body }));});Practical checklist
Section titled “Practical checklist”userVisibleOnly: trueis effectively mandatory. Per MDN,applicationServerKeyis required in some browsers such as Chrome and Edge, and they will reject the promise ifuserVisibleOnlyis not set totrue. Plan for a visible notification per push rather than silent background delivery.- Treat the endpoint as a secret. Per MDN, the subscription endpoint is a unique capability URL: knowledge of the endpoint is all that is necessary to send a message to your application, so it needs to be kept secret or other applications could push to your users.
- Guard against CSRF when subscribing. MDN warns explicitly that when implementing
PushManagersubscriptions it is vitally important to protect against CSRF/XSRF issues in your app. - Delivery is not unlimited everywhere. Per MDN, waking a service worker to deliver a push message increases resource usage, particularly battery, and there is currently no standard mechanism for handling this: Firefox allows a limited quota of push messages per application (refreshed each time the site is visited, with messages that generate notifications exempt), while Chrome has no limits.
- Subscriptions expire and change. Per MDN, the
pushsubscriptionchangeevent fires when a push subscription has been invalidated or is about to be — for example when the push service sets an expiration time — so treat a stored subscription as something that can stop being valid, and re-subscribe when it does. - Each subscription belongs to one worker. Per MDN, each subscription is unique to a service worker.
- A denial is explicit. Per MDN,
deniedmeans the user has explicitly denied permission for the current origin to display system notifications, and MDN’s own example notes that in that case you should be respectful and not bother the user any more.
Where to go next
Section titled “Where to go next”- Web Push reference — the protocol and the subscription model in reference form.
- Notifications API reference — the display
half, including what
showNotification()accepts. - Notification permissions — the permission model in detail.
- Push on iOS Safari — a platform-specific entry on this site.
← Back to the Guides overview.