Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

5.1 Page lifecycle: the hidden transition is the contract

The spec's MUST-flush-on-hidden guarantee parsed clause by clause, state-versus-event reasoning, ordering, and mobile reality.

Levels: Intermediate ~13 min read

Intermediate

Everything in this series so far has been about getting data accepted. This page is about when the browser promises to actually move it. The answer is a single normative sentence, and it keys on a state — the document's visibilityState becoming "hidden" — not on any event name you might be used to wiring.

The guarantee, verbatim

"The user agent MUST schedule immediate transmission of all beacon requests when the document visibilityState transitions to hidden, and must allow all such requests to run to completion without blocking other time-critical and high-priority work." — Beacon, sendBeacon method

Parse it as three commitments. Immediate transmission: hidden is not a hint, it is a deadline — the browser flushes queued beacons right then, not at some idle moment. Run to completion: the requests are allowed to finish their network work even as the page is being frozen or discarded. And Without blocking: the flush must not starve time-critical work — which is why the same spec text that demands immediacy also allows the user agent to schedule transmission to minimize contention. The guarantee is about ordering against page death, not about microsecond latency.

State transitions, not event names

The spec deliberately names the state, not the DOM event that reports it. In JavaScript you observe the transition with visibilitychange — and inside the handler you must re-check the state ( document.visibilityState === 'hidden'), because the same event fires for the visible direction, and handlers that branch on the event name alone double-fire or fire backwards. The runnable example drives the real document of its sandbox frame through the interesting sequences:

Interactive Runnable example
Edit

Ready to run.

Ordering, mobile reality, and what is guaranteed

The order in which the signals arrive is browser behavior, consistent across modern engines but not spec text, and worth knowing exactly: on desktop navigation the visibility transition fires before pagehide, so a flush keyed on hidden is also early enough for any pagehide-dependent bookkeeping. On mobile, app switches and screen locks fire the visibility transition where desktop fires navigation events; a hard OS kill or crash fires nothing at all — which is the deepest argument for flushing on every hidden transition rather than hoarding data for one final moment that may never be signaled.

Quick check

Which handler body is spec-faithful for the last-gasp flush?

document.addEventListener('visibilitychange', );

Key takeaways

  • The spec's MUST: immediate transmission of all beacons when visibilityState transitions to hidden.
  • Key on the state, not the event: inside visibilitychange, re-check document.visibilityState.
  • On desktop navigation, hidden fires before pagehide (browser behavior, consistent across engines).
  • On mobile, the hidden transition is the reliable signal; hard kills fire nothing — flush early, flush often.
  • The flush guarantee is sendBeacon-only; fetch(keepalive) survives teardown but is not spec-bound to flush on hidden.
Was this page helpful?

Mark this learning resource complete to track your learning progress.