API in Capabilities
Screen Wake Lock API
Published
navigator.wakeLock.request("screen") asks the operating system not to dim or lock the display while the document stays visible, and resolves with a WakeLockSentinel that you release yourself or that the browser releases for you the moment the page is hidden. The lock is the right tool for a recipe view, a presentation, or a live tracking screen; it does nothing for background work, because a hidden document can neither hold nor request one.
Chrome 84, Edge 84, Firefox 126, and Safari 16.4 on macOS implement the API without caveats. Safari on iOS 16.4 to 18.3 is recorded as partial in browser-compat-data: the lock has no effect in a standalone Home Screen web app (WebKit bug 254545), and the entry lists iOS 18.4 as the first full release.
Syntax
Section titled “Syntax”navigator.wakeLock.request()navigator.wakeLock.request(type)
sentinel.release()request() returns a Promise<WakeLockSentinel>. release() on the sentinel returns a Promise<undefined> and fires a release event on the sentinel when the lock is gone, whoever released it. Both interfaces are [SecureContext] and exposed on Window only: navigator.wakeLock is undefined on http:// origins other than localhost, and workers have no wake lock at all.
Parameters
Section titled “Parameters”request() takes one optional argument; the sentinel it resolves with exposes three members and one event.
| Name | Type | Required | Description |
|---|---|---|---|
type |
WakeLockType (enum) |
No, defaults to "screen" |
The only value the specification defines is "screen". A "system" type (keep the CPU awake with the screen off) was discussed and dropped; passing it is a WebIDL enum violation. |
WakeLockSentinel member |
Type | Description |
|---|---|---|
released |
boolean (read-only) |
false while the lock is held; true after release() resolves or after the browser released it. Chrome 87 added the attribute (Chrome 84 to 86 shipped the sentinel without it). |
type |
WakeLockType (read-only) |
Echoes the requested type, "screen". |
release() |
Promise<undefined> |
Removes this sentinel from the document’s active locks and releases the platform lock when no other sentinel of the same type remains. |
release event |
Event |
Fired once per sentinel when it is released, including releases the browser performs on page hide, document unload, or OS intervention. |
Several sentinels can be live at once; the platform lock is released when the last one is. The browser also releases every sentinel when document.visibilityState becomes "hidden" and does not restore it when the page becomes visible again.
Exceptions
Section titled “Exceptions”request() rejects with a DOMException or a TypeError. Every rejection the specification defines carries the same name.
| Exception | Condition |
|---|---|
NotAllowedError |
The document is not fully active; or the screen-wake-lock Permissions Policy denies the document (default allowlist 'self'); or the browser denies this lock type for the document; or document.visibilityState is "hidden" at call time or by the time the permission check finishes; or the screen-wake-lock permission resolves to "denied". |
TypeError |
type is not a member of the WakeLockType enum (WebIDL conversion fails before the algorithm starts). |
A low battery or a power-saving mode is a reason the specification lets the browser deny the lock (section 12, Security considerations), and in Chromium that denial surfaces as NotAllowedError. Failure further down, at the operating-system level, is deliberately hidden: the specification notes that a lock the OS refused is indistinguishable from an acquired one, so the promise still resolves and released stays false. release() does not reject; calling it on a sentinel that is already released resolves immediately.
Examples
Section titled “Examples”Both examples feature-detect navigator.wakeLock and run a fallback when it is missing (Firefox before 126, Safari before 16.4, Android WebView builds that strip the permission).
Holding the screen during a workout and re-acquiring after a tab switch
Section titled “Holding the screen during a workout and re-acquiring after a tab switch”The lock is lost whenever the page is hidden, so the visibilitychange listener requests it again when the page returns and the workout is still running. When the API is absent the app shows a one-line hint instead of silently letting the screen time out.
let sentinel = null;let workoutRunning = false;
async function keepScreenOn() { if (!('wakeLock' in navigator)) { document.querySelector('#hint').textContent = 'Raise your screen timeout in system settings; this browser has no wake lock.'; return; } try { sentinel = await navigator.wakeLock.request('screen'); sentinel.addEventListener('release', () => { sentinel = null; }); } catch (err) { console.warn(`${err.name}: ${err.message}`); }}
document.querySelector('#start').addEventListener('click', async () => { workoutRunning = true; await keepScreenOn();});
document.querySelector('#stop').addEventListener('click', async () => { workoutRunning = false; await sentinel?.release();});
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible' && workoutRunning && !sentinel) { keepScreenOn(); }});sentinel?.release() is safe after the browser already released the lock: the release listener has set sentinel to null, so the optional chain skips the call.
Binding a checkbox to the real lock state
Section titled “Binding a checkbox to the real lock state”A UI control that claims the screen is being kept awake has to follow the sentinel, not the click, because the browser can release the lock without the user touching the checkbox. Reading released in the release handler keeps the two in step.
const box = document.querySelector('#keep-awake');let sentinel = null;
box.disabled = !('wakeLock' in navigator);
box.addEventListener('change', async () => { if (box.checked) { try { sentinel = await navigator.wakeLock.request('screen'); sentinel.addEventListener('release', () => { box.checked = !sentinel.released; // false once the browser lets go }); } catch (err) { box.checked = false; // rejected: hidden page, policy, or denial } } else { await sentinel?.release(); }});Disabling the checkbox when navigator.wakeLock is missing tells the user up front that the option is unavailable here rather than failing on the first toggle.
See also
Section titled “See also”- Media Session API, the companion for playback screens that also need lock-screen controls
- Idle Detection API, for reacting to the user walking away instead of preventing the screen from locking
- PWAs on iOS and Safari, where the Home Screen web-app caveat lives
- Screen Wake Lock API: request() method (w3.org)
- Screen Wake Lock API: Security considerations (w3.org)
- WebKit bug 254545: Screen Wake Lock in Home Screen web apps (webkit.org)
- Stay awake with the Screen Wake Lock API (developer.chrome.com)
Specifications
| Specification | Status |
|---|---|
| Screen Wake Lock | W3C |
| Screen Wake Lock API: request() method | W3C |
| Screen Wake Lock API: release() method | W3C |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 84 | high | source | — |
| Chrome (Android) | Yes | 84 | high | source | 1 |
| Edge (Desktop) | Yes | 84 | high | source | 2 |
| Firefox (Desktop) | Yes | 126 | high | source | — |
| Firefox (Android) | Yes | 126 | high | source | 3 |
| Safari (macOS) | Yes | 16.4 | high | source | — |
| Safari (iOS) | Partial | 16.4 → 18.4 | high | source | 4 |
| Samsung Internet | Yes | 14.0 | high | source | 5 |
| WebView (Android) | Yes | 84 | high | source | 6 |
| Opera | Yes | 73 | low | source | — |
- Derived by browser-compat-data mirroring from Chrome.
- Derived by browser-compat-data mirroring from Chrome.
- Derived by browser-compat-data mirroring from Firefox.
- Does not work in standalone Home Screen Web Apps. See bug 254545 (https://webkit.org/b/254545#c32).
- Derived by browser-compat-data mirroring from Chrome Android.
- Derived by browser-compat-data mirroring from Chrome Android.