Ding! You got a notification, but does it cause a little bump of dopamine or a slow drag of cortisol?
The difference between “Ooo, a new message!” and, “Oh, spare me!” are unique to your own situation, but both are visually dependent on badges.
Specifically, the Badging API allows progressive web applications (PWAs) to display notification badges on their icons like native applications.
For example, here’s a familiar visual with counters at the top-right corner of each app:
The Badging API allows progressive web apps to display these icon notification badges.
I’m going to show you how the Badging API works and its current state of compatibility. Then I’ll you walk through a brief tutorial to see the API in action.
Finally, using the Badging API in the main thread of a web application is straightforward, so I’ll go over how to use it in the background of a web application through worker threads.
I’m crossing my fingers that you’ll experience a rush of dopamine by the time you’re done reading and implementing what we’ve learned. 🤞
The navigator
object provides two methods for the Badging API:
navigator.setAppBadge()
for displaying the notification badgenavigator.clearAppBadge()
for removing the badgeThe navigator.setAppBadge()
method takes in a number input greater than 0
to display on the badge, like this example to display the number 22
in a notification badge:
navigator.setAppBadge(22)
Passing 0
removes the notification badge the same way calling navigator.clearAppBadge()
without any argument clears the badge:
navigator.setAppBadge(0) navigator.clearAppBadge() // They both do the same thing
As of writing this guide the Badging API isn’t widely supported:
How the Badging API is implemented across supported browsers varies. The API may not look or function the same way across the browsers that support it.
Lastly, the Badging API is only available to web applications that are delivered using the HTTPS protocol and localhost on supported browsers. You most likely won’t have to worry, but if you have any issues with it and you’re using a supported browser, this could be helpful to know.
To better understand the Badging API, we’ll look at a step-by-step process of building a simple reminder web application that would use it.
Before building the project, let’s start with a basic structure:
reminder-app/ |-- index.html |-- style.css |-- app.js |-- manifest.json
We’ll use a simple HTML and style for our app. Here it is for index.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Reminder PWA</title> <link rel="manifest" href="manifest.json"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>Reminder PWA</h1> <input type="text" id="reminder-input" placeholder="Enter a reminder"> <button onclick="addReminder()">Add Reminder</button> <button onclick="clearReminders()">Clear Reminders</button> <ul id="reminder-list"></ul> <script src="app.js"></script> </body> </html>
And here is it is for style.css
:
body { font-family: Arial, sans-serif; }
This will render something like this:
manifest.json
To make our web app progressive, you need a manifest file. The manifest file contains every information your web app needs to be installed like a native app:
{ "short_name": "Reminder", "name": "Reminder Web Application", "icons": [ { "src": "icon.png", "sizes": "192x192", "type": "image/png" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" }
The sixth line of the manifest.json
file points to an icon.png
file to use for the icon of the web app when you install it. You may need to get an image file, rename it to icon.png
, and move it to the root directory of this project.
app.js
:<let count = 0; const input = document.getElementById("reminder-input"); const list = document.getElementById("reminder-list"); function addReminder() { const item = document.createElement("li"); item.textContent = input.value; list.appendChild(item); count++; updateBadge(); input.value = ""; // Clear input after adding } function clearReminders() { list.replaceChildren(); count = 0; updateBadge(); } function updateBadge() { if ("setAppBadge" in navigator) { navigator.setAppBadge(count).catch((error) => { console.error("Badging failed:", error); }); } else { console.error("Badging API not available"); } }
The updateBadge()
function uses the Badging API to set and clear the notification badge.
Sometimes, you may want to update the application badge in the background. To do that you’ll need to use service workers.
Service workers are a type of worker threads that act as a proxy between a web application and a server. Service workers allow web applications to cache files that are important to the web application to allow offline usage, and to make use of background sync functionality.
Because they’re worker threads, they can also run in a background thread separate from the main thread of your web app.
Before you use service workers in your web application, you need to first register it. To register a service worker, add this line to the app.js
file:
<window.addEventListener(‘load’, () => { if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js'); } });
This example registers an sw.js
file as a service worker. Now, we create the sw.js
file and write the service worker code into it.
Let’s go over some basics. You can access the context of the service worker with self
. You can also attach event listeners to the contexts with the self.addEventListener()
method.
For example, if we want to perform any action when the service worker is installed, we can attach an event listener to the install
event:
<self.addEventListener("install", (event) => { console.log("Service Worker installing."); });
Similarly, we can do the same for fetching items from the server with the fetch
event:
<self.addEventListener("fetch", (event) => { console.log("Fetching:", event.request.url); });
The Badging API supports push notification and background sync events. These are events that can run in the background. This is sync
which gets triggered on background sync events:
<self.addEventListener("sync", (event) => { if ("setAppBadge" in navigator) { navigator.setAppBadge(count).catch((err) => { console.error("Badging failed:", err); }); } else { console.error("Badging not supported"); } });
This is push
which gets triggered when a push notification is passed:
<self.addEventListener("push", (event) => { if ("setAppBadge" in navigator) { const count = event.data.json().badgeCount; navigator.setAppBadge(count).catch((err) => { console.error("Badging failed:", err); }); } else { console.error("Badging not supported"); } });
Finally, I ran a simple experiment to see if you can use the Badging API outside the push
and sync
event handlers. And it turns out that you can! This is the code I added to the sw.js
file:
<let count = 0; setInterval(() => { count++; if ("setAppBadge" in navigator) { navigator.setAppBadge(count).catch((error) => { console.error("Badging failed:", error); }); } else { console.log("Badging API not available"); } }, 1000);
So far it works well on Safari and Chrome on macOS. You can close the web app window, and the badge keeps on going in the background until you quit the application, which is how most applications work.
The Badging API is a powerful tool that lets progressive web apps subtly notify its users that the internal state of the application is changed. The Badging API also makes progressive web apps feel more like native apps.
I hope this guide helps you understand the Badging API. If I’ve forgotten anything, let me know in the comments, and I might even get a notification. 😉
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]