Skip to content

Web push received but not shown

Why a web push arrives but no notification shows, or Chrome shows its generic notice: waitUntil, userVisibleOnly, tag and renotify, and OS settings.

PushBy Rushi Patel, Senior iOS developerUpdated 3 November 20265 min read

Your server got 201 Created, the push reached the browser, and still nothing useful appeared. Either nothing at all, or Chrome’s generic “This site has been updated in the background”. From here on the problem is in the service worker or the device, not the sender. This page goes through each cause in the order to check them.

Symptom to cause

What you see Likely cause Fix
“This site has been updated in the background” No showNotification() before event.waitUntil() settled Show a notification on every push, inside waitUntil
Nothing, no error showNotification() called but its promise not passed to waitUntil Pass the promise; the worker can stop before it runs
Nothing, TypeError in the worker console Permission denied, or the worker is not active yet Check Notification.permission; wait for the worker to activate
subscribe() fails in Chrome or Edge userVisibleOnly missing or false Subscribe with userVisibleOnly: true
A new push replaces the old one without a sound Same tag, renotify not set Add renotify: true, or use a different tag
Works on desktop, not on iPhone Site not added to the Home Screen See web push on iOS
Arrives late or never Browser closed or computer asleep past the TTL A longer TTL, or Urgency: high for messages people wait for

“This site has been updated in the background”

Chrome requires a visible notification for every push. If your push handler does not show one before the promise you passed to event.waitUntil() settles, Chrome shows its own notice with that text. The fix is always the same shape:

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

Three ways code that looks right still triggers it:

  1. A branch that skips the notification. For example if (document is focused) return; logic, or “only show it if the data is new”. Every branch must end in showNotification().
  2. fetch first, notification after, without one chain. If you fetch content and then show it, return the whole chain to waitUntil, and show a fallback notification in catch so a failed fetch still shows something.
  3. An exception in the handler. A bad JSON.parse on a text payload throws before anything is shown. Wrap it.
self.addEventListener("push", (event) => {
  event.waitUntil((async () => {
    try {
      const { id } = event.data.json();
      const msg = await fetch(`/api/messages/${id}`).then((r) => r.json());
      await self.registration.showNotification(msg.title, { body: msg.body });
    } catch {
      await self.registration.showNotification("You have a new message");
    }
  })());
});

Silent pushes: userVisibleOnly

pushManager.subscribe() takes userVisibleOnly, a promise that every push will lead to something the user can see. Chrome and Edge reject the subscription unless it is true, so a data-only web push that updates a cache and shows nothing is not possible there. Firefox lets a site receive a limited number of pushes without a notification; pushes that show one are exempt, and the quota refreshes each time the user visits the site.

const sub = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey });

If you need to sync data in the background, show a notification as part of the same push, or sync the next time the page opens.

The notification is shown but nobody notices

  • tag replaces quietly. A notification with the same tag replaces the older one, and by default the replacement makes no sound. Set renotify: true with the tag when the user should hear it again.
  • silent: true turns off sound and vibration whatever the device settings are.
  • It closes on its own. Use requireInteraction: true if it must stay until the user clicks or dismisses it.
  • The operating system hides it. macOS and Windows have their own notification switch per browser, and Focus or Do Not Disturb hides banners. If the web push tester cannot show a notification either, the cause is here, not in your code.

Check the service worker itself

  • Open DevTools > Application > Service workers. The worker must be activated for your page’s scope, and the Push button there sends it a test push event.
  • showNotification() throws a TypeError while the worker is not activating or activated, and when the user has denied permission.
  • A worker at /js/sw.js only controls /js/. Serve it from the root, or set the Service-Worker-Allowed header.
  • After editing the worker, the old one keeps running until every tab using it closes. Tick “Update on reload” while testing.

With SignOps

SignOps Push sends the title and body you give it in the push, so your worker always has something to show. Its ready-made worker (two lines in your sw.js, see the web push guide) calls showNotification() inside waitUntil for every push that has a title or body, draws the image and up to two buttons, and opens the link on click. A push you send with neither is left to your own code, which on Chrome must still show something. The @signops/web library subscribes with userVisibleOnly: true. To rule out your server, the web push tester sends a push to this browser with no account, and web push errors covers the status codes before the push reaches the browser.

Sources: web.dev: Push events, MDN: PushManager.subscribe(), MDN: Push API, MDN: showNotification().

Frequently asked questions

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

hello@signops.dev
Why does Chrome say "This site has been updated in the background"?

Your service worker received a push but did not show a notification before the promise passed to event.waitUntil() settled. Chrome then shows its own generic notice instead. Call self.registration.showNotification() inside event.waitUntil() on every push.

Can I send a web push without showing a notification?

Not in Chrome or Edge. Both reject pushManager.subscribe() unless userVisibleOnly is true, which is a promise to show a notification for every push. Firefox allows a limited number of pushes without a notification, and the quota refreshes each time the user visits the site.

The push arrives in the service worker but nothing appears. Why?

The usual causes are a showNotification call outside event.waitUntil(), a promise that is not returned so the worker stops early, a tag that replaces an older notification quietly, notifications turned off for the browser in the operating system, or Focus or Do Not Disturb.

Why does a second notification with the same tag not alert?

A notification with the same tag replaces the older one, and by default the replacement makes no sound or vibration. Set renotify to true, together with the tag, if the user should be alerted again.

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.