Overview

Web push notifications allow you to re-engage users even after they've left your website — no app required. They work through a combination of the Push API, Notifications API, and Service Workers. This guide walks through the complete implementation from scratch.

Prerequisites

  • A website served over HTTPS (required by all browsers)
  • Basic knowledge of JavaScript
  • A VAPID key pair (Voluntary Application Server Identification)
  • A server-side component to store subscriptions and send push messages

Step 1: Register a Service Worker

A service worker is a background script that intercepts push events even when your page isn't open. Register it in your main JavaScript file:


if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(reg => console.log('Service Worker registered', reg))
    .catch(err => console.error('Registration failed', err));
}

Step 2: Request Notification Permission

Before subscribing, you must request user permission. Do this in response to a user gesture (like a button click) — browsers block programmatic permission prompts:


async function requestPermission() {
  const permission = await Notification.requestPermission();
  if (permission === 'granted') {
    await subscribeUser();
  }
}

Step 3: Create a Push Subscription

Using your VAPID public key, subscribe the user through the service worker registration:


async function subscribeUser() {
  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(YOUR_PUBLIC_VAPID_KEY)
  });
  // Send subscription object to your server
  await saveSubscription(subscription);
}

The urlBase64ToUint8Array helper converts your base64 VAPID key to the format the API expects. Numerous open-source implementations are available on GitHub.

Step 4: Handle Push Events in the Service Worker

Inside your sw.js file, listen for the push event and display a notification:


self.addEventListener('push', event => {
  const data = event.data.json();
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: '/icons/icon-192.png',
      badge: '/icons/badge-72.png',
      data: { url: data.url }
    })
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();
  event.waitUntil(clients.openWindow(event.notification.data.url));
});

Step 5: Send a Push Message from Your Server

On the server side, use the web-push library (Node.js) to send notifications to stored subscriptions:


const webpush = require('web-push');
webpush.setVapidDetails(
  'mailto:you@example.com',
  PUBLIC_VAPID_KEY,
  PRIVATE_VAPID_KEY
);

const payload = JSON.stringify({
  title: 'New Article Published',
  body: 'Check out our latest guide on push notifications.',
  url: 'https://example.com/articles/new-guide'
});

webpush.sendNotification(subscription, payload);

Browser Compatibility Notes

  • Chrome, Edge, Firefox: Full support
  • Safari (macOS 13+, iOS 16.4+): Supported via Web Push standard
  • Older iOS: Not supported — consider in-app fallbacks

Next Steps

Once basic notifications are working, explore advanced features like notification actions, images, silent pushes for background data sync, and analytics tracking via notification click events.