How to handle WebPush API PushSubscriptionChange event in modern browsers
The W3 specification defines a pushsubscriptionchange event in order to resubscribe to push and send the new subscription back to the server. But some browsers like Chrome hasn’t implemented it yet and others didn’t follow the specification strictly.
Anyway, this should be implemented because it’s the standard option, browsers like Firefox still supports it, and other browsers will implement it in the future.
Chrome doesn’t implement PushSubscriptionChange Event
The Problem
The PushSubscriptionChangeEvent interface looks like this:
To use this event we have to listen it in the Service Worker.
Now to renew subscription, at first it seems to be easy. We make a request to the server sending old and new subscription and server searches the old one and replace it by the new one.
But we have a problem here.
Old and new subscriptions properties are always null in all browsers currently.
This raises the following questions.
- If the new subscription is null. How can we get there?
- If the old subscription is null. How can we do to tell the server what device or user are we? Because it have to know what subscription should replace.
The solution
We can solve the first one easily by calling getSubscription() function. But to solve the second one, we need to use IndexedDb to storage current subscription for the next pushsubscriptionchange event.
The resulting code is the following:
First time, we request a subscription and user grants permissions, in the browser, so we have to send a message to service worker with action REQUEST_SUBSCRIPTION and it will save subscription in its storage.
If subscription expires sometime, service worker will update it in the server through pushsubscriptionchange event.
In the browser we can do something like:
What about Chrome?
Like I said at the beginning of the post, Chrome doesn’t implement pushsubscriptionchange event currently, that means we can listen this event for other browsers but it won’t never triggered in Chrome. So, what could we do to solve this problem?
- The only workaround at the moment is to call uploadSubscriptionToTheServer() every time the page is loaded in order to minimize the time with an invalid subscription.
- If the page could be loaded offline, then it’s possible to use background sync API to refresh subscription when browser will be online again.
This solution is not perfect, the user could lose some push notifications if he doesn’t open the webapp for a long time.