· deepdives · 7 min read
Mastering User Experience: A Deep Dive into the Screen Wake Lock API
Learn how to use the Screen Wake Lock API to prevent device screens from sleeping during critical tasks. This guide covers browser support, practical code examples (vanilla JS, TypeScript, React hook), fallbacks, UX considerations, performance tips, and real-world use cases.

Why preventing screen sleep matters
Screens that unexpectedly dim or sleep during critical tasks - navigation, video calls, cooking timers, guided workouts, or point-of-sale kiosks - break flow and harm user experience. Traditionally web apps had few safe, standardized ways to keep the device awake. The Screen Wake Lock API changes that by offering a clean API to request that the screen remain on while your app needs it.
This article explains how the API works, best practices for a responsible implementation, fallback strategies for unsupported browsers, practical code examples (vanilla JS, TypeScript, and a React hook), and real-world scenarios where a wake lock improves UX.
What the Screen Wake Lock API does (and doesn’t)
- The API allows a web page to request a wake lock of type
screen
, which prevents the display from dimming or locking while the document is visible. - It is intended for short-lived, user-initiated use - not indefinite background persistence.
- The API does not override system-level power policies or permissions on the device; the user agent (browser/OS) may still enforce limits.
Useful references:
- MDN: Screen Wake Lock API
- W3C spec: Screen Wake Lock
- Browser support overview: Can I use - Screen Wake Lock API
Browser support and feature detection
Support has improved but is not universal. Always do feature detection and provide a fallback.
Basic detection:
if ('wakeLock' in navigator) {
// Safe to attempt a wake lock
} else {
// Provide fallback or graceful degradation
}
Caniuse and MDN are good places to check current support and platform caveats. If support is missing, consider a graceful fallback (see the fallback section below).
Core API patterns
At its simplest, requesting a screen wake lock looks like this:
let wakeLock = null;
async function requestWakeLock() {
try {
wakeLock = await navigator.wakeLock.request('screen');
console.log('Wake lock active');
// Optional: listen for release events
wakeLock.addEventListener('release', () => {
console.log('Wake lock released');
});
} catch (err) {
console.error(`Wake lock request failed: ${err.name}, ${err.message}`);
}
}
async function releaseWakeLock() {
if (wakeLock) {
try {
await wakeLock.release();
wakeLock = null;
} catch (err) {
console.error('Failed to release wake lock:', err);
}
}
}
Important notes:
- The returned object is a WakeLockSentinel. You can call
.release()
or listen for itsrelease
event. - The sentinel can be invalidated by the UA (browser) for reasons such as power saving.
- Re-requesting may be necessary when the document regains visibility.
Handling visibility changes and re-acquisition
A common pattern is to re-request the wake lock when the page becomes visible again. Browsers may automatically release wake locks when a tab is hidden or when the OS applies power-saving policies.
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible') {
await requestWakeLock();
} else {
await releaseWakeLock();
}
});
This ensures the lock is active only when the user can see and interact with the page.
Using AbortController to manage lifetime
Some implementations accept an AbortSignal so you can abort the request cleanly.
const ac = new AbortController();
try {
wakeLock = await navigator.wakeLock.request('screen', { signal: ac.signal });
} catch (err) {
if (err.name === 'AbortError') {
console.log('Wake lock request aborted');
}
}
// Later to cancel
ac.abort();
Check support for the options object in your target browsers.
Practical implementation: TypeScript example
let wakeLock: WakeLockSentinel | null = null;
export async function enableWakeLock(): Promise<void> {
if (!('wakeLock' in navigator)) return;
try {
wakeLock = await (navigator as any).wakeLock.request('screen');
wakeLock.addEventListener('release', () =>
console.log('Wake lock released')
);
} catch (err) {
console.error('Could not get wake lock:', err);
}
}
export async function disableWakeLock(): Promise<void> {
if (!wakeLock) return;
try {
await wakeLock.release();
} finally {
wakeLock = null;
}
}
(You may need to augment global declarations for WakeLockSentinel
or use any
depending on your TypeScript config.)
React hook: useWakeLock
A reusable React hook encapsulates the logic and visibility handling:
import { useEffect, useRef } from 'react';
export function useWakeLock(enabled) {
const wakeLockRef = useRef(null);
useEffect(() => {
if (!('wakeLock' in navigator) || !enabled) return;
let mounted = true;
async function requestLock() {
try {
wakeLockRef.current = await navigator.wakeLock.request('screen');
wakeLockRef.current.addEventListener('release', () =>
console.log('released')
);
} catch (err) {
console.error('Wake lock failed', err);
}
}
requestLock();
function handleVisibility() {
if (document.visibilityState === 'visible' && enabled) requestLock();
}
document.addEventListener('visibilitychange', handleVisibility);
return () => {
mounted = false;
document.removeEventListener('visibilitychange', handleVisibility);
if (wakeLockRef.current) wakeLockRef.current.release();
};
}, [enabled]);
}
Use the hook in a component that has a user-controlled toggle for wake-lock behavior.
Fallback strategies for unsupported environments
- NoSleep.js: A widely used workaround that plays an invisible looping video to keep the device awake. Not ideal (hacks, power/performance issues), but effective on older browsers: https://github.com/richtr/NoSleep.js
- In many cases, educating the user and offering an explanatory toggle (“Keep screen on”) that suggests they change native device settings can be acceptable.
- Progressive enhancement: only enable wake lock features when supported, and ensure your app behaves acceptably without it.
UX and ethical considerations (don’t be reckless)
- Request wake locks only for clearly user-initiated and necessary tasks (guided workouts, timers, navigation, POS, healthcare monitoring).
- Always show a visible indicator (icon or status line) when a wake lock is active so users know their screen will stay on.
- Provide an easy way to disable the behavior (toggle in UI, automatic release after task completion).
- Be transparent about battery impact, especially for long-running operations.
- Test on battery-limited devices and explain to users when keeping the screen on may drain battery.
Real-world use cases and patterns
- Navigation and maps: Keep the screen on during turn-by-turn navigation so users don’t have to touch the device while driving or walking.
- Video and conferencing apps: Prevent the screen from dimming during active calls or when streaming live video that doesn’t rely on the
- Workout/fitness timers: Keep the display on for exercise sets, timers, or guided workout steps.
- Kiosk/interactive displays: Maintain a consistent experience for customers interacting with a public display.
- Medical/monitoring dashboards: Ensure critical monitoring dashboards stay visible during patient observations.
- Presentations and demos: Prevent displays from sleeping mid-presentation.
Testing checklist
- Test on iOS, Android, desktop browsers - behavior and support differ.
- Test with battery saver modes enabled; some UAs may force release.
- Verify visibility-change handling by switching tabs, locking/unlocking the device, or moving to a different app.
- Ensure wake locks are released on unload and on component unmount.
- Check for memory leaks: if you add event listeners on the sentinel, remove them when releasing.
Performance and resource advice
- Wake locks prevent the screen from sleeping, which increases battery usage. Use them sparingly.
- Avoid combining unnecessary timers, heavy animations, and a wake lock; each increases energy consumption.
- Release the lock as soon as the task completes. Do not hold the lock indefinitely.
Debugging common issues
- Request fails with
NotAllowedError
orSecurityError
: ensure the page is served in a secure context (HTTPS) and that your UA supports wake lock in the current state. Some platforms require a user gesture. - Wake lock is released unexpectedly: handle
release
events and re-acquire onvisibilitychange
when appropriate. - Wake lock seems ignored on mobile: many mobile OSs aggressively suspend webpages; check your target browser’s policies.
Example: Minimal production-ready pattern
A robust pattern ties together feature detection, re-acquisition on visibility changes, and a UI indicator:
let sentinel = null;
async function enableKeepAwake() {
if (!('wakeLock' in navigator)) return false;
try {
sentinel = await navigator.wakeLock.request('screen');
sentinel.addEventListener('release', () => updateUI(false));
updateUI(true);
return true;
} catch (err) {
console.warn('Wake lock unavailable:', err);
updateUI(false);
return false;
}
}
async function disableKeepAwake() {
if (!sentinel) return;
await sentinel.release();
sentinel = null;
updateUI(false);
}
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible' && sentinel == null) {
await enableKeepAwake();
}
});
function updateUI(active) {
const el = document.getElementById('wakeLockIndicator');
if (!el) return;
el.textContent = active ? 'Keep screen on - active' : 'Keep screen on - off';
}
Final checklist before shipping
- Add feature detection and graceful fallback.
- Only enable on explicit user action or clearly user-expected flows.
- Provide a visible status and easy way to disable.
- Handle visibility changes and sentinel
release
events. - Test across devices and battery saver scenarios.
- Monitor analytics (how often feature is used) and user feedback for battery complaints.
Further reading
- MDN: Screen Wake Lock API
- W3C spec: Screen Wake Lock
- NoSleep.js (fallback): GitHub repository
- Feature support: Can I use - Screen Wake Lock API
By using the Screen Wake Lock API responsibly - with proper feature detection, user consent, visible UI affordances, and fallbacks - you can significantly improve user experience for tasks where screen-on behavior is essential, while minimizing unwanted battery drain and respecting platform constraints.