Push Notifications
Push has four parts: permission, service worker, browser push subscription, and a server that sends Web Push messages.
sequenceDiagram
participant App as Web app
participant SW as Service worker
participant Push as Browser push service
participant API as App server
App->>App: Ask permission after user intent
App->>SW: Ensure registration
App->>Push: subscribe with applicationServerKey
Push-->>App: PushSubscription
App->>API: Store subscription for user
API->>Push: Send Web Push payload
Push->>SW: push event
SW->>SW: showNotification
Subscription Sketch
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: publicVapidKey,
});
await fetch('/api/push-subscriptions', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(subscription),
});
}
Service Worker Handler
self.addEventListener('push', (event) => {
const data = event.data?.json() ?? { title: 'Update' };
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192.png',
data: { url: data.url ?? '/' },
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const url = event.notification.data?.url ?? '/';
event.waitUntil(clients.openWindow(url));
});
Rules
- Ask permission from a user gesture after explaining value.
- Treat push subscriptions as secret capability URLs.
- Support unsubscribe and expired subscription cleanup.
- Test denied permission, quiet UI, expired subscription, and click routing.
- Do not promise uniform behavior across all browsers and OS versions without device tests.