push.md

5 min read Original article ↗

Push API specification for self-hosting already exists but we're not using it

Date: 2023-12-07

The dream

Let's assume you have an inexplicable urge to self-host push notifications. Or it could be because you're trying to un-google.

I use the term self-host as an easy shorthand. To be honest I don't want to self-host anything if I can avoid it. But when it becomes technically possible to self-host something, it is possible to pay someone to do that instead of you being the product. Think providers like Mullvad, Proton or Tuta. That's the end goal, not self-hosting in itself.

Also, the terminology around push technologies varies a lot. I'll be using the terminology from the diagram below this text.

Back to the urge. As a way to accomplish self-hosting I often think to myself – if only push notifications had a standard that would let the user specify a push server for the application to send messages to. But that would never happen. There's no way to convince the platforms and application developers to adopt such a standard even if there was one.

I was then surprised when another rabbit hole lead me to the Web Push API and I realized that we already have exactly that.

It is stable, it is being used, and since no one on the web can be trusted, it is also end-to-end encrypted.

The solution

Don't be fooled by the name. While it's called Web Push API the specification does not care whether your client is a browser or an Android phone and neither does the application server.

Here's a quick primer into how it works, simplifying a bit for brevity.

Subscribing for push notifications

The browser exposes a JavaScript API, with a method getSubscription() that returns JSON as below, which is then sent to and stored by the application server.

{
  "endpoint": "https://push-server.browser-vendor.test/subscription/id/...",
  "expirationTime": null,
  "keys": {
    "p256dh": "...",
    "auth": "..."
  }
}

The "endpoint" property is both the push API endpoint and the subscription ID.

Sending push notifications

If you ignore the encryption, which is what the "keys" property is for, it is astonishingly simple.

To send a push message, the application server sends a POST request to the "endpoint" URL. The push message content is the POST body.

With encryption the body is end-to-end encrypted. The application server holds keys for encryption and the client (browser in this case) holds keys for decryption.

Your own push server

Every browser vendor has their own push server but nothing in the specification prevents you from hosting your own and replacing the "endpoint" with that.

Go ahead and try it out. You can use the browser debugger to change the "endpoint" before it is sent to the application server. For the sake of testing, you can use ntfy.sh as the push server. Just replace the "endpoint" with "https://ntfy.sh/arbitrary-string-here" and use any of the ntfy clients to listen for messages sent to that endpoint. As of writing, ntfy doesn't support the encryption part yet, so you'll receive binary blobs.

If you do try it out you'll quickly realize – as I did – that the biggest obstacle is that there is no one using Web Push except for the spam industry.

Even if a web application supports notifications it is often only using the Notification API not the Push API, meaning you'll only receive notifications while the web application is open.

While that's not the only obstacle it is the biggest one.

This gets us back to the title. You might be wondering what I mean by "we".

I wish I could say that I mean anyone who wants to self-host or use self-hosted push notifications.

But since the biggest obstacle is applications, "we" also includes application developers, who have other priorities than catering to niches like this. Even if they're developing a privacy focused app (looking at you Signal).

When I got out of the Web Push API rabbit hole I had hoped that the obstacles were limited to having

  • a push client
  • a push server
  • communication between the push client and the application client

The first two of which can almost already be solved by things like UnifiedPush and ntfy.sh or Mozilla's autopush-rs.

UnifiedPush offers a solution for the communication part as well but it would, again, require cooperation from application developers. This isn't a must-have for the MVP though, as you could still receive the notifications, and maybe eventually get enough critical mass for application developers to care.

But since the obstacle here is applications not using Web Push at all we are back to it's never going to happen.

On the bright side I think an even bigger obstacle has already been overcome. That is the Push API standard I used to daydream about. With it I feel like we are on the verge of this being possible.

So I am writing this in the hope that we – as in anyone part of the diagram below – some day decide to use the Push API.