The only snippet you will need to deal with push notifications in a service worker

The only snippet you will need to deal with push notifications in a service worker

I'm working on a PWA at the moment. What a great time it is to be able to develop near native looking mobile applications without having to deal with flutter, native code, etc.

One part in particular is great: push notifications. Now that Safari 16 has added support for them, it's not realistic to actually use this in production.

Show me the snippet

I know, i know... let's get to the point of this article: the snippet.

// @link https://flaviocopes.com/push-api/
// @link https://web.dev/push-notifications-handling-messages/
self.addEventListener('push', function (event) {
  if (!event.data) {
    console.log('This push event has no data.');
    return;
  }
  if (!self.registration) {
    console.log('Service worker does not control the page');
    return;
  }
  if (!self.registration || !self.registration.pushManager) {
    console.log('Push is not supported');
    return;
  }

  const eventText = event.data.text();
  // Specify default options
  let options = {};
  let title = '';

  // Support both plain text notification and json
  if (eventText.substr(0, 1) === '{') {
    const eventData = JSON.parse(eventText);
    title = eventData.title;

    // Set specific options
    // @link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#parameters
    if (eventData.options) {
      options = Object.assign(options, eventData.options);
    }

    // Check expiration if specified
    if (eventData.expires && Date.now() > eventData.expires) {
      console.log('Push notification has expired');
      return;
    }
  } else {
    title = eventText;
  }

  // Warning: this can fail silently if notifications are disabled at system level
  // The promise itself resolve to undefined and is not helpful to see if it has been displayed properly
  const promiseChain = self.registration.showNotification(title, options);

  // With this, the browser will keep the service worker running until the promise you passed in has settled.
  event.waitUntil(promiseChain);
});

So what does this do ?

  • In your service worker (using workbox is highly recommended), define the listener for push notifications
  • Do some checks to see if the push is actually valid
  • Support push messages in both plain text and json format. The json format allows us to set custom options for each push message (body, icons, actions...)
  • I added an expiration check. Indeed, if the device is offline, it will get the push notifications as soon as it gets online. But maybe your push notifications won't be relevant anymore. If it's the case, simply pass a "expires" property along with the timestamp at which the notification expires.
  • And then, show the notification :-)
  • (and yes, I added some comments and links to make sure to remember how it works)

Happy coding :-)