Beacons are a way to send asynchronous pings to a server for the purposes such as logging and analytics. The API itself doesn’t give you a way to get notified when the ping has been successfully sent, which is intentional since the ping may be sent a while after the page has been closed or navigated away from. There are use cases where the web developer wants to send a ping to the server which is a candidate to use a beacon for, but they also need to know when/if the ping is delivered successfully, which makes beacons an unsuitable solution.
Service worker is a new technology that allows (among other things) intercepting the network requests made by the browser. It recently occurred to me that mixing these two technologies can solve the use case very well. The idea is to intercept the beacon fetch inside a service worker and then tell the web page about whether the beacon was successfully sent. I made a demo which shows how this can work. This demo works on Firefox Nightly if you toggle the
dom.serviceWorkers.enabled pref. It currently doesn’t work on Chrome, because it doesn’t allow a service worker to intercept the beacon, and I filed a bug about it.
Here is how this demo works: It registers a service worker as you would usually do, and then for sending the beacon, we create a new iframe to make sure the document where we call
sendBeacon is indeed intercepted by the service worker, and call
sendBeacon as usual in that iframe. Inside the service worker, we intercept the beacon. So at this point the beacon fetch has gotten to our service worker. My simple demo just sends a message to all controlled windows about this. A real service worker however would probably do a fetch on its own for sending the beacon to the network, wait for the returned promise to resolve, and then record a log of some sort such as in the DOM Cache, or send a message back to the controlled document.
It’s nice that service workers give you a way to delve into the guts of the platform and retrieve the information that interests you even if the rest of the platform hides that information! I hope this demo is useful to people who have this use case.