This document specifies an API that allows web applications to request a wake lock. A wake lock prevents some aspect of the device from entering a power-saving state (e.g., preventing the system from turning off the screen).

Implementors need to be aware that this specification is extremely unstable. Implementors who are not taking part in the discussions will find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the repository on GitHub and take part in the discussions.

Introduction

Modern OSs achieve longer battery life by implementing aggressive power management, meaning that shortly after the lack of user activity, a host device may lower the screen brightness, turn the screen off and even let the CPU go into a deep power state, allowing to sip as little power as possible.

Though this is great for prolonged battery life, it can sometime hinder good, valid use-cases such as:

More use-cases can be found in Use Cases and Requirements.

A wake lock will generally prevent something from happening, but UAs (and the underlying OS) may time limit a wake lock given the battery status (wall power connected, discharging, low battery level), or even disallow wake locks in the case a power saving mode is activated.

Any active wake lock MUST also prevent the page from entering UA induced CPU suspension as defined by [[PAGE-LIFECYCLE]].

This specification defines the following wake lock types:

  1. A screen wake lock prevents the screen from turning off. Only visible documents can acquire the wake lock.
  2. A system wake lock prevents the CPU from entering a deep power state. This may also prevent communication chips such as cellular or Wi-Fi from sleeping.
Though a system wake lock will usually keep the network connection alive, it is most likely not required for such. Audio streaming on devices usually does the same and if you need it for long running upload and download tasks, such as for a podcast, other more appropriate features exist, like [[BACKGROUND-FETCH]].
One type of wake lock can imply the effects of another: for example, screen wake lock logically implies that the program which displays information on the screen continues running, as if the system wake lock were also applied. But to avoid dependence on such implementation details which may not always be true, this specification treats all types of wake locks as independent.

A user agent can deny a wake lock of a particular wake lock type for a particular {{Document}} by any implementation-specific reason, for example, a user or platform setting or preference.

Policy control

The wake lock feature is a policy-controlled feature with feature name `"wake-lock"` and default allowlist `["self"]`.

The default allowlist of `["self"]` allows wake lock usage in same-origin nested frames but prevents third-party content from using wake locks.

Third-party usage can be selectively enabled by adding `allow="wake-lock"` attribute to the frame container element:

          <iframe src="https://third-party.com" allow="wake-lock"/></iframe>
        

Alternatively, the wake lock feature can be disabled completely by specifying the feature policy in a HTTP response header:

          Feature-Policy: {"wake-lock": []}
        

See [[[FEATURE-POLICY]]] for more details.

Permissions and user prompts

The [[PERMISSIONS]] API provides a uniform way for websites to request permissions from users and query which permissions they have.

It is recommended that a UA shows some form of unobtrusive notification that informs the user when a wake lock is active, as well as provides the user with the means to block the ongoing operation, or simply dismiss the notification.

The `"wake-lock"` powerful feature is defined as follows:

The permission descriptor type is represented by the WakeLockPermissionDescriptor dictionary, which augments the {{PermissionDescriptor}} with a type member, allowing for more fine-grained permissions.

        dictionary WakeLockPermissionDescriptor : PermissionDescriptor {
          WakeLockType type;
        };
      

The {{PermissionDescriptor.name}} is `"wake-lock"`.

Within this section, |descriptor| is an instance of the permission descriptor type of the `"wake-lock"` powerful feature.

To block a permission, run these steps:

  1. Let |descriptor| be the permission descriptor type instance to be blocked.
  2. Set |descriptor|'s permission state to {{"denied"}}.
  3. Let |record| be the platform wake lock's state record associated with |descriptor|'s type member.
  4. [=list/For each=] |lock| in |record|.[[\InstanceList]]:
    1. Run release a wake lock on |lock|.

To obtain permission for wake lock type |type|, run these steps in parallel. This async algorithm returns either {{"granted"}} or {{"denied"}}.

  1. Let |permissionDesc:PermissionDescriptor| be a newly created {{PermissionDescriptor}}.
  2. Set |permissionDesc|'s name to "`wake-lock`".
  3. Set |permissionDesc|'s type to |type|.
  4. Let |resultPromise| be the result of running query a permission with |permissionDesc|.
  5. Await |resultPromise| to settle.
  6. If |resultPromise| rejects, return {{"denied"}}.
  7. Otherwise, let |status:PermissionStatus| be the result of |resultPromise|.
  8. Let |state| be the value of |status|.state.
  9. If |state| is {{"prompt"}}, run the following steps:
    1. If these obtain permission steps were not triggered by user activation, return {{"denied"}}.
    2. Return the result of requesting permission to use with |permissionDesc|.
  10. Otherwise, return |state|.
In the case the steps are run from a dedicated worker, then the current global object is a {{DedicatedWorkerGlobalScope}}, which means that the obtain permission steps can never be triggered by user activation, meaning that in order to use wake locks from a dedicated worker, prior permission needs to granted from the browsing context who created it, e.g. the browsing context that is exists in the {{DedicatedWorkerGlobalScope}}'s owner set.

The WakeLockType enum

For the purpose of wake lock type description, this specification defines the following enumeration:

        enum WakeLockType { "screen", "system" };
      
screen
Screen wake lock type.
system
System wake lock type.

Concepts and state record

The term platform wake lock refers to platform interfaces with which the user agent interacts to query state and acquire and release a wake lock.

A platform wake lock can be defined by the underlying platform (e.g. in a native wake lock framework) or by the user agent, if it has direct hardware control.

Each platform wake lock (one per wake lock type) has an associated state record with the following internal slots:

Internal slot Initial value Description (non-normative)
[[\InstanceList]] The empty set. A set of {{WakeLock}} instances.
[[\RequestCounter]] 0. The value indicates the amount of current requests for the wake lock type. A number greater than zero indicates an outstanding wake lock request

The WakeLock interface

The {{WakeLock}} interface allows the page to request wake locks of a particular type, to determine the current wake lock state and to receive notifications when the wake lock state is changed.

        [Constructor(WakeLockType type), SecureContext, Exposed=(DedicatedWorker, Window)]
        interface WakeLock : EventTarget {
          [Exposed=Window] static Promise<PermissionState> requestPermission(WakeLockType type);
          readonly attribute WakeLockType type;
          readonly attribute boolean active;
          attribute EventHandler onactivechange;
          Promise<void> request();
          void abort();
          static sequence<WakeLock> query(optional WakeLockQueryFilter filter);
        };
      

Internal slots

Internal slot Description (non-normative)
[[\requestPromise]] The pending promise created during request().

Constructor

To create and initialize a {{WakeLock}} object of type |type|, the following steps MUST be performed:

  1. Let |document| be the responsible document of the current settings object.
  2. If the current global object is the {{DedicatedWorkerGlobalScope}} object and its owner set is empty, throw a "{{NotAllowedError}}" {{DOMException}}.
  3. If the current global object is the {{Window}} object and the |document|'s [=Document/browsing context=] is `null`, throw a "{{NotAllowedError}}" {{DOMException}}.
  4. If |document| is not allowed to use the policy-controlled feature named "`wake-lock`", throw a "{{NotAllowedError}}" {{DOMException}}.
  5. If the user agent denies the wake lock of this |type| for |document|, throw a "{{NotAllowedError}}" {{DOMException}}.
  6. Let |lock| be a new {{WakeLock}} object.
  7. Set |lock|'s type to |type|.
  8. Let |record| be the platform wake lock's state record associated with |type|.
  9. Add |lock| to |record|.[[\InstanceList]].
  10. If the wake lock of type |type| is currently acquired, set |lock|'s active to `true`, otherwise to `false`.
  11. Return |lock|.

requestPermission() static method

The requestPermission() method, when invoked, MUST run the following steps. This algorithm resolves with either {{"granted"}} or {{"denied"}}.

  1. Let |promise:Promise| be a new promise.
  2. Let |type| be the first argument.
  3. Return |promise| and run the following steps in parallel:
    1. Let |state| be the result of running and waiting for the obtain permission steps with |type|.
    2. Resolve |promise| with |state|.

type attribute

When getting, the type attribute returns this {{WakeLock}}'s wake lock type.

active attribute

The {{active}} attribute represents whether a wake lock is currently acquired by the {{WakeLock}} instance.

onactivechange attribute

A {{WakeLock}}'s onactivechange attribute is an {{EventHandler}} with the corresponding event handler event type of `activechange`. Fired when current wake lock status indicated by the active attribute changes.

request() method

To abort the request steps for a running instance of request(), run these additional steps:

  1. Set |lock|.[[\requestPromise]] to `undefined`.
  2. Abort the associated request() algorithm.

The request() method, when invoked, MUST run the following steps:

  1. Let |lock| be the context object.
  2. Let |record| be the platform wake lock's state record associated with |lock|'s |type|.
  3. If the promise |lock|.[[\requestPromise]] is not `undefined`, return it.
  4. Let |promise:Promise| be a new promise.
  5. Set |lock|.[[\requestPromise]] to promise.
  6. Return |promise| and run the following steps in parallel:
    1. Let |state| be the result of running and waiting for the obtain permission steps with |type|.
    2. If |state| is {{"denied"}}, then reject |promise| with a "{{NotAllowedError}}" {{DOMException}}, and run abort the request steps.
    3. If the current global object is not a {{DedicatedWorkerGlobalScope}} object, run the following steps:
      1. Let |document| be the responsible document of the current settings object.
      2. If |document| is not fully active, reject |promise| with a "{{NotAllowedError}}" {{DOMException}}, and run abort the request steps.
      3. If |lock|'s |type| is {{ WakeLockType["screen"] }} and the {{Document} of the top-level browsing context is hidden, reject |promise| with a "{{NotAllowedError}}" {{DOMException}}, and run abort the request steps.
    4. Increase |record|.[[\RequestCounter]] by one.
    5. If |record|.[[\RequestCounter]] is 1, run the following steps:
      1. Let |success| be the the result of running and waiting for acquire a wake lock on |lock|.
      2. If |success| is `false` then reject |promise| with a "{{NotAllowedError}}" {{DOMException}}, and run abort the request steps.
    6. Resolve |promise| with `void`.
The additional visibility requirement for screen wake lock is to prevent keeping the screen on when the page is not visible, such as when the browser is minimized. As this condition is transient and not under control of the web page, the specification chooses to automatically acquire and release the lock when visibility changes rather than having the page to deal with it, e.g by re-requesting the lock each time the page becomes visible again.

abort() method

The abort() method, when invoked, MUST run the following steps:

  1. Let |lock| be the context object.
  2. Let |record| be the platform wake lock's state record associated with |lock|'s |type|.
  3. Decrease |record|.[[\RequestCounter]] by one.
  4. If |record|.[[\RequestCounter]] is 0, then run the following steps in parallel:
    1. Run release a wake lock on |lock|.

The WakeLockQueryFilter dictionary

          dictionary WakeLockQueryFilter {
            WakeLockType? type;
            boolean? active;
          };
        

The type member and active member allows filtering by wake lock type and activity (whether the wake lock is currently acquired by the user agent.).

query() static method

The query() method, when invoked, MUST run the following steps.

  1. Let |filter| be the first argument.
  2. Let |records| be the empty list.
  3. Let |type| be the |filter| dictionary member of the same name.
  4. Let |active| be the |filter| dictionary member of the same name.
  5. If |type| is present, add the platform wake lock's state record associated with wake lock type |type| to |records|.
  6. Otherwise, add all state records to |records|.
  7. Let |locks| be the empty set.
  8. [=list/For each=] |record| in |records|:
    1. [=list/For each=] |lock| in |record|.[[\InstanceList]]:
      1. If |active| is present, add |lock| to |locks| if |active| is equal to |lock|'s active attribute value.
      2. Otherwise, add |lock| to |locks|
  9. Return |locks|.

Managing Wake Locks

This section applies to each wake lock type equally and independently, unless a particular wake lock type is explicitly mentioned.

The user agent acquires the wake lock by requesting the underlying operating system to apply the lock. The lock is considered acquired only when the request to the operating system succeeds.

Conversely, the user agent releases the wake lock by requesting the underlying operating system to no longer apply the wake lock. The lock is considered released only when the request to the operating system succeeds.

The wake lock is applicable if the state of the operating system permits application of the lock (e.g. there is sufficient battery charge).

The screen wake lock MUST NOT be applicable after the screen is manually switched off by the user until it is switched on again. Manually switching off the screen MUST NOT affect the applicability of the system wake lock.

Whether the wake lock is applicable is a transient condition, e.g. when the battery charge is low but then the battery is recharged. So like the visibility requirement, this is part of automatic wake lock management and not part of the decision process whether to allow or deny the wake lock.

Auto-releasing wake locks

A user agent may release a wake lock at any time it:

Handling document loss of full activity

When the user agent determines that a responsible document of the current settings object is no longer fully active, it must run these steps:

  1. Let |record| be the platform wake lock's state record associated with wake lock type {{"screen"}} and {{"system"}}.
  2. [=list/For each=] |lock| in |record|.[[\InstanceList]]:
    1. Run release a wake lock on |lock|.
Only documents presented to the user, thus with an associated [=Document/browsing context=] can be active documents, so the above steps are only relevant for these.

Handling document loss of visibility

When the user agent determines that the visibility state of the {{Document}} of the top-level browsing context changes, it must run these steps:

  1. Let |document| be the {{Document}} of the top-level browsing context.
  2. If |document|'s visibility state is `"visible"`, abort these steps.
  3. Let |screenRecord| be the platform wake lock's state record associated with wake lock type {{ WakeLockType["screen"] }}.
  4. [=list/For each=] |lock| in |screenRecord|.[[\InstanceList]]:
    1. Run release a wake lock on |lock|.
As some locks like {{ WakeLockType["system"] }} are allowed to run while the {{Document}} of the top-level browsing context is not visible, it is encouraged that user agents show some UI indicating this.
The visibility state is only exposed on the {{Window}} object, thus the above steps are not relevant to wake locks running as part of a dedicated worker.

Acquire wake lock algorithm

To acquire a wake lock for a given {{WakeLock}} object |lock|, run these steps in parallel:
  1. Let |type| be |lock|'s type.
  2. If the wake lock for type |type| is not applicable, return `false`.
  3. Ask the underlying operation system to acquire the wake lock of type |type| and let |success| be `true` if the operation succeeded, or else `false`.
  4. If |success| is different from |lock|'s active, set |lock|'s active to |success| and fire an event named `"activechange"` at |lock|.
  5. Return |success|.

Release wake lock algorithm

To release a wake lock for a given {{WakeLock}} object |lock|, run these steps in parallel:

  1. Let |type| be |lock|'s type.
  2. If the promise |lock|.[[\requestPromise]] not `undefined` and is pending, reject it with an "{{AbortError}}" {{DOMException}} and abort the request steps for the associated running request() algorithm.
  3. Ask the underlying operation system to release the wake lock of type |type| and let |success| be `true` if the operation succeeded, or else `false`.
  4. If |success| is different from |lock|'s active, set |lock|'s active to the negated |success| and fire an event named `"activechange"` at |lock|.
  5. If |lock|'s type is `"screen"` run the following:
    1. The user agent MUST reset the platform-specific inactivity timer after which the screen is actually turned off.
  6. Return |success|.
Resetting the inactivity timer prevents the screen from going blank immediately after the wake lock is released.

Security and privacy considerations

Application of a wake lock causes various device components such as display or CPU to operate at higher power levels than they otherwise would. This can lead to undesirable and potentially dangerous effects such as excessive heating and faster than normal battery charge depletion. The latter is particularly relevant to mobile devices which may not have a stationary power source readily available. Complete battery depletion at an unexpected time can lead to inability of the user to make or receive calls and use network services, including the emergency call service. Implementations should consider preventing wake lock application if they determine that the remaining battery capacity is low.

The ability to observe the global state of a wake lock can create a communication channel between two otherwise isolated {{Document}} objects. One document can request wake lock which changes the global wake lock state, and another document can observe this change by subscribing to events in {{WakeLock}}.

When the user agent does not acquire wake lock even though a browsing context has requested it, this can be observed by the browsing context and can possibly disclose sensitive information about the state of the device such as that battery level is low.

Examples

        async function tryKeepScreenAlive(minutes) {
          const lock = new WakeLock("screen");
          lock.request();

          setTimeout(() => lock.abort(), minutes * 60 * 1000);
        }

        tryKeepScreenAlive(10);
      

This example allows the user to request a screen wake lock by clicking on a checkbox, but updates the checkbox checked state in case the wake lock state changes:

        const checkbox = document.createElement("input");
        checkbox.setAttribute("type", "checkbox");
        document.body.appendChild(checkbox);

        const lock = new WakeLock("screen");

        lock.onactivechange = () => checkbox.checked = lock.active;

        try {
          checkbox.disabled = true;
          if (checkbox.checked) {
            await lock.request();
          } else {
            lock.abort();
          }
        } catch {
          // On failure, reset the checkbox to reflect the
          // current state. `onactivechanged` will not have fired.
          checkbox.checked = lock.active;
        } finally {
          checkbox.disabled = false;
        }
      

In this example, two screen wake lock requests are created and released independently:

        const lock1 = new WakeLock("screen");
        const lock2 = new WakeLock("screen");

        lock1.request();

        // ...somewhere else

        lock2.request();

        // ...somewhere else

        lock2.abort();
        lock1.abort();
      

Dependencies

Document's hidden attribute, and visibility state are defined in [[PAGE-VISIBILITY]].

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

Acknowledgments

We would like to offer our sincere thanks to Mounir Lamouri, Sergey Konstantinov, Matvey Larionov, Dominique Hazael-Massieux, Domenic Denicola, Thomas Steiner for their contributions to this work.