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

1.1 The fire-and-forget problem, and the API that solves it

Why teardown-time telemetry is hard, what navigator.sendBeacon() promises (queueing, not delivery), and the fixed fetch recipe every beacon request carries.

Levels: Beginner ~12 min read

Basic

Every analytics pipeline, error reporter, and A/B logger eventually hits the same wall: the most important telemetry is produced at the exact moment the page is being torn down. The user clicks a link, closes the tab, or switches apps — and the code that was supposed to report what just happened is racing the browser's demolition crew. Ordinary tools lose that race more often than they win it, because they were never designed to survive the context that created them.

This series is about the platform's answer: the navigator.sendBeacon() method defined by the W3C Beacon specification, the keepalive flag of the Fetch standard that powers it, and the fetchLater() deferred-fetch API that extends the idea. Each part builds on the previous one, and every code sample runs exactly as shown — the runnable examples on these pages execute in a sandboxed frame whose Content-Security-Policy blocks the network, which turns out to be the perfect laboratory for observing what this API actually promises (and what it deliberately does not).

Why teardown-time telemetry is hard

A page's JavaScript stops running when the page goes away. That single fact invalidates the three tools you would otherwise reach for. An XMLHttpRequest or fetch() call needs the document alive long enough to complete the network round trip, but navigation can discard the document at any moment after the handler returns. An in-memory buffer of unsent events evaporates with the document itself. And the classic workaround — a synchronous request inside an unload handler — blocks the UI thread, delays the very navigation the user asked for, and is progressively disallowed by modern browsers precisely because of the damage it does.

The result is a systematic blind spot: the events that mark the end of a session are the least likely to be recorded. Funnel completion, rage-click bursts right before abandonment, form data typed but never submitted — all of it disappears at the moment of dismissal. What is needed is a way to hand data to the browser and say: this must outlive the page. That is the contract the Beacon API formalizes.

One method, one boolean, no response

The entire API surface is a single method on navigator, defined by the W3C Beacon specification (a Candidate Recommendation Draft, with a live Editor's Draft; it has never been part of the WHATWG HTML Standard):

webidl
// W3C Beacon — the complete IDL:
partial interface Navigator {
  boolean sendBeacon(USVString url, optional BodyInit? data = null);
};

One call queues a POST request that the browser guarantees to keep working on even after the page that created it is gone. There is no callback, no Promise, no Response object — the method returns true if the browser accepted the data into its transfer queue, and false if it refused (almost always because of the payload-size quota this series covers in depth). The spec's own wording is worth memorizing, because the distinction it draws is the most misunderstood fact in the whole API: the return value describes queueing, not delivery.

"The sendBeacon() method returns true if the user agent is able to successfully queue the data for transfer. Otherwise it returns false." — Beacon, Return Value

What the browser actually sends

Internally, the Beacon spec's processing model builds a request with a fixed recipe — you control none of these fields:

The fixed request recipe a sendBeacon call produces (W3C Beacon, processing model).

Request field

Value sendBeacon always uses

method

POST — always; there is no way to change it

keepalive

true — this is what lets the request outlive the page

credentials mode

include — cookies ride along, even cross-origin

initiator type

"beacon" — visible to DevTools and Resource Timing, not to page JS

mode

no-cors by default; switches to "cors" only for non-safelisted Content-Types

Content-Type

derived from the data argument, never set by hand

The keepalive flag is the load-bearing wall. The Fetch standard defines it as the marker that allows a request to outlive the environment settings object that created it — and when a fetch group is terminated, keepalive requests are explicitly exempt from cancellation. Every consequence in this series, from the 64 KiB quota to the flush-on-hidden guarantee, follows from that one flag.

Interactive Runnable example
Edit

Ready to run.

Quick check

sendBeacon just returned true. What do you actually know at that moment?

const queued = navigator.sendBeacon('/api/collect', payload);
// queued === true
// What is guaranteed?

Key takeaways

  • Telemetry emitted at page-dismissal time is the least reliable data in ordinary pipelines; sendBeacon exists specifically for it.
  • The API is one method: sendBeacon(url, data), POST-only, no response, returning a boolean.
  • The boolean means queued, not delivered — the spec's own words.
  • The request is a fixed-recipe fetch: POST, keepalive: true, credentials include, initiator "beacon", no-cors by default.
  • The W3C Beacon specification is its normative home — it is not part of the WHATWG HTML Standard.
Was this page helpful?

Mark this learning resource complete to track your learning progress.