Skip to main content

navigator.sendBeacon

navigator.sendBeacon sends a small HTTP POST request reliably during page unload. The browser guarantees delivery without blocking navigation — making it ideal for fire-and-forget data like analytics pings.

Browser support: Widely available across all modern browsers.

Use cases

  • Analytics pings (page views, click tracking)
  • Diagnostics and error reporting
  • Session-end data (time on page, scroll depth)

Example

The modern best practice is to send beacons on visibilitychange instead of unload (which is unreliable on mobile):

document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
const data = JSON.stringify({ event: "session_end", duration: 42000 });
navigator.sendBeacon("/analytics", new Blob([data], { type: "application/json" }));
}
});

Comparison with fetch + keepalive

You can achieve similar reliability with fetch, plus gain more control:

document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
fetch("/analytics", {
method: "POST",
body: JSON.stringify({ event: "session_end", duration: 42000 }),
headers: { "Content-Type": "application/json", "X-Custom": "value" },
keepalive: true,
priority: "low",
});
}
});
FeaturesendBeaconfetch + keepalive
Custom headersNo (Content-Type inferred from body)Yes
Response accessNoYes
Priority controlNoYes (priority option)
SimplicityOne-linerMore verbose
HTTP methodsPOST onlyAny

When to use which

Use sendBeacon for simple fire-and-forget POST requests — typically analytics or diagnostics. Prefer fetch with keepalive: true and priority: "low" when you need custom headers, response access, priority control, or a method other than POST.

Limitations

  • 64 KiB payload cap — shared quota across all in-flight keepalive requests (both sendBeacon and fetch + keepalive)
  • POST only — no other HTTP methods
  • No access to the response body
  • No custom headers beyond what the body type implies for Content-Type