Use Web Push

In extensions you can use any Push provider to send push notifications and messages. A push from the Push API will be processed by your service worker as soon as it is received. If the service worker has been suspended, a Push will wake it back up. The process to use it in extensions is exactly the same as what you would use it on the open web.

Get permission to use the Push API

When you register a Push server on a normal website, the user is shown a permission prompt to grant or deny it. With extensions that prompt won't be shown. In order to use the Push API in your extension, you need to set the notifications permission in your manifest.json

    "manifest_version": 3,
    "permissions": ["notifications"]

If you are missing this permission, then any interaction with registration.pushManager will result in an immediate error, the same result as if the user has denied the permission. Additionally, keep in mind that the notifications permission will cause a permission warning to be displayed on install. Chrome will also disable the extension for any existing installs until the user approves the new permission request. You can learn more about how to handle this in the permission warning guide.

Push providers and Push services

Once you have added the permission to your manifest.json, you will need to configure the connection between your backend and the extension. This connection can be thought of in two parts - the Push provider, and the Push service. A provider is the SDK being used by you to send the message to the Push service. There are many different options, and any Push provider can work for the Push API (though they may not offer an SDK that makes it simple to integrate). You will need to experiment with your provider's SDK to see what is possible. A Push service is what the end user's device is registered with, so it can be alerted to any push message sent by a Push provider. This is something that you have no control over, as it is hardcoded into individual browsers. For Chrome, Firebase Cloud Messaging is the Push service. Any messages being pushed to a Chrome user will routed through it.

Self hosting a Push provider

Any Push provider can work, however not all providers offer an SDK that works in service workers. You will need to consult your provider if you have issues getting it running. You don't need to use a public provider, however. Using libraries like web-push, you can host your own backend.

You can test out this library using Specifically, you will need to copy the Push server's VAPID public key in order to generate the Push subscription in the browser. This public key is actually a base64 encoded binary value that will need to be decoded and converted to a Uint8Array in order to register with the browser's Push manager. There are libraries available to perform this logic, but the following is all that is needed.

function urlB64ToUint8Array(base64String) {
  const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');

  const rawData = atob(base64);
  const outputArray = new Uint8Array(rawData.length);

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  return outputArray;

That value provided is passed into Push manager

const applicationServerKey = urlB64ToUint8Array(SERVER_PUBLIC_KEY);

async function subscribe() {
  try {
    let subscription = await self.registration.pushManager.subscribe({
      userVisibleOnly: true,

    console.log(`Subscribed: ${JSON.stringify(subscription,0,2)}`);

    return subscription
  } catch (error) {
    console.error('Subscribe error: ', error);

const subscription = await subscribe();

The subscribe function returns a PushSubscription, an object that contains the metadata of the Push server. Since you are using, this value needs to be copied to the Push Subscription portion of the page.

Once you have the PushSubscription, you are ready to register a listener for push messages in our extension's service worker.

self.addEventListener('push', function (event) {
  console.log(`Push had this data/text: "${}"`);

With your listener in place, you can submit a message on, and messages will be logged into the service worker's console.

Since it is an open web standard, there is a lot of existing documentation on how to implement Web Push, including on Chrome's blog. For a complete version of the example covered here, there is one available in our extensions sample repo.

Silent Push

You have been able to receive a Push notification in your Manifest v3 extension since Manifest v3 was introduced in Chrome 88. However, there had always been the requirement that the notification showed some kind of user visible prompt, like a Web Notification. This made it a lot less useful if you wanted to push commands or data updates to your extension without bothering the user with unnecessary information. As of Chrome 121, extensions are able to set userVisibleOnly to false. You can now send silent, non user facing push notifications to your users. In order to use this, set userVisibleOnly to false when you call pushManager.subscribe.

let subscription = await self.registration.pushManager.subscribe({
  userVisibleOnly: false,