PWA Guide
Web Push notifications
How web push subscriptions work, what VAPID is for, and how iOS Safari differs from Android Chrome.
All materials
1. Flow in one minute
- Ask for notification permission after a clear user action.
- Subscribe with PushManager + your VAPID public key.
- Send the subscription JSON to your backend.
- Server sends a push message signed with VAPID.
- Service Worker receives
push and shows a notification.
2. Subscribe example
const permission = await Notification.requestPermission();
if (permission !== 'granted') return;
const reg = await navigator.serviceWorker.ready;
const sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY),
});
await fetch('/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(sub),
});
3. SW push handler
self.addEventListener('push', (event) => {
const data = event.data ? event.data.json() : {};
event.waitUntil(self.registration.showNotification(data.title || 'Update', {
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));
});
4. Chrome vs iOS Safari
| Topic | Chrome / Android | Safari / iOS |
| Web Push | Mature | Supported on newer iOS, with limits |
| Home Screen install | Helpful, not always required | Usually required for reliable web push |
| Permission UX | Prompt available | Stricter; ask in context |
| Background delivery | Generally reliable | More constrained by system power rules |
5. Practical rules
- Never ask for push on first paint.
- Explain value before the browser permission dialog.
- Store subscriptions per device and handle expiration.
- Keep payloads small; put details behind a URL open.