This specification defines a “Push API” that provides webapps with scripted access to server-sent messages, for simplicity referred to here as push messages, as delivered by push services. Push services are a way for webapp servers to send messages to webapps, whether or not the webapp is active in a browser window.

Push messages may be delivered via various methods, either via standardized protocols (e.g. Server-Sent Events [[SSE]], the GSM Short Message Service [[GSM-SMS]], SIP MESSAGE [[RFC3428]], or OMA Push [[OMA-PUSH]]), or via browser-specific methods. The specific method to be used by a webapp is either selected by the user through a push service extension, or by the browser. The Push API is defined to promote compatibility with any delivery method.

Introduction

As defined here, push services support delivery of webapp 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]], as this specification uses that specification and terminology.

Terminology

The Function interface represents a function in the scripting language being used as defined in [[!HTML5]].

The concepts queue a task and fires a simple event are defined in [[!HTML5]].

The terms event handlers and event handler event types are defined in [[!HTML5]].

The Promise interface, the concepts of a resolver, a resolver's fulfill algorithm and a resolver's reject algorithm are defined in [[!DOM4]].

The term push service extension refers to a browser extension enabling push service configuration for the user, and thereby enabling Push API binding to event delivery via the service.

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 webapp server refers to server-side components of a webapp.

The term push message refers to an indication to a webapp that there is new information for it from the webapp server, all or part of which MAY be contained in the push message itself.

The term push registration refers to each logical channel aimed at delivering push messages from an webapp server to a webapp, which is created by a distinct registration of such webapp via this Push API.

The term push service refers to an overall end-to-end system that allows webapp servers to send push messages to a webapp.

The term push server refers to the push service access point via which webapp-servers can initiate push message delivery. Push servers typically expose APIs specific to the push service, e.g. for push message delivery initiation.

The term Shared Worker is used as defined in [[workers]].

The term Service Worker is used as defined in [[!SERVICEWORKERS]].

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 register() method, unless a prearranged trust relationship applies.

User agents may support prearranged trust relationships that do not require such per-request user interfaces.

Permissions that are preserved beyond the current browsing session must be revocable.

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 webapp servers to inform webapps that new data is available at the webapp server, or pass the new data directly to the webapp in the push message.

As push services and the over-the-air/wire protocols they use may have varying message delivery or sequencing reliability, push messages delivered via the push API include a version value that can help webapps recognize new data, or detect when a resynchronization with the webapp server or re-registration with the push service is needed.

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:


 // http://example.com/serviceworker.js
 
 this.oninstall = function(e) {
  // Note that push messages won't be delivered to this service worker (SW)
  // until the install and activate steps are completed. This
  // may mean waiting until caches are populated, etc.
  e.waitUntil(...);
 };
 
 this.onactivate = function(e) { ... }

 // Note that we no longer need navigator.hasPendingMessages() because the UA
 // can queue push messages for the SW and deliver them as events whenever it
 // deems necessary.
 this.onpush = function(e) {
  // Log the pushRegistrationId
  console.log(e.message.pushRegistrationId);
  // Log the version
  console.log(e.message.version);
  // Log the deserialized JSON data object
  console.log(e.message.data);
  // ...
  // From here the SW can write the data to IDB, send it to any open windows,
  // etc.
 }
 
 // http://example.com/webapp.js
 
 var logError = console.error.bind(console);
 
 function toQueryString(obj) {
  var encode = encodeURIComponent;
  for (var x in obj) {
   components.push(encode(x) + "=" + encode(obj[x]));
  }
  return "?" + components.join("&");
 }

 function registerWithAppServer(registration) {
  // We've been handed the info that the app server may need
  // to complete preparation for activating the push service
  // including the pushEndpoint and pushRegistrationId
  asyncXHR(
   "http://example.com/push/activate" + toQueryString(registration);
  );
 }
 
 // This is an ugly detail of the current SW design. See:
 //   https://github.com/slightlyoff/ServiceWorker/issues/174
 function swReady() {
  var sw = navigator.serviceWorker;
  return new Promise(function(resolve, reject) {
   if (!sw.active) {
    // Note that the promise returned from register() resolves as soon
    // as the script for the SW is downloaded and evaluates without issue.
    // At this point it is NOT considered installed and will not receive
    // push events. We will, however, allow the registration for pushes
    // to proceed at this point. Push registrations that succeed and generate
    // messages will see those messages queued until the SW is installed
    // and activated, perhaps at some time in the near future (e.g., once
    // resources for the application itself are downloaded).
    sw.register("/service_worker.js", { scope: "*" }).then(resolve, reject);
   } else {
     sw.ready().then(resolve, reject);
   }
  });
 }

 // Only try to register for a push channel when we have valid SW
 swReady().then(function(sw) {
  var gcmSenderId = "......";
  var apnSenderId = "......";
  var regId = "......";
  var push = navigator.push;

	// The push object is an async map that can be used to enumerate and
  // test for active channels.
  push.has(regId).catch(function() {
	 // this will be executed if the regId is not found 
   // register() is async and can prompt the user. On success, the
   // expected regId value should be added to the map.
   push.register({
    // the "sender" field is push-server-specific and is optional.
    // Some servers (e.g., GCM) will require that this field be
    // populated with a pre-arranged ID for the app. The system
    // selects between the supplied keys to decide which one to
    // offer the "local" push server for this registration.
    sender: {
     apn: apnSenderId,
     gcm: gcmSenderId,
     // ...
    }
   }).then(registerWithAppServer, logError);
  });
 });

 
/* Hypothetical end-to-end flow of a push service lifecycle
   +--------+               +--------+             +--------+           +--------+
   | webapp |               |  user  |             |  push  |           |  app   |
   |  +SW   |               | agent  |             | server |           | server |
   +--------+               +--------+             +--------+           +--------+
       |                        |                      |                     |
       |                        |                      |         Developer registers with push
       |                        |                      |         service(s) and receives data 
       |                        |                      |          needed for app registration
       |                        |                      |              with push service
  User invokes app,             |                      |                     |
  which is configured           |                      |                     |
  with push service             |                      |                     |
  registration options          |                      |                     |
       |<---- app setup with push service registration options if needed --->|
       |                        |                      |                     |
       |--register w/options--->|                      |                     |
       |                  (user accepts)               |                     |
       |                        |                      |                     |
       |                        |<-setup push service->|                     |
       |                        |                      |                     |
       |<--- call promise ------|                      |                     |
       | fullfilled function w/ |                      |                     |
       | registration attributes|                      |                     |
       |                        |                      |                     |
       |<----deliver registration attributes to app server for later use---->|
       |                        |                      |                     |
       |                        |                      |         Server associates registration
       |                        |                      |           attributes with webapp
       |                        |                      |                     |
       |                        |                      |              (sometime later)
       |                        |                      |         Server has data to push, 
       |                        |                      |        invokes push server API as
       |                        |                      |        per registration attributes
       |                        |                      |                     |
       |                        |                      |<--push message-|
       |                        |                      |   per service API   |
       |                        |                      |                     |
       |                        |             (match to user agent)          |
       |                        |                      |                     |
       |                        |<--push message--|                     |
       |                        | per service protocol |                     |
       |                        |                      |                     |
       |                (match to webapp)              |                     |
       |                        |                      |                     |
       |<-----push message------|                      |                     |
       |                        |                      |                     |
*/
   

Push Server Discovery and API Use

This specification does not define either specific normative methods via which webapps can determine the applicable push system, or initiate push requests through that system via a push server API. While these limitations add complexity for webapp developers, they reflect the current reality of a diversity of push systems, for which convergence at least in push server APIs, is not expected to be a short-term possibility. While a converged push server 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 systems 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 systems as needed.

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

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

The Push API does not provide any pushRegistration attributes that normatively identify the particular push system that applies to the registration. Webapps that are designed to work with a single push system are assumed to know inherently how to use the push server API of that system. 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 system, 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 server API, webapp servers that are designed to work with multiple push systems may need to determine the applicable system, e.g. using methods such as:

If the applicable push system cannot be determined prior to creation of a push registration, webapps may need to provide any predetermined system-specific data necessary in the registration process, through the registerOptions. When working with multiple push systems, the webapp may need to concatenate all necessary data of the set of systems in the registerOptions. It is assumed that the user agent will be able to recognize the applicable options from the registerOptions parameter, and apply them as necessary in selecting from supported systems or registering with a single supported system.

Navigator Interface

readonly attribute PushManager push
The object that exposes the push service management interface.

TAG issue: navigator.push as an object of PushManager type seems misleading per se and is inconsistent with Array.prototype.push method. Suggestion: navigator.pushRegistrationManager.

PushManager Interface

TAG issue: PushManager is limited to dealing with registrations. Suggestion: PushRegistrationManager.

TAG issue: PushManager.registrations method seems inconsistent. Suggestion: PushManager.getRegistrations.

TAG issue: PushManager.register provides two heterogeneous functions: asking use permission, registering push notifications. This mixing leads to odd user agent behavior, i.e. push service failure forces webapp to ask permission again. Suggestion: split the functionality and provide separate methods to ask user permission (check if permission has already being granted) and to register push notifications. Provide different sets of errors for those purposes.

The PushManager interface defines the operations that enable webapps to establish access to push services.

Promise register (optional Object registerOptions)
This method allows a webapp to create a new push registration to receive push messages. It returns a Promise that will allow the caller to be notified about the result of the operation.
optional Object registerOptions
An object that provides push server-specific registration parameters that the webapp needs to establish the push service with the push server. The registerOptions can be shared by multiple webapps or unique to a specific webapp.
Promise unregister ()
This method allows a webapp to unregister a specific push registration. It returns a Promise that will allow the caller to be notified about the result of the operation.
DOMString pushRegistrationId
Identifies the push registration that the webapp requests to unregister
Promise registrations ()
This method allows a webapp to retrieve the list of its active push registrations. It returns a Promise that will allow the caller to be notified about the result of the operation.

Steps

TAG issue: AbortError is raised when user doesn't grant permissions, not when registration is aborted. Suggestion: PermissionDeniedError.

The register method when invoked MUST run the following steps:

  1. Let promise be a new Promise object and resolver its associated resolver.
  2. Return promise and continue the following steps asynchronously.
  3. Ask the user whether it allows the requesting webapp to activate the reception of push messages, unless a prearranged trust relationship applies or the user has already granted permission explicitly to this webapp.
  4. If not granted, run the following sub-steps and terminate these steps:
    1. Let error be a new DOMError object whose name is "AbortError".
    2. Invoke resolver's reject algorithm with error as the value argument.
  5. Make a request to the system to create a new push registration for the requesting webapp.
  6. If there is an error invoke resolver's reject algorithm with no arguments and terminate these steps.
  7. When the request has been completed run the following sub-steps:
    1. Let pushRegistration be a new pushRegistration object providing the details of the push registration.
    2. Invoke resolver's fulfill algorithm with pushRegistration as the value argument.

The unregister method when invoked MUST run the following steps:

  1. Let promise be a new Promise object and resolver its associated resolver.
  2. Return promise and continue the following steps asynchronously.
  3. Check that the pushRegistrationId attribute relates to an active push registration of the requesting webapp.
  4. If the previous step was not successful, run the following sub-steps and terminate these steps:
    1. Let error be a new DOMError object whose name is " NoModificationAllowedError".
    2. Invoke resolver's reject algorithm algorithm with error as the value argument.
  5. Make a request to the system to deactivate the push registration identified by the pushRegistrationId attribute.
  6. If there is an error invoke resolver's reject algorithm with no arguments and terminate these steps.
  7. When the request has been completed invoke resolver's fulfill algorithm with a DOMString set to the value of the pushRegistrationId attribute as the value argument.

The registrations method when invoked MUST run the following steps:

  1. Let promise be a new Promise object and resolver its associated resolver.
  2. Return promise and continue the following steps asynchronously.
  3. Retrieve the list of push registration associated to the requesting webapp
  4. If there is an error invoke resolver's reject algorithm algorithm with no arguments and terminate these steps.
  5. When the request has been completed run the following sub-steps:
    1. Let pushRegistrations be a new array containing a pushRegistration object per active push registration associated to the requesting webapp. A length of zero for pushRegistrations indicates that there are no registrations.
    2. Invoke resolver's fulfill algorithm algorithm with pushRegistrations as the value argument.

Push Registration Persistence

To facilitate persistence of push registrations when a webapp is closed, it can use a Service Worker to register for and receive push events. In that case, even if the webapp parent window is closed, the pushRegistration object will still enable delivery of push messages, through the Service Worker. The push messages, can then be processed by the Service Worker, e.g. including one or more of the following actions:

If a webapp creates a push registration without using a Service Worker, the pushRegistration object will persist only as long as the webapp window is open.

Push Registration Uniqueness

Each push registration is unique, i.e. a single instance specific to each webapp and call to the register interface. Multiple instances of the same webapp can only share a push registration if it has been created by a shared worker.

Webapps that create multiple push registrations are responsible for mapping the individual registrations to specific app functions as necessary. For example, the webapp or webapp server can associate a specific pushRegistration to a particular function of the app through JavaScript.

PushRegistration Interface

The PushRegistration interface contains information about a specific channel used by a webapp to receive push messages.

readonly attribute DOMString pushEndpoint
It MUST return the absolute URL exposed by the push server where the webapp server can send push messages to this webapp
readonly attribute DOMString pushRegistrationId
It MUST return a univocal identifier of this push registration in the push server. It is used by the application server to indicate the target of the push messages that it submits to the push server.

PushMessage Interface

The PushMessage interface represents a received push message.

readonly attribute DOMString pushRegistrationId
MUST return the identifier of the push registration to which this event is related.
readonly attribute unsigned long long? version
MUST return an identifier of the latest version of the content available through this push registration. If it is different from the last version the webapp is aware of it signals that it has new content to be retrieved from the webapp server. The version is an integer value that is incremented when new content is available through a push registration. So higher values of version indicate newer content. Note that the push server may just notify of the latest version if multiple message requests have been recieved from the webapp server before the push server is ready to send a message. Thus a message for each version may not be received by the user agent and in turn by the webapp. This attribute MUST return null when the push server has lost track of the state, in order to indicate the webapp that it should ask the webapp server and restore local state.
readonly attribute Object data
MUST return the deserialized JSON data object, if any, received by the user agent in the push message.

PushRegisterMessage Interface

TAG issue: PushRegisterMessage name is confusing as it really occurs when push service failed, not when new registration granted. Suggestion: PushServiceFailure.

The PushRegisterMessage interface represents an event related to a push registration that is no longer valid and thus needs to be created again by the webapp by means of a new invocation of the register method.

readonly attribute DOMString pushRegistrationId
MUST return the identifier of the push registration to which this event is related.

Push Events

A webapp that wants to be able to make use of the capabilities provided by this API needs to be registered to receive the following events:

name type description
push PushMessage Incoming push message
push-register PushRegisterMessage Request to register a specific push registration

TAG issue: How to invoke a webapp that is using History API to manipulate page URLs?

Upon receiving a push message from the push server the User agent MUST run the following steps:

Upon any event that makes a push registration no longer valid, e.g. push server database failure, the User agent MUST run the following steps:

If a push message or an indication about a push registration being no longer valid is received and the webapp is not active in a browser window, the User agent must invoke the webapp if possible, and deliver the push message to it. Examples of cases in which webapps should be invokable include:

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.