Push Notifications

Push has four parts: permission, service worker, browser push subscription, and a server that sends Web Push messages.

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.