[Proposal] Stateful Javascript Page Unload Beacon API

Summary

Developers frequently want to send ‘beacons’ for usage or performance data when users are done interacting with their site, but none of the existing techniques for doing this are reliable over all platforms, and can also cause performance issues.

We would like a add a new stateful beacon API inspired by the existing navigator.sendBeacon(), where the browser is in control of the exact time that the beacon is sent, rather than beacon sending being triggered by a JS call the developer makes. This both frees the developer from having to determine when and how to send their beacons, and allows for increased reliability.

Example usage

Developer creates a new PendingBeacon object with a target URL. From the moment of that object’s construction, the browser promises to at some point in the future send that pending beacon, even if the developer doesn’t interact with the beacon any further. The developer can, however, keep a reference to the PendingBeacon and populate it, perhaps repeatedly, with data as the user uses the page. Finally, on document unload (which may be at some arbitrary point in time due to BFCache), the beacon is sent by the browser with whichever data was attached to it.

6 Likes

We like this proposal, and would be excited to use it. It would allow us to report a single beacon containing all of the ad event information that would traditionally be sent using multiple beacons. This means less bandwidth and waking up the radio fewer times, an improvement in the end user’s web experience. One aspect of this proposal that is very important to us, however, is reliability: the beacon needs to be sent essentially all the time. Otherwise we would need to send some beacons directly in cases where we need our reporting to be as comprehensive as possible.

This would make a lot of finicky bits around sendBeacon() evaporate. I’m all for it.

Could this API expose an option for compressing the beacon data? One problem with sendBeacon() and fetch(…, { keepalive: true }) is errors when composing them with CompressionStream. It makes sense: they cannot wait around for any promises or callbacks because the whole point is that they can be sent while or after the browser tears down the JS execution context.

User-space compression with pako.js or similar is also unwise. Most compression libraries try very hard to do lazy computation via promises, callbacks, etc. You can find ones with synchronous compression, but eagerly blocking the main thread to compress data for APIs where their point is to delay work until it can’t interrupt the user… you can probably see the contradiction. (Something like lzutf8’s incremental .compressBlock() API used in very small frequent bursts seems like the only non-bad option.)

I don’t mind lacking control over compression other than true/false, because the savings for a user’s upload bandwidth with even the equivalent of gzip -1 are very worth it.

1 Like

Note that this will be discussed today on the WebPerfWG call - 8am PST. Please join us if you’re interested in this.