loke.dev
Header image for How to Keep a Device’s Screen Awake Without the "Invisible Video" Hack

How to Keep a Device’s Screen Awake Without the "Invisible Video" Hack

The Screen Wake Lock API offers a native, battery-conscious way to keep displays active during critical user tasks without resorting to hacky workarounds.

· 3 min read

How to Keep a Device’s Screen Awake Without the "Invisible Video" Hack

You’re halfway through a complex recipe, your hands are covered in flour, and just as you need to check the next step, your tablet screen goes pitch black. Or maybe you're building a dashboard that needs to stay visible during a long deployment process. In the old days, we solved this by embedding a 1px by 1px invisible video that played on a loop. It worked, but it was a battery-guzzling disaster and felt like trying to fix a leaky faucet with chewing gum.

The Screen Wake Lock API is the grown-up, native way to prevent devices from dimming or locking the screen. It’s cleaner, more efficient, and actually tells the operating system *why* you’re hogging the backlight.

The Bare Minimum to Get Started

At its simplest, a wake lock is just a promise. You ask the browser for a "screen" lock, and if the user hasn't blocked it (and the battery isn't critically low), you get a WakeLockSentinel object back.

let wakeLock = null;

const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    console.log('Screen is staying awake! 🛡️');
  } catch (err) {
    // The browser might refuse if the battery is low or the tab is hidden
    console.error(`${err.name}, ${err.message}`);
  }
};

requestWakeLock();

Why the "Invisible Video" Was a Nightmare

If you’ve never used the video hack, count yourself lucky. It involved creating a Base64-encoded string of a silent, tiny video and forcing it to play. Not only did this keep the screen on, but it also kept the CPU and GPU active to "render" those invisible pixels.

The Screen Wake Lock API is much kinder to the hardware. It allows the system to optimize power consumption. Plus, it’s much easier to debug than a phantom <video> element buried in your DOM.

Managing the "Sentinel"

The object returned by the request—the WakeLockSentinel—is your handle for the lock. You don’t just fire and forget; you need to know when the lock is released. Browsers are aggressive about saving power, so they will release your lock if the user minimizes the tab or switches apps.

You can listen for the release event to update your UI or log the state.

const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');

    wakeLock.addEventListener('release', () => {
      console.log('Wake Lock was released. The screen can now dim.');
    });

  } catch (err) {
    console.error(`Failed to lock screen: ${err.message}`);
  }
};

To manually release it (because being a good citizen means giving the battery a break when you’re done):

// Later, when the task is finished...
if (wakeLock !== null) {
  wakeLock.release();
  wakeLock = null;
}

The "Gotcha": Visibility Changes

This is where most people get tripped up. A wake lock is automatically released when a tab becomes inactive. If I’m looking at your recipe app, then jump over to Twitter to complain about my floury hands, the browser releases the lock. When I switch back to your app, the lock does not automatically re-engage.

You have to handle this yourself using the visibilitychange event.

const handleVisibilityChange = async () => {
  if (wakeLock !== null && document.visibilityState === 'visible') {
    await requestWakeLock();
  }
};

document.addEventListener('visibilitychange', handleVisibilityChange);

Putting it All Together (The "Copy-Paste" Version)

If you're looking for a robust implementation that handles checking for browser support and managing the lifecycle, here is a clean way to wrap it up:

let wakeLock = null;

async function toggleWakeLock() {
  // 1. Check if the browser even supports it
  if ('wakeLock' in navigator) {
    try {
      // 2. Request the lock
      wakeLock = await navigator.wakeLock.request('screen');
      
      wakeLock.addEventListener('release', () => {
        console.log('Wake Lock released');
      });
      
      console.log('Wake Lock active');
    } catch (err) {
      console.error(`Wake Lock Error: ${err.message}`);
    }
  } else {
    console.error('Wake Lock API not supported in this browser.');
  }
}

// Re-acquire lock when the page becomes visible again
document.addEventListener('visibilitychange', async () => {
  if (wakeLock !== null && document.visibilityState === 'visible') {
    await toggleWakeLock();
  }
});

A Few Real-World Rules

1. HTTPS is mandatory. Like most modern Web APIs (Geolocation, Camera, etc.), this won't work over an unsecure connection.
2. User Activation is usually required. You can't just grab a wake lock the second a page loads. It usually needs to happen inside a click handler or some form of user interaction.
3. Don't be a battery hog. Only request the lock when it’s absolutely necessary. If your app is just a static blog post, let the screen dim. If it’s a fitness timer or a navigation tool, lock away.

The Screen Wake Lock API is one of those "small but mighty" additions to the web platform. It replaces a hacky, resource-heavy workaround with a single, intent-based method call. Your users' batteries will thank you.