Skip to content

Web push on iPhone and iPad

What iOS needs for web push: version 16.4, a Home Screen web app, a standalone manifest and a prompt from a tap. With detection code and a service worker.

PushBy Rushi Patel, Senior iOS developerUpdated 2 November 20266 min read

iPhones and iPads get web push for sites that the user has added to the Home Screen, since iOS and iPadOS 16.4. It is the same Push API, Notifications API and service worker that Chrome and Firefox use, with three extra conditions. Most “web push does not work on iOS” reports are one of them.

The three conditions

  1. iOS or iPadOS 16.4 or later.
  2. Opened from the Home Screen. The user taps Share, then Add to Home Screen, and opens the site from that icon. In a Safari tab the page has no PushManager at all.
  3. A manifest with display set to standalone or fullscreen. Without it, the Home Screen icon opens a Safari tab and condition 2 fails.

And one rule for the prompt: Notification.requestPermission() must run from a tap. On page load it is ignored.

The manifest

{
  "name": "Example",
  "short_name": "Example",
  "id": "/",
  "start_url": "/",
  "display": "standalone",
  "icons": [{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }]
}
<link rel="manifest" href="/manifest.webmanifest" />

The id matters on iOS: it identifies the installed web app, and Focus settings follow it across the user’s devices.

Detect, then guide the user

Detect features, not browsers. On an iPhone without PushManager, the useful answer is a short “add to Home Screen” hint:

const isIOS = /iPhone|iPad|iPod/.test(navigator.userAgent) || (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
const standalone = window.matchMedia("(display-mode: standalone)").matches || navigator.standalone === true;

if ("PushManager" in window && "serviceWorker" in navigator) {
  showEnableButton();
} else if (isIOS && !standalone) {
  showHint("To get notifications, tap Share, then Add to Home Screen, and open the app from there.");
}

Ask from a tap

enableButton.addEventListener("click", async () => {
  const permission = await Notification.requestPermission(); // first line in the handler
  if (permission !== "granted") return;
  const reg = await navigator.serviceWorker.ready;
  const sub = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: VAPID_PUBLIC_KEY });
  await fetch("/api/push/subscribe", { method: "POST", body: JSON.stringify(sub) });
});

Fetch anything you need, such as the VAPID key, before the tap. An await fetch() between the tap and requestPermission() can lose the gesture.

The service worker

self.addEventListener("push", (event) => {
  const { title, body, url } = event.data.json();
  event.waitUntil(self.registration.showNotification(title, { body, data: { url } }));
});

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

Always show a notification for every push. Safari expects each push to produce one (userVisibleOnly: true), and silent pushes are not supported.

Badges

iOS 16.4 also added the Badging API for Home Screen web apps: navigator.setAppBadge(3) and navigator.clearAppBadge(), from the page or from the service worker’s push handler.

Sending

The subscription’s endpoint is on web.push.apple.com. Send to it exactly as to Chrome’s or Firefox’s: an encrypted body, a VAPID Authorization header, a TTL. If your server has an allow list for outgoing requests, add *.push.apple.com. Apple is strict about the VAPID sub claim: give a real mailto: or https: value. A 403 means the VAPID header failed; a 404 or 410 means the subscription is gone. All the codes are in web push errors.

Things that still differ from Android and desktop

  • Each Home Screen install has its own permission and subscription, separate from Safari.
  • If the user removes the icon, the subscription goes with it; your next send gets a 410.
  • In the EU, Apple’s iOS 17.4 changes briefly removed Home Screen web apps, then restored them; test on current versions before relying on any one behaviour.

With SignOps

SignOps Push sends web pushes to Safari, Chrome, Edge and Firefox with VAPID keys it makes for your app, removes subscriptions that answer 404 or 410, and sends to the user’s Android and iOS apps from the same call. The web push guide has the iPhone steps, and the web push tester sends a test push to the device you open it on.

Sources: WebKit: Web Push for Web Apps on iOS and iPadOS, MDN: Push API, MDN: Badging API.

Frequently asked questions

More questions? Email us and the answer goes on this page.

hello@signops.dev
Does web push work on iPhone?

Yes, on iOS and iPadOS 16.4 and later, for a site the user has added to the Home Screen and opened from that icon. In a normal Safari tab, and in Chrome or Firefox on iPhone, the Push API is not offered to the page, so there is nothing to subscribe.

Why is PushManager undefined on iPhone?

The page is open in a Safari tab, not from the Home Screen, or the device runs a version older than iOS 16.4. Detect the feature with "PushManager" in window and, if it is missing on an iPhone, show the user how to add the site to the Home Screen.

Do I need an Apple Developer account for web push on iOS?

No. Web push on iOS uses the same standard Push API and VAPID keys as Chrome and Firefox. You do not need an Apple Developer Program membership or an APNs key. Allow your server to reach push endpoints on *.push.apple.com.

Why does Notification.requestPermission() do nothing on iPhone?

Safari only shows the prompt when the call comes straight from a user action such as a tap on a button. Calling it on page load, or after an await that loses the gesture, is ignored.

Send your first push today.

Free for 1,000 push devices, 100 approvals and 1,000 passkey sign-ins a month, and 500 email codes to try. No card until you pass a free amount.