Technical
sendBeacon
Also called Navigator.sendBeacon.
sendBeacon is the browser method `navigator.sendBeacon(url, data)` that queues a small POST to go out in the background, even as the page unloads. Its return value says whether the browser queued it, not whether it arrived.
How it is measured
Call it and open the Network panel: type `ping` or `beacon`, method POST, and the page does not wait. The return value only reports acceptance into the queue, and pending beacons share a limit of about 64 KB.
Measure arrival on the server by comparing beacons sent per page load with beacons received, by browser. The body type matters: a Blob with `application/json` triggers a CORS preflight, while a plain string goes out as `text/plain` without one.
Worked example
A blog sends scroll depth on `pagehide` with a JSON string as the body. It goes out as `text/plain` and the server parses it fine, arriving on 96 of 100 test closes. A developer then switches to a Blob typed `application/json`. The cross-origin collector now needs a preflight, and arrivals fall to 58 of 100 on Safari.
Reverting to the string body and having the server parse `text/plain` restores 95 of 100.
How it differs
sendBeacon is the API call. A beacon is the kind of request it produces. `fetch` with `keepalive: true` also sends a beacon-style request. sendBeacon is limited to POST with no readable response, while fetch allows headers and reading the answer.
Common errors
Sending JSON as a Blob and triggering a preflight. Going past 64 KB. Calling it from `unload`. Reading the return value as proof of delivery. Expecting cookies on cross-origin calls without credentials mode. Firing it in a loop on every scroll event.
In practice
Send once at hide time with a string body, keep it small, and have the server accept `text/plain`. Compare beacons sent with beacons received for each browser. Use `fetch` with keepalive where you need custom headers.