Pushpad
Articles › Troubleshooting, Web Push Notifications

Web push subscription age affects delivery rates

  • # deliverability
  • # push-api

This article investigates one of the reasons that negatively impact delivery rates for web push. First it shows that web push subscriptions can last many years without expiring, then it proves a negative correlation between the age of a web push subscription and its expected delivery rate.

Introduction

Delivery rates for web push can be low and this is caused by many factors, including poor internet connectivity and devices that kill background processes. However one of the main reasons is the presence of old, unused subscriptions that last for long periods of time. Those subscriptions are probably associated to devices or browsers that aren't used anymore. However we can't exclude that some browsers may also fail to notify the push service about push subscription deactivation (see this bug for example). The result is the presence of endpoints (which are like mailboxes) that are not checked, thus decreasing the average delivery rates of web push notifications.

You expect that a subscription that is not checked for a long time gets automatically removed or marked as expired by the browser push service, but this is not always true, as shown by this study.

Age of web push subscriptions

How long does a web push subscription last before expiring? This actually depends on the implementation of the browser and the browser push service (e.g. Google FCM, Mozilla Autopush, etc.). The standard (i.e. W3C Push API, IETF WebPush) doesn't enforce an expiration and leaves the decision to the browser manufacturer. The result is the presence of legacy subscriptions that last for several months or even years. The following chart shows the age distribution of subscriptions for a three-years old project with about 8k active subscriptions:

The chart shows the age of the subscriptions that currently return valid status codes (e.g. HTTP 2xx). Expired subscriptions that return 404 Not Found or 410 Gone are not present because they get deleted immediately.

The following charts show into more detail the age of subscriptions for different browsers / push services.

Age of Google FCM / GCM endpoints, that are used by Chrome and other browsers like Opera on Android

Age of Mozilla Autopush endpoints, that are used by Firefox

Age of Microsoft WNS endpoints, that are used by Edge (Push API support was added only a few months ago)

All push services have long lasting subscriptions.

Delivery rate for old web push subscriptions

There's nothing wrong with having old subscriptions... if they are still valid and checked by the browser. However this study shows that older subscriptions have lower delivery rates compared to more recent subscriptions.

Data is based on a notification sent to about 8k valid subscriptions. Delivery rate was observed after 3 days and only a negligible increment was observed in the next days.

Recent subscriptions show delivery rates near 70%, while after a quarter the delivery rate is reduced to a half. After 9 months the average delivery rate falls below 10%. Finally after 2 years and a half the delivery rate is only 2%.

The low delivery rates for old endpoints can be easily explained by the fact that it is more likely that an old subscription belongs to an abandoned device or browser. However what it is not clear is why the browser push service (e.g. Google FCM, Mozilla Autopush, etc.) keeps old subscriptions that are not checked anymore. Basically they keep returning 2xx status codes instead of deleting the subscription and returning 404 / 410.

Who should remove the old subscriptions?

The question is: who should remove the old, inactive subscriptions? Is it the browser (e.g. Chrome), the push service (e.g. Google FCM) or the application server (e.g. Pushpad)?

The browser behavior is described by the Push API standard:

When a push subscription is deactivated, both the user agent and the push service MUST delete any stored copies of its details.

It is important that all browsers properly notify their push service when a subscription is deactivated / refreshed, otherwise the old subscription cannot be marked as expired in a promptly manner. The standard says "MUST", so it is correct. However we still have doubts about possible buggy behaviors in the implementations, for example in case of poor internet connectivity.

In any case this mechanism is not sufficient when a user gets rid of a device or stops using a given browser. In this scenario the browser cannot notify its push service.

There is a feature described by the Push API that would solve this scenario, ensuring the eventual removal of old subscriptions: indeed a push subscription can have an expirationTime associated to it. However that attribute is optional and no current browser uses that: Chrome and Opera set it to null, while Firefox doesn't support it.

If the browser cannot solve this issue, then probably the right place to remove the old subscriptions is the push service (e.g. Google FCM, Mozilla Autopush, etc.). For a push service it would be easy to detect a browser that it is inactive for a long period (e.g. 2 months) and delete its subscription. However, based on the data reported above, most push services don't do that in a reliable way, thus keeping many useless subscriptions.

It would be interesting to have information about that from each browser push service, because this is implementation specific. The WebPush standard unfortunately doesn't enforce a subscription expiration due to inactivity. The section about Subscription Expiration only says:

A push service MAY expire a subscription at any time.

Finally you can wonder whether the application server (e.g. Pushpad) should delete the endpoints if they don't send notification receipts for some time. The answer is no, because it is not safe and it is not the right place.

For example a subscription may not receive notifications for a long time and thus it does not produce delivery receipts... however that subscription is still valid. The browser push service is a better place to check for inactive subscriptions because a browser connects to its push service frequently to check for incoming messages, even if there aren't any messages.

Is there any workaround to increase delivery rates?

As explained above, we don't believe that an application server (e.g. Pushpad) is the right place to detect and delete inactive subscriptions: if a subscription keeps returning valid status codes and it is not marked as expired by the push service, then we keep that subscription. Basically we need to accept that web push delivery rates can be low for the above reasons: it is not a bug and active users receive the notifications properly. Only the average delivery rate is affected, not the service itself.

However, given the data above, we understand that some Pushpad customers may decide to target only devices with higher delivery rates: you can check out this simple solution that shows how to target only recently active users.

Finally we hope that in the future the browser push services will implement better mechanisms to remove the inactive subscriptions. It would also be useful if all browsers could set an expirationTime on all generated subscriptions.

Further discussion and updates