Screen Wake Lock

navigator.wakeLock.request('screen') prevents the display from sleeping. One async call, a release event for when the OS revokes it, and a good-citizen pattern for re-requesting. Now green tier -- Safari finally shipped it.

June 10, 20263 min read17 / 17

The screen dims and the user's progress disappears. Every developer who has built a recipe app, a workout tracker, or a presentation viewer has hit this.

The Screen Wake Lock API solves it in one async call.

Requesting a Wake Lock

JavaScript
let wakeLock = null async function keepScreenOn() { wakeLock = await navigator.wakeLock.request('screen') }

navigator.wakeLock.request('screen') returns a WakeLockSentinel -- a reference to the active lock. While this sentinel is held, the display will not sleep automatically.

No permission dialog appears. The browser grants the lock immediately.

The Sentinel and the release Event

The OS can revoke the lock at any time: the user switches tabs, the app loses focus, or the battery drops critically low. The release event fires when this happens:

JavaScript
wakeLock.addEventListener('release', () => { wakeLock = null // The screen may now sleep -- re-request if the experience is still active })

Releasing manually:

JavaScript
await wakeLock.release() wakeLock = null

The sentinel also has a .released boolean you can check synchronously.

Screen Wake Lock lifecycle: request, acquired, and the conditions that trigger release ExpandScreen Wake Lock lifecycle: request, acquired, and the conditions that trigger release

Being a Good Citizen

A wake lock prevents the OS from saving battery. A screen that never sleeps is a screen that drains power the user did not consent to.

Release the lock when the experience ends:

JavaScript
function onLeaveRecipePage() { if (wakeLock) { wakeLock.release() wakeLock = null } }

Re-request when the tab becomes visible again. The OS automatically releases the sentinel when a tab is hidden:

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

This pattern -- release on hide, re-request on show -- is the approach recommended by the spec.

Green Tier

Screen Wake Lock is green tier. Chrome, Firefox, Edge, and Safari all support it. Safari was the last holdout, shipping the API in Safari 16.4 (March 2023).

JavaScript
if ('wakeLock' in navigator) { // Screen Wake Lock is available }

No HTTPS exception -- the API requires a secure context, same as geolocation and camera. It does not require a permission dialog, but browsers may still refuse the request if the page is not focused or visible.

When Not to Use It

  • When the user cannot see the screen. If they are not actively watching, there is no reason to keep it on.
  • Without a visible status indicator. Users who notice battery drain will be confused. Show a small "screen stays on" label.
  • Indefinitely. Always tie the lock to a specific user action -- entering a recipe step, starting a workout, launching a presentation. Release it when that action ends.

That is the last API in this chapter on device sensors and input. The next chapter steps outside the device entirely. Web Bluetooth is about reaching across the air to BLE hardware in the space around the user -- and the first thing you will learn is that the API is the easy part.

The Essentials

  1. await navigator.wakeLock.request('screen') -- async, no dialog, returns a WakeLockSentinel.
  2. The OS can revoke the lock anytime (tab hidden, battery critical). Listen to the release event and re-request if needed.
  3. Release manually when the experience ends: await wakeLock.release().
  4. Green tier as of Safari 16.4 (2023) -- works in Chrome, Firefox, Edge, and Safari.
  5. Be a good citizen: always pair a wake lock with an explicit release condition and a visible indicator.

Further Reading and Watching