Screen Wake Lock API: Keeping the Display Active on Purpose
AI generated
JS
() =>
JavaScript · Browser APIs · UX
Screen Wake Lock API
Keep the display active exactly when it matters

Some web applications need a screen that stays on: a cooking recipe you do not want to tap while stirring, a video call without camera movement, or a progress bar that runs for minutes. The Screen Wake Lock API solves exactly this problem without tricks like invisible videos or dummy timers.

15 min read WakeLockSentinel navigator.wakeLock Progressive Enhancement

1. Why screens fall asleep in the first place

Operating systems dim and lock screens after a period of inactivity to save battery. That behavior is correct in almost every situation, but it becomes a problem the moment a web page is meant to actively guide a user who is not constantly touching the screen. A recipe widget, a workout timer, or a full-screen presentation are typical candidates.

Before the Wake Lock API, developers reached for workarounds: playing an invisible, endlessly looping video, or scrolling the page by a pixel every few seconds via JavaScript. Both approaches worked unreliably, wasted battery unnecessarily, and felt like a hack because that is exactly what they were. The native API replaces these tricks with an explicit request controlled by the browser.

2. The core mechanism: navigator.wakeLock.request()

The entry point is navigator.wakeLock.request('screen'). The call returns a promise that resolves with a WakeLockSentinel object once the browser agrees to the request. Currently the specification only defines the type 'screen', though future extensions for other wake states are already being discussed.

It matters that the request runs in a secure context (HTTPS) and, in most cases, as a reaction to a user gesture, similar to the Fullscreen or Notifications API. A lock requested purely on page load without any interaction can be rejected by the browser or may not even be offered at all.


let wakeLockSentinel = null;

async function requestWakeLock() {
  try {
    wakeLockSentinel = await navigator.wakeLock.request('screen');
    console.log('Wake Lock active');

    wakeLockSentinel.addEventListener('release', () => {
      console.log('Wake Lock was released');
    });
  } catch (err) {
    console.error(`Wake Lock failed: ${err.name}, ${err.message}`);
  }
}

document.querySelector('#start-cooking').addEventListener('click', requestWakeLock);

3. Releasing locks correctly

An active wake lock is a resource you must not forget to release. As soon as the action is finished, whether the recipe is done or the upload has completed, call sentinel.release(). The sentinel object becomes invalid afterward and must be requested again if needed. A second, repeated call to release() on the same object does not throw an error in most implementations, but it is still advisable to manage your own state cleanly instead of relying on this tolerant behavior.

A frequently overlooked edge case: the browser automatically releases the lock once the tab moves to the background, gets minimized, or the screen locks. When the user returns to the page, the old sentinel is already invalid, even if release() was never explicitly called. Your own logic must detect this state and request the lock again when appropriate.


async function releaseWakeLock() {
  if (wakeLockSentinel) {
    await wakeLockSentinel.release();
    wakeLockSentinel = null;
  }
}

document.querySelector('#stop-cooking').addEventListener('click', releaseWakeLock);

4. Reacting to visibility changes

Since the lock automatically expires when moved to the background, it is worth listening to the document's visibilitychange event. When the tab becomes visible again and a lock was previously desired, the application can re-request the wake lock without a new user gesture, because the original consent is considered still valid.

This combination of a visibility listener and a re-request makes the wake lock logic robust against app switching on mobile devices, where users briefly open another app and then return. Without this mechanism, the screen could fall asleep again after returning, even though the activity is technically still running.


document.addEventListener('visibilitychange', async () => {
  if (wakeLockWanted && document.visibilityState === 'visible') {
    wakeLockSentinel = await navigator.wakeLock.request('screen');
  }
});

5. Feature detection and fallback

The API is not yet available everywhere, older mobile browsers and some desktop browsers do not fully support it. A simple check for 'wakeLock' in navigator is enough to determine whether the feature is offered before calling it.

If support is missing, the application should not simply stay silent, it should give the user a subtle hint, for example a note to keep the screen on manually or to increase the display timeout in system settings. It is important that the core functionality of the page remains fully usable without the wake lock, the API is a pure convenience feature.

6. Typical use cases

Besides recipe apps and video conferencing tools, presentation software, kiosk systems, fitness timers, and dashboards in control rooms all benefit from the API. Anywhere content is meant to be viewed over an extended period without touch interaction, the wake lock is a fitting solution.

Loading screens for lengthy uploads or file conversions are another good example: the user is actively waiting for a result but does not want to constantly tap the screen just to keep it awake. A wake lock during the loading process, released immediately upon completion, noticeably improves the experience here.

In education, interactive learning apps where a user follows a longer explainer video or a guided exercise also benefit from a stable wake lock, since a screen falling asleep mid-way interrupts the learning flow and forces an unlock right in the middle of a thought process. The same applies to meditation and breathing apps that display visual guidance over several minutes while the user's hands are not free to touch the screen. Self-checkout terminals and digital signage in waiting areas that run on a web page frequently rely on the Wake Lock API too, avoiding separate kiosk software while still staying visible at all times.

7. Battery consumption and responsible use

A permanently bright screen is one of the biggest battery drains on mobile devices. The Wake Lock API is therefore not a free pass to use it wherever convenient, but a targeted tool for clearly scoped time periods with real need.

Good practice means giving the user control: a visible toggle that shows whether the screen is currently being kept awake and that can be disabled at any time. This keeps it transparent why the battery drains faster and leaves the user in charge of their device. An automatic deactivation after a sensible maximum duration, for example after two hours of uninterrupted activity, is also a good safeguard against locks accidentally staying active forever when an application was forgotten in the background.

8. Security and permission model

Unlike camera or location access, the browser does not show a visible permission dialog for the Wake Lock API, control happens implicitly through the secure context and the user gesture requirement. Some browsers additionally allow restricting the behavior for embedded iframes via a Permissions-Policy header such as Permissions-Policy: screen-wake-lock=().

This is particularly relevant for pages with third-party content: an embedded ad widget should normally not be able to keep the entire page's screen awake. The Permissions-Policy lets you assign this capability specifically only to your own, trusted frames.

9. A complete practical example

In practice, requesting, releasing, and visibility handling are best encapsulated in a small reusable class or utility function that any component can use independently. This keeps the actual application logic free of API details while the wake lock state is managed centrally.

The snippet below shows a pattern that combines requesting, automatic restoration after a tab switch, and clean cleanup when leaving the page. The table afterward compares the workarounds that were common before with the native API.


class WakeLockManager {
  #sentinel = null;
  #wanted = false;

  async enable() {
    this.#wanted = true;
    if (!('wakeLock' in navigator)) return false;
    try {
      this.#sentinel = await navigator.wakeLock.request('screen');
      return true;
    } catch {
      return false;
    }
  }

  async disable() {
    this.#wanted = false;
    if (this.#sentinel) {
      await this.#sentinel.release();
      this.#sentinel = null;
    }
  }

  init() {
    document.addEventListener('visibilitychange', async () => {
      if (this.#wanted && document.visibilityState === 'visible' && !this.#sentinel) {
        await this.enable();
      }
    });
  }
}

const wakeLock = new WakeLockManager();
wakeLock.init();
Approach Reliability Battery cost Browser support
navigator.wakeLock.request() High, official API Controlled, explicit lock Chrome, Edge, Opera, partial Safari
Invisible looping video Medium, OS dependent Unnecessarily high due to video decoding Broad but unofficial
Periodic micro-scrolling Low, feels like a bug Increased through constant reflows Broad but unofficial
No mechanism Screen sleeps after timeout Minimal Always available

Mironsoft

Modern browser APIs, performance, and maintainable JavaScript

JavaScript that holds up in the real browser, not just in the tutorial?

We review existing frontend code for outdated patterns, unnecessary dependencies, and performance traps, then replace them with modern, native browser APIs that mean less bundle weight and less maintenance burden.

Code Review

Systematically finding outdated patterns, unnecessary dependencies, and memory leaks.

Performance Optimization

Improving bundle size, load time, and runtime performance with modern APIs.

Modernization

Deliberately introducing native browser APIs instead of heavy libraries.

10. Summary

Screen Wake Lock API: The Essentials at a Glance

Entry point

navigator.wakeLock.request('screen') returns a promise with a WakeLockSentinel.

Release

Always call sentinel.release() once the activity is finished.

Background

Locks expire automatically on tab switch, re-request via visibilitychange.

Fallback

Check feature detection and keep core functionality usable without the lock.

11. FAQ: Screen Wake Lock API: The Essentials at a Glance

1What exactly does the Screen Wake Lock API do?
It lets a web page explicitly ask the browser not to dim or lock the device screen automatically while the request stays active.
2Does the API require HTTPS?
Yes, the Wake Lock API only works in a secure context, meaning HTTPS or localhost during development.
3Do I have to release the lock manually?
Yes, sentinel.release() should end the lock as soon as it is no longer needed, otherwise the screen stays active unnecessarily.
4What happens if I switch tabs?
The browser automatically releases the wake lock once the tab moves to the background or the device locks, a new request is needed when returning.
5Can I check whether a browser supports the API?
Yes, the check 'wakeLock' in navigator lets you determine availability before calling the feature.
6Does the browser show a permission dialog?
No, unlike camera or location access there is no visible dialog, control happens through secure context and user gesture requirements.
7Does an active wake lock increase battery consumption?
Yes, a permanently bright screen consumes more energy, so the lock should only be set for clearly scoped, necessary time periods.
8Can I request multiple wake locks at once?
Technically yes, but it is more sensible to manage the state centrally in a single instance to keep release and restoration consistent.
9Can the API be restricted in embedded iframes?
Yes, the Permissions-Policy header with screen-wake-lock lets you specifically disable the capability for third-party frames.
10What alternatives existed before this API?
Developers used invisible looping videos or periodic micro-scrolling, both unreliable workarounds with unnecessarily high battery cost.