Idle Detection
IdleDetector reports whether the user has been inactive and whether the screen is locked -- using OS-level signals, not just tab focus. The threshold is minimum 60 seconds, and it requires explicit permission. Chromium only.
Chat apps show "Away" when you stop responding. Netflix asks "Still watching?" after you have not touched anything in a while. Both need the same thing: a reliable signal that the user is no longer present.
The Idle Detection API provides that signal from the operating system -- not just from the tab.
This distinction matters. A user who switches to WhatsApp to reply to a message is still active at the OS level, even though your web app's tab is in the background. The Idle Detection API sees that interaction and reports the user as active. A blur event on the window would not.
The Two States
The API reports two independent dimensions:
User state:
"active"-- the user has interacted with any app or the OS recently (mouse, keyboard, touch, anything)"idle"-- no user interaction detected for at least the configured threshold
Screen state:
"unlocked"-- the screen is visible and accessible"locked"-- the screen is off or the lock screen is showing
These states are independent. The screen can be locked while the user state is still "active" -- that happens when a user locks their phone immediately after using it.
Requesting Permission and Starting Detection
// Permission must be requested first
const permission = await IdleDetector.requestPermission()
if (permission !== 'granted') return
// Create the detector and start it
const detector = new IdleDetector()
detector.addEventListener('change', () => {
console.log('User state:', detector.userState)
console.log('Screen state:', detector.screenState)
})
await detector.start({
threshold: 60_000, // 60 seconds minimum -- browser enforces this floor
signal: abortController.signal // optional: stop detection when aborted
})threshold sets how long the user must be inactive before userState flips to "idle". The browser enforces a minimum of 60 seconds -- you cannot detect inactivity at shorter intervals. This is intentional: shorter thresholds would make idle state useful for timing attacks.
Practical Uses
Chat presence. Set userState to "away" in your chat UI when the detector reports "idle". Reset to "active" when it returns to "active". This is how modern chat apps show whether a contact is currently at their device.
Reduce background work. When the user goes idle, lower the frequency of polling operations, pause non-critical animations, or defer expensive computations. The user is not watching -- save their battery.
"Are you still there?" Video or content streaming services use this to pause playback and prompt the user rather than waste bandwidth serving content no one is watching.
Lock-screen detection. When screenState becomes "locked", pause any audio or video the page might be playing -- the screen is off, the user has stepped away.
ExpandIdle Detection API: active/idle user state transitions, unlocked/locked screen state, and the setup flow
The Privacy Tradeoff
The Idle Detection API requires explicit permission precisely because it reveals information about the user's behavior at the OS level. An idle state tells you the user stepped away, which can reveal information about their schedule or habits over time.
The 60-second minimum threshold and the permission requirement are the spec's mitigations. The API is Chromium-only -- Firefox and Safari have not implemented it, partly over these same privacy concerns.
Stopping Detection
Pass an AbortController signal to start() and call abort() to stop:
const controller = new AbortController()
await detector.start({ threshold: 60_000, signal: controller.signal })
// Later, to stop:
controller.abort()The detector also stops automatically when the page is hidden or when the user revokes permission.
Support
Idle Detection is Chromium only. It works in Chrome and Edge. Firefox and Safari do not implement it.
if ('IdleDetector' in window) {
// Idle Detection is available
}That closes out the device-state chapter. The next chapter shifts from reading device state to integrating with the operating system itself -- starting with what it means for a web app to be installed. PWA and OS Integration explains what installation unlocks and why it matters for every API that follows.
The Essentials
userStateis"active"or"idle"based on OS-level interaction -- not just your tab. Mouse movement in another app counts as active.screenStateis"unlocked"or"locked"-- independent of user state.IdleDetector.requestPermission()is required first. Thendetector.start({ threshold }).- Minimum threshold is 60 seconds, browser-enforced. Cannot detect inactivity at shorter intervals.
changeevent fires when either state changes. Stop with anAbortControllersignal.- Chromium only. Safari and Firefox have not implemented it.
Further Reading and Watching
- How to detect when user AFK (Detect When the User Is Idle with Idle Detection API) (YouTube) -- walks through requestPermission, start(), the change event, and how userState and screenState differ
- Detect inactive users with the Idle Detection API -- Chrome for Developers -- official guide covering the permission model, threshold behavior, AbortController pattern, and privacy considerations
Keep reading