The Push API provides webapps with scripted access to server-sent messages, for simplicity referred to here as push messages, as delivered by push services. A push service allows an application server to send messages to a webapp, regardless of whether the webapp is currently active on the user agent. The push message will be delivered to a Service Worker, which could then store the message's data or display a notification to the user.

This specification is designed to promote compatibility with any delivery method for push messages from push services to user agents.

Introduction

As defined here, push services support delivery of application server messages in the following contexts and related use cases:

This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.

Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]].

Dependencies

The terms event handler, event handler event type, queue a task, and fire a simple event are defined in [[!HTML5]].

Promise, and JSON.parse are defined in [[!ECMASCRIPT]].

EventInit, DOMException, AbortError, InvalidStateError, SecurityError, NetworkError, and steps for constructing events are defined in [[!DOM]].

The terms service worker, service worker registration, installing worker, waiting worker, and active worker, and the types ServiceWorkerRegistration, ServiceWorkerGlobalScope, ExtendableEvent, and ExtendableEventInit are defined in [[!SERVICE-WORKERS]].

The algorithms utf-8 encode, and utf-8 decode are defined in [[!ENCODING]].

Blob is defined in [[!FILEAPI]].

Any, ArrayBuffer, BufferSource, and USVString are defined in [[!WEBIDL]].

Concepts

Webapp

The term webapp refers to a Web application, i.e. an application implemented using Web technologies, and executing within the context of a Web user agent, e.g. a Web browser or other Web runtime environment.

The term application server refers to server-side components of a webapp.

Push message

A push message is an indication to a webapp that there is new information for it from the application server. All or part of this information MAY be contained in the push message itself.

A push message MUST be delivered to the active worker associated with the push subscription to which the message was submitted. If the worker or its webapp is not currently running, the worker must be started to enable delivery.

Push subscription

A push subscription is a message delivery context established between the user agent and the push service on behalf of a webapp, and associated with the webapp's service worker registration. A push subscription MUST NOT persist longer than its associated service worker registration, but it MAY be deactivated earlier.

When a push subscription is deactivated both the user agent and the push service MUST delete any stored copies of its details. Further push messages for this push subscription MUST NOT be delivered.

A push subscription has an associated endpoint. It MUST be the absolute URL exposed by the push service where the application server can send push messages to. It MAY be the same for all push subscriptions associated with a push service.

A push subscription has an associated subscription id. It is used by the application server to indicate the target of the push messages that it submits to the push service. Each pair of subscription id and endpoint MUST be globally unique.

Push service

The term push service refers to an overall end-to-end system that allows application servers to send push messages to a webapp. A push service has a server reachable at an associated endpoint. Such servers typically expose APIs specific to the push service, e.g. for push message delivery initiation.

Permission

The term express permission refers to an act by the user, e.g. via user interface or host device platform features, via which the user approves the permission of a webapp to access the Push API.

Security and privacy considerations

User agents MUST NOT provide Push API access to webapps without the express permission of the user. User agents MUST acquire consent for permission through a user interface for each call to the subscribe() method, unless a previous permission grant has been persisted, or a prearranged trust relationship applies. Permissions that are preserved beyond the current browsing session MUST be revocable.

When a permission is revoked, all push subscriptions created with that permission MUST be deactivated.

When a service worker registration is unregistered, any associated push subscription MUST be deactivated.

The subscription id of a deactivated push subscription MUST NOT be reused for a new push subscription. This prevents the creation of a persistent identifier that the user cannot remove. This also prevents reuse of the details of one push subscription to send push messages to another push subscription.

User agents MUST implement the Push API to be HTTPS-only. SSL-only support provides better protection for the user against man-in-the-middle attacks intended to obtain push subscription data. Browsers may ignore this rule for development purposes only.

Push Framework

Although push services are expected to differ in deployment, a typical deployment is expected to have the following general entities and example operation for delivery of push messages:

This overall framework allows application servers to inform webapps that new data is available at the application server, or pass the new data directly to the webapp in the push message.

The push API enables delivery of arbitrary application data to webapps, and makes no assumptions about the over-the-air/wire protocol used by push services. As such, the details of what types of data flow through a push services for a particular webapp are specific to the push service and webapp. As needed, clarification about what data flows over-the-air/wire should be sought from push service operators or webapp developers.

The following code and diagram illustrate a hypothetical use of the push API.

Example

// https://example.com/serviceworker.js
this.onpush = function(event) {
  console.log(event.data);
  // From here we can write the data to IndexedDB, send it to any open
  // windows, display a notification, etc.
}

// https://example.com/webapp.js
navigator.serviceWorker.register('serviceworker.js').then(
  function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe().then(
      function(pushSubscription) {
        console.log(pushSubscription.subscriptionId);
        console.log(pushSubscription.endpoint);
        // The push subscription details needed by the application
        // server are now available, and can be sent to it using,
        // for example, an XMLHttpRequest.
      }, function(error) {
        // During development it often helps to log errors to the
        // console. In a production environment it might make sense to
        // also report information about errors back to the
        // application server.
        console.log(error);
      }
    );
  });

Sequence diagram

Example flow of events for subscription, message delivery, and unsubscription
Example flow of events for subscription, message delivery, and unsubscription

Push Service Discovery and API Use

This specification does not define either specific normative methods via which webapps can determine the applicable push service, or initiate push requests through that service via a push service API. While these limitations add complexity for webapp developers, they reflect the current reality of a diversity of push services, for which convergence at least on an API level, is not expected to be a short-term possibility. While a converged push service API is a worthwhile goal and may be addressed in a different specification, the Push API defined here has been designed to enable the current variety of push services to be used as appropriate for the webapp host device or software platform. This section provides examples of how a webapp can be designed to work with a variety of hypothetical push services as needed.

The Push API provides several interface parameters and attributes that can enable a webapp to deliver and obtain the necessary push service specific data enabling use of that particular push service. These parameters and attributes include:

Push services that are compatible with the Push API will be expected to clarify how these data are used in their APIs, e.g. through their developer programs. Examples of considerations include:

The Push API does not provide any PushSubscription attributes that normatively identify the particular push service that applies to the subscription. Webapps that are designed to work with a single push service are assumed to know inherently how to use the API of that service. For such webapps, a key consideration is ensuring that if the webapp is used on a device or browser that does not support the necessary push service, that either the user is informed that the push-dependent webapp functions will not work, or the webapp must use alternate methods e.g. [[websockets]] or [[SSE]] to deliver the server-initiated data.

Prior to use of a push service API, application servers that are designed to work with multiple push services may need to determine the applicable service by parsing the endpoint to detect the push service from the URI domain.

Extensions to the ServiceWorkerRegistration interface

The Service Worker specification defines a ServiceWorkerRegistration interface [[!SERVICE-WORKERS]], which this specification extends.

readonly attribute PushManager pushManager

The pushManager attribute exposes a PushManager, which has an associated service worker registration represented by the ServiceWorkerRegistration on which the attribute is exposed.

PushManager interface

The PushManager interface defines the operations to access push services.

Promise<PushSubscription> subscribe ()
Promise<PushSubscription?> getSubscription ()
Promise<PushPermissionStatus> hasPermission ()

The subscribe method when invoked MUST run the following steps:

  1. Let promise be a new Promise.
  2. Return promise and continue the following steps asynchronously.
  3. If the scheme of the document url is not https, reject promise with a DOMException whose name is "SecurityError" and terminate these steps.
  4. Let registration be the PushManager's associated service worker registration.
  5. If registration has no active worker, run the following substeps:
    1. If registration has no installing worker and no waiting worker, reject promise with a DOMException whose name is "InvalidStateError" and terminate these steps.
    2. Wait for the installing worker or waiting worker of registration to become its active worker.
    3. If registration fails to activate either worker, reject promise with a DOMException whose name is "InvalidStateError" and terminate these steps.
    4. Once registration has an active worker, proceed with the steps below.
  6. Ask the user whether they allow the webapp to receive push messages, unless a prearranged trust relationship applies or the user has already granted or denied permission explicitly for this webapp.
  7. If not granted, reject promise with a DOMException whose name is "PermissionDeniedError" and terminate these steps.
  8. If the webapp is already subscribed, run the following substeps:
    1. Retrieve the push subscription associated with the webapp.
    2. If there is an error, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
    3. When the request has been completed, resolve promise with a PushSubscription providing the details of the retrieved push subscription.
  9. Make a request to the push service to create a new push subscription for the webapp.
  10. If there is an error, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
  11. When the request has been completed, resolve promise with a PushSubscription providing the details of the new push subscription.

The getSubscription method when invoked MUST run the following steps:

  1. Let promise be a new Promise.
  2. Return promise and continue the following steps asynchronously.
  3. If the webapp is not subscribed, resolve promise with null.
  4. Retrieve the push subscription associated with the webapp.
  5. If there is an error, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
  6. When the request has been completed, resolve promise with a PushSubscription providing the details of the retrieved push subscription.

The hasPermission method when invoked MUST run the following steps:

  1. Let promise be a new Promise.
  2. Return promise and continue the following steps asynchronously.
  3. Retrieve the push permission status (PushPermissionStatus) of the requesting webapp
  4. If there is an error, reject promise with no arguments and terminate these steps.
  5. When the request has been completed, resolve promise with PushPermissionStatus providing the push permission status.

Permission to use the push service can be persistent, that is, it does not need to be reconfirmed for subsequent subscriptions if a valid permission exists.

If there is a need to ask for permission, it needs to be done by invoking the subscribe method.

PushSubscription interface

A PushSubscription object represents a push subscription.

readonly attribute USVString endpoint
readonly attribute DOMString subscriptionId
Promise<boolean> unsubscribe ()

When getting the endpoint attribute, the user agent MUST return the endpoint associated with the push subscription.

When getting the subscriptionId attribute, the user agent MUST return the subscription id associated with the push subscription.

The unsubscribe method when invoked MUST run the following steps:

  1. Let promise be a new Promise.
  2. Return promise and continue the following steps asynchronously.
  3. If the push subscription has already been deactivated, resolve promise with false and terminate these steps.
  4. Make a request to the push service to deactivate the push subscription.
  5. If it was not possible to access the push service, reject promise with a "NetworkError" exception and terminate these steps.
  6. When the request has been completed, resolve promise with true.

PushMessageData interface

ArrayBuffer arrayBuffer ()
Blob blob ()
Any json ()
USVString text ()

PushMessageData objects have an associated bytes (a byte sequence) set on creation.

The arrayBuffer() method, when invoked, MUST return an ArrayBuffer whose contents are bytes.

The blob() method, when invoked, MUST return a Blob whose contents are bytes and type is not provided.

The json() method, when invoked, MUST return the result of invoking the initial value of JSON.parse with the result of running utf-8 decode on bytes as argument. Re-throw any exceptions thrown by JSON.parse.

The text() method, when invoked, MUST return the result of running utf-8 decode on bytes.

In future, PushMessageDataInit is likely to be a union type that includes types such as Blob and BufferSource. The algorithm below would be extended, rather like the Fetch standard's extract a byte stream algorithm.

To extract a byte sequence from object, run these steps:

  1. Let bytes be an empty byte sequence.
  2. Switch on object's type:
    USVString
    Set bytes to the result of running utf-8 encode on object.
  3. Return bytes.

Events

The Service Worker specification defines a ServiceWorkerGlobalScope interface [[!SERVICE-WORKERS]], which this specification extends.

attribute EventHandler onpush
attribute EventHandler onpushsubscriptionchange

The onpush attribute is an event handler whose corresponding event handler event type is push.

The onpushsubscriptionchange attribute is an event handler whose corresponding event handler event type is pushsubscriptionchange.

The push event

The PushEvent interface represents a received push message.

readonly attribute PushMessageData data
PushMessageDataInit data

Upon receiving a push message for a push subscription from the push service the user agent MUST run the following steps:

  1. If the Service Worker associated with the webapp is not running, start it.
  2. Let scope be the ServiceWorkerGlobalScope of the Service Worker associated with the webapp.
  3. Let event be a new PushEvent, whose data attribute is a new PushMessageData with bytes set to the binary message data received by the user agent in the push message, or an empty byte sequence if no data was received.
  4. Queue a task to fire event as a simple event named push at scope.

When a constructor of the PushEvent interface, or of an interface that inherits from the PushEvent interface, is invoked, the usual steps for constructing events MUST be modified as follows: instead of setting the data attribute of the event to the value of the eventInitDict's "data" member, set the data attribute to a new PushMessageData with bytes set to the result of extracting a byte sequence from that dictionary member, or an empty byte sequence if eventInitDict is not provided or has no "data" member.

The pushsubscriptionchange event

The pushsubscriptionchange event indicates that a push subscription has been invalidated, or will soon be invalidated. For example, the push service MAY set an expiration time. A webapp SHOULD attempt to resubscribe while handling this event, in order to continue receiving push messages.

To fire a pushsubscriptionchange event, the user agent MUST run the following steps:

  1. If the Service Worker associated with the webapp is not running, start it.
  2. Let scope be the ServiceWorkerGlobalScope of the Service Worker associated with the webapp.
  3. Queue a task to fire a simple event named pushsubscriptionchange at scope.

Enumerations

granted
denied
default
Enumeration Description
granted The webapp has permission to use the Push API.
denied The webapp has been denied permission to use the Push API.
default The webapp needs to ask for permission in order to use the Push API.

Exceptions

The Push API uses the following new DOMException names.

Name Description
PermissionDeniedError The operation failed because the user denied permission to use the API.

Acknowledgements

The editors would like to express their gratitude to the Mozilla and Telefónica Digital teams implementing the Firefox OS Push message solution and specially to Doug Turner, Nikhil Marathe, Fernando R. Sela, Guillermo López, Antonio Amaya, José Manuel Cantera and Albert Crespell, for their technical guidance, implementation work and support.