Register for this year’s #ChromeDevSummit happening on Nov. 11-12 in San Francisco to learn about the latest features and tools coming to the Web. Request an invite on the Chrome Dev Summit 2019 website

Sending Messages with Web Push Libraries

One of the pain points when working with web push is that triggering a push message is extremely
"fiddly". To trigger a push message an application needs to make a POST request to a push
service following the web push
protocol. To use push across all
browsers you need to use VAPID
(a.k.a. application server keys) which basically requires setting a header with a value proving
your application can message a user. To send data with a push message, the data needs to be
encrypted and specific headers
need to be added so the browser can decrypt the message correctly.

The main issue with triggering push is that if you hit a problem, it's difficult to diagnose
the issue. This is improving with time and wider browser support but it's far from easy. For
this reason, I strongly recommend using a library to handle the encryption, formatting and
triggering of your push message.

If you really want to learn about what the libraries are doing, we'll cover it
in the next section. For now, we are going to look at managing subscriptions and using an
existing web push library to make the push requests.

In this section we'll be using the web-push Node
library. Other languages will have differences, but
they won't be too dissimilar. We are looking at Node since it's JavaScript and should be the
most accessible for readers.

This demo uses nedb to store the subscriptions, it's a
simple file based database, but you could use any database of your choice. We are only using this as
it requires zero set-up. For production you'd want to use something more reliable. (I tend to
stick with good old MySQL.)

Sending Push Messages

When it comes to sending a push message, we ultimately need some event to trigger the process of
sending a message to users. A common approach is creating an admin page that let's you
configure and trigger the push message. But you could create a program to run locally or any
other approach that allows accessing the list of PushSubscription's and running the code to
trigger the push message.

Our demo has an "admin like" page that lets you trigger a push. Since it's just a demo it's a
public page.

I'm going to go through each step involved in getting the demo working. These will be baby
steps so everyone can follow along, including anyone who is new to Node.

When we discussed subscribing a user, we covered adding an applicationServerKey to the
subscribe() options. It's on the back end that we'll need this private key.

In the demo, these values are added to our Node app like so (boring code I know, but just want
you to know there is no magic):

Now we can start to use the web-push module. First we need to tell the web-push module about
our application server keys. (Remember they are also known as VAPID keys because that's the name
of the spec.)

Note that we also included a "mailto:" string. This string needs to be either a URL or a mailto
email address. This piece of information will actually be sent to the web push service as part of
the request to trigger a push. The reason this is done is so that if a web push service needs
to get in touch with the sender, they have some information that will enable them to.

With this, the web-push module is ready to use, the next step is to trigger a push message.

The demo uses the pretend admin panel to trigger push messages.

Clicking the "Trigger Push Message" button will make a POST request to /api/trigger-push-msg/,
which is the signal for our backend to send push messages, so we create the route in
express for this endpoint:

app.post('/api/trigger-push-msg/', function (req, res) {

When this request is received, we grab the subscriptions from the database and
for each one, we trigger a push message.

The call to webpush.sendNotification() will return a promise. If the
message was sent successfully the promise will resolve and there is
nothing we need to do. If the promise rejects, you need to examine the
error as it'll inform you as to whether the PushSubscription is still
valid or not.

To determine the type of error from a push service it's best to look at the status code. Error
messages vary between push services and some are more helpful than others.

In this example, it checks for status codes 404 and 410, which are the HTTP status codes for
'Not Found' and 'Gone'. If we receive one of these, it means the subscription has expired
or is no longer valid. In these scenarios, we need to remove the subscriptions from our database.

In case of some other error, we just throw err, which will make the promise returned by
triggerPushMsg() reject.

We'll cover some of the other status codes in the next section when we look at the web push
protocol in more detail.

Note: If you hit problems at this stage, it's worth looking at the error logs from Firefox before
Chrome. The Mozilla push service has much more helpful error messages compared to Chrome / FCM.

After looping through the subscriptions, we need to return a JSON response.