The Push API enables sending of a push message to a webapp via a push service. An application server can send a push message at any time, even when a webapp or user agent is inactive. The push service ensures reliable and efficient delivery to the user agent. Push messages are delivered to a Service Worker that runs in the origin of the webapp, which can use the information in the message to update local state or display a notification to the user.

This specification is designed for use with the web push protocol, which describes how an application server or user agent interacts with a push service.

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, trusted event, and fire a simple event are defined in [[!HTML5]].

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

EventInit, DOMException, AbortError, InvalidStateError, InvalidAccessError, SecurityError, NetworkError, event listener, 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, ExtendableEventInit, extend lifetime promises, the Clear Registration algorithm, and the Handle Functional Event algorithm 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, NotAllowedError, and USVString are defined in [[!WEBIDL]].

The web push protocol [[!WEBPUSH-PROTOCOL]] describes a protocol that enables communication between a user agent or application server and a push service. Alternative protocols could be used in place of this protocol, but this specification assumes the use of this protocol; alternative protocols are expected to provide compatible semantics.

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 data sent to a webapp from an application server.

A push message is delivered to the active worker associated with the push subscription to which the message was submitted. If the service worker is not currently running, the worker is 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. Each push subscription is associated with a service worker registration and a service worker registration has at most one push subscription.

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

A push subscription is deactivated when its associated service worker registration is unregistered, though a push subscription MAY be deactivated earlier. A push subscription is removed when the clear registration algorithm is run for the service worker registration.

A push subscription has an associated push endpoint. It MUST be the absolute URL exposed by the push service where the application server can send push messages to. A push endpoint MUST uniquely identify the push subscription.

Push service

The term push service refers to a system that allows application servers to send push messages to a webapp. A push service serves the push endpoint or endpoints for the push subscriptions it serves.

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 use of the Push API by the webapp.

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.

The user agent MAY consider the PushSubscriptionOptions when acquiring permission or determining the permission status.

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 push endpoint 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

A push message is sent from an application server to a webapp as follows:

This overall framework allows application servers to activate a Service Worker in response to events at the application server. Information about those events can be included in the push message, which allows the webapp to react appropriately to those events, potentially without needing to initiate network requests.

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.endpoint);
        console.log(pushSubscription.getKey('p256dh'));
        console.log(pushSubscription.getKey('auth'));
        // 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, push message delivery, and unsubscription
Example flow of events for subscription, push message delivery, and unsubscription

Push service use

The fields included in the PushSubscription is all the information needed for an application server to send a push message. Push services that are compatible with the Push API provide a push endpoint that conforms to the web push protocol. These parameters and attributes include:

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 (optional PushSubscriptionOptionsInit options)
Promise<PushSubscription?> getSubscription ()
Promise<PushPermissionState> permissionState (optional PushSubscriptionOptionsInit options)

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 allOptions be the value of the options argument, if provided, or a PushSubscriptionOptions dictionary with default values.
  5. If allOptions includes a non-null value for the applicationServerKey attribute, check that the value is valid (i.e., ensure that it describes a valid point on the P-256 curve). If the applicationServerKey value is invalid, reject promise with an InvalidAccessError and terminate these steps.
  6. Let registration be the PushManager's associated service worker registration.
  7. 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.
  8. 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.
  9. If not granted, reject promise with a DOMException whose name is "NotAllowedError" and terminate these steps.
  10. If the Service Worker is already subscribed, run the following substeps:
    1. Retrieve the push subscription associated with the Service Worker.
    2. If there is an error, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
    3. Let subscription be the retrieved subscription.
    4. Compare allOptions with the options attribute of subscription. If any attribute on allOptions contains a different value to that stored for subscription, then reject promise with an InvalidStateError and terminate these steps. The contents of BufferSource values are compared for equality rather than references.
    5. When the request has been completed, resolve promise with subscription.
  11. Make a request to the push service to create a new push subscription for the Service Worker.
  12. If there is an error, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
  13. Let subscription be a new subscription.
  14. Set the options attribute of subscription to be a copy of allOptions.
  15. Generate a new P-256 ECDH key pair. Store the private key in an internal slot on subscription; this value MUST NOT be made available to applications. The public key is also stored in an internal slot and can be retrieved by calling the getKey method of the PushSubscription with an argument of p256dh.
  16. Generate a new authentication secret, which is a sequence of octets as defined in [[!WEBPUSH-ENCRYPTION]]. Store the authentication secret in an internal slot on subscription. This key can be retrieved by calling the getKey method of the PushSubscription with an argument of auth.
  17. 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 Service Worker is not subscribed, resolve promise with null.
  4. Retrieve the push subscription associated with the Service Worker.
  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 permissionState 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 (PushPermissionState) 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 PushPermissionState 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.

PushSubscriptionOptions Interface and Dictionary

A PushSubscriptionOptionsInit represents additional options associated with a push subscription. The user agent MAY consider these options when requesting express permission from the user. When an option is considered, the user agent SHOULD enforce it on incoming push messages.

Once set, options for a push subscription cannot change. A pre-existing push subscription can be unsubscribed to create a push subscription with new options.

boolean userVisibleOnly = false
BufferSource? applicationServerKey = null
readonly attribute boolean userVisibleOnly
[Throws] readonly attribute ArrayBuffer? applicationServerKey

The userVisibleOnly option, when set to true, indicates that the push subscription will only be used for push messages whose effect is made visible to the user, for example by displaying a Web Notification. [[NOTIFICATIONS]]

The applicationServerKey option includes an elliptic curve public key for an application server. This is the key that the application server will use to authenticate itself when sending push messages to this subscription as defined in [[!WEBPUSH-VAPID]]; the push service will reject any push message unless the corresponding private key is used to generate an authentication token.

If present, the value of applicationServerKey MUST include a point on the P-256 elliptic curve [[!FIPS-186-3]], encoded in the uncompressed form described in [[!X9.62]] Annex A (that is, 65 octets, starting with an 0x04 octet). The applicationServerKey MUST be a different value to the one used for message encryption [[WEBPUSH-ENCRYPTION]].

PushSubscription interface

A PushSubscription object represents a push subscription.

readonly attribute USVString endpoint
[SameObject] readonly attribute PushSubscriptionOptions options
ArrayBuffer? getKey (PushEncryptionKeyName name)
Promise<boolean> unsubscribe ()
serializer

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

The getKey method retrieves keying material that can be used for encrypting and authenticating messages. When getKey is invoked the following process is followed:

  1. Find the internal slot corresponding to the key named by the name argument.
  2. If a slot was not found, return null.
  3. Initialize a variable key with a newly instantiated ArrayBuffer instance.
  4. If the internal slot contains an asymmetric key pair, set the contents of key to the serialized value of the public key from the key pair. This uses the serialization format described in the specification that defines the name. For example, [[!WEBPUSH-ENCRYPTION]] specifies that the p256dh public key is encoded using the uncompressed format defined in [[X9.62]] Annex A (that is, a 65 octet sequence that starts with a 0x04 octet).
  5. Otherwise, if the internal slot contains a symmetric key, set the contents of key to a copy of the value from the internal slot. For example, the auth parameter contains an octet sequence used by the user agent to authenticate messages sent by an application server.
  6. Return key.

Keys named p256dh and auth MUST be supported.

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.

The serializer for a PushSubscription invokes the following steps:

  1. Let map be an empty map.
  2. Add an entry to map whose key name is endpoint and whose value is the result of converting the endpoint attribute of the PushSubscription to a serialized value. The user agent MUST use a serialization method that does not contain input-dependent branchs (that is, one that is constant time). Note that a URL - as ASCII text - will not ordinarily require special treatment.
  3. Let keys be an empty map.
  4. For each identifier i corresponding to keys in internal slots on the PushSubscription, ordered by the name of the key:
    1. If the internal slot corresponds to an asymmetric key pair, let b be the encoded value of the public key corresponding to the key name i, using the encoding defined for the key name (see getKey).
    2. Otherwise, let b be the value as returned by getKey.
    3. Let s be the URL-safe base64 encoding without padding [[!RFC4648]] of b as a USVString. The user agent MUST use a serialization method that does not branch based on the value of b.
    4. Add an entry to keys whose key name is the name of i and whose value is s.
  5. Add an entry to map whose key name is keys and whose value is keys.
  6. Return map.

Note that the options to a PushSubscription are not serialized.

PushEncryptionKeyName enumeration

Encryption keys used for push message encryption are provided to a webapp through the getKey method or the serializer of PushSubscription. Each key is named using a value from the PushEncryptionKeyName enumeration.

p256dh
auth

The p256dh value is used to retrieve the P-256 ECDH Diffie-Hellman public key described in [[!WEBPUSH-ENCRYPTION]].

The auth value is used to retrieve the authentication secret described in [[!WEBPUSH-ENCRYPTION]].

PushMessageData interface

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

PushMessageData objects have an associated bytes (a byte sequence) set on creation, which is null if there was no data in the push message.

The arrayBuffer() method, when invoked, MUST return an ArrayBuffer whose contents are bytes. Exceptions thrown during the creation of the ArrayBuffer object are re-thrown.

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.

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

  1. Let bytes be an empty byte sequence.
  2. Switch on object's type:
    BufferSource
    Set bytes to a copy of object's contents.
    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 from the push service, the user agent MUST run the following steps:

  1. Let registration be the service worker registration corresponding to the push message.
  2. If registration is not found, abort these steps.
  3. Let subscription be the active push subscription for registration.
  4. Initialize pushdata to a value of null.
  5. If the push message contains a payload, perform the following steps:
    1. Decrypt the push message using the private key from the key pair associated with subscription and the process described in [[!WEBPUSH-ENCRYPTION]]. This produces the plain text of the message.
    2. If the push message could not be decrypted for any reason, discard the message and terminate this process. A push event MUST NOT be fired for a push message that was not successfully decrypted using the key pair associated with the push subscription.
    3. Let pushdata be the decrypted plain text of the push message.
  6. Invoke the Handle Functional Event algorithm with a service worker registration of registration and callbackSteps set to the following steps:
    1. Set global to the global object that was provided as an argument.
    2. Create a trusted event, e, that uses the PushEvent interface, with the event type push, which does not bubble, is not cancelable, and has no default action.
    3. If the push message contains valid data - that is, if the message can be successfully decoded and decrypted - set the data attribute of e to a new PushMessageData instance with bytes set to the binary push message data.
    4. Dispatch e to global.
    5. Run the following steps in parallel:
      1. Wait for all of the promises in the extend lifetime promises of e to resolve.
      2. If any promise rejects, abort these steps.
      3. Acknowledge the receipt of the push message according to [[!WEBPUSH-PROTOCOL]].

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 are extended to include the following steps:

  1. If eventInitDict's data member is not present, set the data attribute of the event to null and terminate these steps.
  2. Set b to the result of extracting a byte sequence from the "data" member of eventInitDict.
  3. Set the data attribute of the event to a new PushMessageData instance with bytes set to b.

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 Service Worker SHOULD attempt to resubscribe while handling this event, in order to continue receiving push messages.

When new push subscription information becomes available, the user agent MUST run the following steps:

  1. Let registration be the service worker registration corresponding to the push message.
  2. If registration is not found, abort these steps.
  3. Invoke the Handle Functional Event algorithm with a service worker registration of registration and callbackSteps set to the following steps:
    1. Set global to the global object that was provided as an argument.
    2. Create a trusted event, e, that uses the ExtendableEvent interface, with the event type pushsubscriptionchange, which does not bubble, is not cancelable, and has no default action.
    3. Dispatch e to global.
    4. If the previous push subscription is still active, perform the following steps in parallel:
      1. Set oldSubscription to the previous push subscription.
      2. Wait for all of the promises in the extend lifetime promises of e to either resolve or reject.
      3. Unsubscribe oldSubscription.

This algorithm ensures that the Service Worker is able to react to any non-destructive change in a push subscription, such as an automatic refresh, without causing any active push subscription to be terminated prematurely. A Service Worker can request a new push subscription during this process and ensure that no push messages are lost.

Enumerations

granted
denied
prompt
Enumeration Description
granted The webapp has permission to use the Push API.
denied The webapp has been denied permission to use the Push API.
prompt The webapp needs to ask for permission in order to use the Push 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.