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](https://developer.chrome.com/docs/extensions/develop/concepts/permission-warnings)
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](https://developer.chrome.com/docs/extensions/develop/concepts/permission-warnings#update_permissions).

### 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](https://firebase.google.com/docs/cloud-messaging) is the Push service. Any messages being pushed to a Chrome
user will be 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](https://www.npmjs.com/package/web-push), you can host your own backend.

You can test out this library using
[web-push-codelab.glitch.me](https://web-push-codelab.glitch.me/). 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](https://en.wikipedia.org/wiki/Base64)
encoded binary value that will need to be decoded and converted to a
[Uint8Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) in order to register with the browser's [Push
manager](https://developer.mozilla.org/docs/Web/API/PushManager). 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 SERVER_PUBLIC_KEY = '_INSERT_VALUE_HERE_';
    const applicationServerKey = urlB64ToUint8Array(SERVER_PUBLIC_KEY);

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

        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](https://developer.mozilla.org/docs/Web/API/PushSubscription), an
object that contains the metadata of the Push server. Since you are using
[web-push-codelab.glitch.me](https://web-push-codelab.glitch.me/), 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: "${event.data.text()}"`);
    });

With your listener in place, you can submit a message on
[web-push-codelab.glitch.me](https://web-push-codelab.glitch.me/), 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](https://developer.chrome.com/blog/push-notifications-on-the-open-web). For a
complete version of the example covered here, there is one available in our
[extensions sample repo](https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/cookbook.push).

### 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](https://developer.mozilla.org/docs/Web/API/Notifications_API/Using_the_Notifications_API). 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](https://chromiumdash.appspot.com/commit/f6a8800208dc4bc20a0250a7964983ce5aa746f0%5D), extensions
are able to set [userVisibleOnly](https://developer.mozilla.org/docs/Web/API/PushSubscriptionOptions/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,
      applicationServerKey
    });