Build my web app

Web push notifications: how they work, what each platform allows, and how not to get muted

The Push API and VAPID in plain terms, why iOS requires installation first, permission prompts that get accepted, OneSignal vs rolling your own, and the frequency that keeps subscribers.

Push is the feature that turns an installed web app from "a nicer bookmark" into a channel. It is also the feature most often done badly. This guide covers the mechanism, the platform rules, and the behaviour that keeps people subscribed.

How web push works

  1. Your page asks the browser for permission to show notifications.
  2. If granted, the page asks the service worker to subscribe to push. The browser returns a subscription: a unique URL at the browser vendor's push service plus encryption keys.
  3. You store that subscription on your server (or a provider does).
  4. To notify, your server sends an encrypted message to the subscription URL, signed with your VAPID key pair so the push service knows it is from you.
  5. The push service wakes the user's browser, which runs your service worker's push event even if the site is closed. Your handler shows the notification.
  6. Tapping it fires notificationclick, where you open or focus the right page.

No app store, no vendor SDK required — although a provider like OneSignal handles steps 3–4 and the dashboard, which is why the builder integrates it.

The service worker side

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

self.addEventListener('notificationclick', (e) => {
  e.notification.close();
  e.waitUntil(clients.matchAll({ type: 'window' }).then(list => {
    const url = e.notification.data.url;
    for (const c of list) if (c.url.includes(self.location.origin)) return c.focus().then(() => c.navigate(url));
    return clients.openWindow(url);
  }));
});

The badge is a monochrome icon Android shows in the status bar; without one, Android uses a generic bell.

Platform rules

Android (Chrome, Edge, Samsung, Firefox)iOS / iPadOS (Safari and others)Desktop
Works from a browser tabYesNo — only after Add to Home ScreenYes
Minimum versionLong-standingiOS 16.4 (March 2023)Long-standing; macOS Safari 16+
Permission requestAny time; Chrome may use a quiet prompt for sites users usually blockMust be in response to a user tapAny time; Chrome quiet UI applies
Delivered with app closedYesYesWhile the browser is running (Chrome/Edge can run in background)
Icon badge countVia notificationYes (Badging API)Yes

The iOS rule has a practical consequence: your permission request must live inside the installed app, and your install page should tell iPhone users that notifications come after installing. Asking in Safari does nothing.

Permission prompts that get accepted

Browsers penalise sites whose prompts are usually dismissed — Chrome downgrades them to a quiet indicator nobody sees. So:

Provider or do-it-yourself

OneSignal (what the builder integrates): hosted subscription storage, a sending dashboard, segments, scheduling, RSS-to-push automation, and a generous free tier. Cost: their script on your page and their data processing, which you disclose in your privacy policy. Self-hosted: any server with a web-push library (Node web-push, PHP minishlink/web-push, Python pywebpush), your own VAPID keys, and a table of subscriptions. Cost: your time; no third party. For most website owners the provider is the right call; for developers with a backend, self-hosting is a day's work and permanent.

What to send, and how often

The unsubscribe rate on push is brutal because muting is one tap away. Guidance that holds across categories:

Watch two numbers in your provider: opt-out rate per campaign and click rate. A campaign with a high opt-out rate tells you what your subscribers did not sign up for.

Privacy and compliance

Push subscriptions are personal data. State in your privacy policy that you send notifications, through which provider, and how to stop (browser site settings, or a toggle in your app). In the EU, the permission itself is consent; don't pre-tick anything and don't re-prompt people who declined.