Technology
Keeping the phone screen on in a web app people use mid-game (Wake Lock API, the parts that bite)
Source: Dev Community|
3 min read
I run a small fan site for a Fortnite event, and one page is a chest counter: you tap +1 every time you open a chest, and it turns the count into odds. Analytics showed something I hadn't designed for. On phones, people tap it about 50 times per visit. They prop the phone next to the console and keep tapping between fights. Which means the phone goes to sleep between matches, and every time they come back they have to unlock it first. So I added the Screen Wake Lock API. The happy path is one line: The rest of this post is the stuff that one line doesn't tell you. 1. The browser takes the lock away, a lot A wake lock is released automatically whenever the page is hidden: switching apps, locking the phone, changing tabs. When the user comes back, you don't get it back for free. You have to request it again on visibilitychange: If you only request once on load, it silently stops working the first time someone checks a message. 2. Don't grab it on page load Plenty of visitors read the page and leave. Holding the screen on for them just drains their battery. I only ask for the lock after the first tap on a counter button, and only re-acquire on visibilitychange if counting has started: 3. Requests can fail, and that's fine request() rejects in battery-saver mode, in some embedded browsers, and under certain permission policies. The counter must keep working anyway, so the failure is swallowed: catch { sentinel = null; // counting still works, the screen just sleeps } Also guard against double requests: a fast double-tap can fire two request() calls before the first resolves. I keep a pending promise and skip if one is in flight. 4. Give people an off switch, and remember it Some people don't want their screen pinned on. A checkbox, "Keep my screen on while counting", is on by default, and the choice goes into localStorage (wrapped in try/catch, since private mode can throw). Turning it off releases the current lock right away. 5. Hide the option where it can't work Older iOS Safari (before 16.4) has no navigator.wakeLock. Showing a checkbox that does nothing is worse than no checkbox, so the row starts hidden and is only revealed when the API exists. The whole thing Here is the module as it runs on the site, small enough to paste: export Passing wakeLock and doc in, instead of reading navigator and document inside, is what makes it testable: in Node I hand it a fake wakeLock that records calls and a fake document I can "show" again, then assert things like "the first tap requests once, later taps reuse it" and "after the browser releases it, showing the page takes it back". Eight small tests, no browser needed. You can try it on the Pirate Token chest tracker: tap +1 once, then leave your phone alone and watch it not go dark. If you've hit other Wake Lock edge cases (I'd love to hear how Samsung Internet behaves), tell me in the comments.