Page Lifecycle Events
active, passive, hidden, frozen, discarded — Page Lifecycle states and the events you should actually use.
- browser
- page-lifecycle
- visibility
- bfcache
- performance
Mobile browsers aggressively suspend, freeze, and discard background tabs. If you only know load/unload, you’ll lose analytics, leak connections, and block bfcache. The Page Lifecycle model names states and preferred events.
Docs: Page Lifecycle API, MDN Page Lifecycle (related visibility).
States (conceptual)
active → passive → hidden → frozen → discarded
↘ terminated (crash / hard kill)
| State | User-facing |
|---|---|
| active | Foreground, input possible |
| passive | Visible but another window has focus (desktop) |
| hidden | Not visible |
| frozen | JS timers paused; may resume (bfcache-like freeze) |
| discarded | Gone from memory; next view is a full reload |
Not every browser exposes every transition equally; code to progressive enhancement.
Events to prefer
| Prefer | Avoid |
|---|---|
visibilitychange |
Relying only on blur |
pagehide |
unload |
pageshow |
Assuming always cold start |
freeze / resume (where available) |
Ignoring freeze |
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/ingest', sessionSummary());
pauseVideo();
} else {
resumeVideo();
}
});
window.addEventListener('pagehide', (e) => {
// e.persisted → may enter bfcache
teardownRealtime({ keepForBfcache: e.persisted });
});
Why unload is toxic
unload breaks bfcache eligibility in many cases and is unreliable on mobile (tab kill without firing). Use pagehide + sendBeacon / fetch keepalive.
Practical policies
- Analytics: flush on
visibilitychangehidden /pagehide. - WebSockets: close or heartbeat carefully when hidden; reconnect on visible /
pageshowpersisted. - Media: pause when hidden.
- Timers: don’t assume
setIntervalruns in background. - Auth: revalidate on resume from bfcache — bfcache.
discarded
Chrome may discard background tabs under memory pressure. Next navigation reloads document. Design for restartable state (persist drafts to IDB/localStorage).
Interview out-loud
“Page Lifecycle covers active through frozen and discarded. I use visibilitychange and pagehide instead of unload so mobile and bfcache work. On pageshow with persisted I revalidate session and reconnect.”
Testing freeze/discard
Chrome’s Lifecycle helpers and “Discard tab” experiments (where available) help validate resume paths. Manually: background the tab for minutes on Android, return, confirm sockets reconnect and forms still have drafts from IDB. Assume timers did not run while frozen.
Analytics integrity
Session duration and bounce metrics go wrong when you only listen to unload. Mobile may kill the tab without firing it. Prefer visibilitychange for “session engaged” heartbeats and pagehide for final beacons. Deduplicate with a session id in sessionStorage so restored bfcache pages do not look like brand-new sessions unless you intentionally define them that way.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.
- Browser DevTools Performance PanelRecord main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.
- Browser Networking 101DNS, TCP/TLS, HTTP/1.1 vs H2/H3, connection reuse, and what frontend code can actually influence.
- Compositor LayersWhen browsers promote layers, why transform/opacity animate cheaply, and layer explosion costs.