Using Push Notifications in Progressive Web Apps

Push Notification in PWAs

Push Notifications in PWAs

We all know that push notifications are those nifty little messages that pop up on your phone or desktop, keeping you in the loop with updates, reminders, and important info from your favorite apps. They’re like a friendly tap on the shoulder, ensuring you never miss a beat.

Push notifications in PWAs are a great way to keep users informed and engaged. By implementing push notifications, you can send messages and updates directly to their devices, just like mobile apps do. It’s a powerful tool to grab their attention and provide timely information. Let’s explore how you can leverage push notifications in your PWA to enhance the user experience and drive engagement.

We have an elegant and subtle way to notify users of something new – a badge over the app icon. Badges are familiar to mobile app users, as they are small graphical elements placed on the app icon. They can be seen on the home screen or taskbar, depending on the platform. Typically, a badge appears as a colored circle with a number indicating new items, such as unread messages in a mailbox.

This mechanism can also be used for web applications using the Badging API. It applies specifically to installed web applications with offline support via a service worker and correct web app manifest. To learn more about it, check the blog “Building Offline Capabilities with Service Workers in PWAs”

To implement a badge over the app icon, you can choose between two methods: `setAppBadge()` and `clearAppBadge()`. In this scenario, let’s say we want to notify the user about 3 new messages in their mailbox.

// Check if the API is supported
if ('setAppBadge' in navigator) {
navigator.setAppBadge(3).catch((error) => {
// Code to handle an error

To remove a badge:




This is what an app icon with a badge looks like;

Push Notification in PWAs


Managing badges is possible in both the main application and the service worker. In the service worker, two events play a role:

The “push” event allows for controlled timing of notification requests, but it comes with limitations and requirements from the Push API. Additionally, displaying a browser-native notification is mandatory.

The “periodicsync” event enables badge updates in the background, but it is subject to the limitations of the Periodic Background Sync API. The timing of syncs depends on the browser’s Site Engagement index, which can result in several hours between updates.

While there isn’t a perfect method for badge management in the service worker at present, ongoing discussions focus on improving the integration between the Push API and badging.

Push notifications, popular on mobile platforms, are now available on the web, providing a valuable way to keep users informed. They allow you to send titles, descriptions, URLs, and images from your backend to users’ devices. App owners can effectively re-engage their user base with push notifications. Here’s what you need to know:

They use native controls from the operating system or browser, ensuring a seamless experience for developers and users.

Users explicitly choose to receive push notifications and can opt out anytime. They can also block notifications using platform-specific tools on mobile and web.

Push notifications can reach users’ devices even when the app is not open, thanks to event handling in the web platform’s service worker.

A third-party “Messaging Service” handles subscriptions and message delivery independently. As a developer, you can leverage this service for subscription, unsubscription, and sending notifications via the Push API. Best of all, it’s free to use, and you don’t have to choose a specific Messaging Service explicitly.

Implementing push notifications on the PWA includes multiple steps:

Step 1. Getting credentials

Generate a set of “VAPID keys” to authenticate user devices with the Messaging Service. Each app requires its own set of keys, including a public and private key. You can use tools like the web-push module or free online services to generate these keys. If you choose to use the web-push module, you can follow these steps:

npm install web-push -g
web-push generate-vapid-keys –json

Step 2: Subscribing and saving

Once the user has given explicit consent to receive push notifications (e.g., by clicking a button in the user interface), you can use the `subscribe()` method of the PushManager interface. This method is available on the active service worker registration.

As a best practice, it is recommended to hide or disable any relevant UI controls if the browser does not support the Push API.

if (!('PushManager' in window)) {// Code to disable or hide push-related UI controls
console.log('Push API is not supported');

“Subscribe” button handler (for the sake of the example, the code is simplified and doesn’t contain error handling):

async function subscribeForPush() {
const registration = await navigator.serviceWorker.ready;

const pushSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true, // Should be always true as currently browsers only support explicitly visible notifications
applicationServerKey: 'publicKey from Step 1 converted to Uint8Array'

// Send push subscription to our server to persist it

Once the subscription process is completed, there are several options available to enhance the user experience:

Request the subscription status from the Messaging Service by using the `getSubscription()` method. This allows you to set the initial status for subscription UI controls.

It’s recommended to check and request permission for notifications using the Notifications API before initiating the subscription process. This provides you with more control over when the permission prompt is displayed. If you skip this step, calling `subscribe()` will prompt the user to grant or deny notification permission.

Implement the logic for unsubscription and include corresponding UI controls. It’s preferable to provide users with the ability to unsubscribe through your app, as they can easily resubscribe if desired. This approach is more user-friendly compared to having users block your origin using browser settings, which would require them to unblock your origin again if they wish to resubscribe.

You can refer to an extended code sample that includes a method for converting the publicKey to Uint8Array by following this link.

Step 3: Sending a notification

In your backend, iterate through the push subscription objects obtained and saved in Step 2. For each subscription, send a special HTTPS request to the Messaging Service. It’s worth noting that web push notifications allow you to target specific user devices by including user-identifying data (e.g., internal user ID) alongside the push subscription object. This enables you to send notifications to specific users rather than broadcasting to all devices.

To construct the request according to the Web Push protocol, you will need the following:

  • The endpoint field from the subscription object, which is a URL of the Messaging Service with a unique device token.
  • The VAPID keys generated in Step 1.
  • The payload you wish to send as the notification, often serialized as a JSON object following the Notification specification.

For NodeJS backends, you can simplify the process by using the `sendNotification()` method provided by the web-push module. Similar libraries are available for other platforms.

Once your request is received by the Messaging Service, it will deliver the push notification to

the user’s device.

Step 4. Receiving and displaying

To receive a notification, a service worker on the user device listens for the push event and handles it:

self.addEventListener('push', (event) => {
const notificationData = JSON.parse(;

self.registration.showNotification(notificationData.title, {
body: notificationData.message,
icon: notificationData.icon

To handle user actions, you can implement handlers for the `notificationclick` and `notificationclose` events within the service worker.

When it comes to push notifications on the web, there are a few additional points worth noting:

You can customize the notification by including data sent as a payload from your server (via the Messaging Service). Additionally, before displaying the notification, you can make additional API calls to retrieve extra data. However, it’s important to be mindful of the limited execution time of the service worker. Any operations performed before calling `showNotification()` should not be overly time-consuming.

In a service worker, it is mandatory to use the `showNotification()` method upon receiving a push event. This ensures that a native notification is displayed to the user, except for one specific exception. Failing to call this method or calling it incorrectly will still result in a notification being shown, informing the user that “something has happened with your app in the background” (the exact wording is determined by the browser). This measure is in place to prevent malicious apps from waking up service workers without the user’s knowledge or consent.

For more information on Progressive Web Apps (PWAs), you can refer to these articles on

“Advantages of Progressive Web Apps (PWAs) Over Native Apps” – Read Here
“How to Convert an Existing Website to a Progressive Web App (PWA)?” – Read Here

Leave A Comment


Our purpose is to build solutions that remove barriers preventing people from doing their best work.

Melbourne, Australia
(Sat - Thursday)
(10am - 05 pm)