The Wonderful Tale of sendBeacon

When we proposed to do this workshop, about 6 months ago, we had a lovely laundry list of things we'd like to cover. We wanted to teach y'all folks about all the emerging application development techniques. Among those things was network priorization.

Networking in the browser is different from on servers. Because browsers are sandboxed VMs that need to run untrusted code, for security reasons networking is rather restricted. And with these restrictions come constraints — browser networking can feel rather "high level" or "indirect" depending on your perspective.

Take a browser, and a server. The browser wants to show a page, and needs to request some resources. It'll fire a request for /index.html first, parse the HTML, and then fire more requests to get subsequent resources from the same host.

Now it's good to remember that throughput on any given device is going to be limited. There can only flow so much data through a single tube. This means we need to prioritize what comes first.

This is the murky grounds of network prioritization, where the best possible tool will be to try out stuff, and create intuition.

So in terms of hierarchy, loading .html files, or files linked from within the <head> is usually the highest priority. There's special attributes such as rel="preload" that lower that priority, but it not the default.

Enter sendBeacon API — this is an API that makes request with the lowest priority possible. Preloading something? Yep, more important than a beacon. Performing a fetch() yep; beacon will wait.

sendBeacon was meant for one thing, and one thing only: to guarantee sending analytics data to servers, without affecting performance. sendBeacon allows scheduling a request — if the scheduler returns true, the browser will send off the request in the background, whenever the network is available.

Exercise 1

Cool! Now you have a basic hook that can send data to a server. However, in a heavily populated environment, it will cause a good amount of slowdown. Let's pull out the sendBeacon API.

Exercise 2


Idealy we could send JSON down as text/json, but due to a Chrome CORS bug, it's been temporarily disabled. Given that Chrome is widely used, it's probably worth sending data down as text/plain for the time being, and not relying on CORS checks. Not great, but there's no other way.

Something to worry about is that the sendBeacon API can only send up to 65536 bytes. If the number is higher than that, it might reject it — in this case it's best to assert() that the size is lower. If the size is larger than that, there's been a programmer error, and it should be explicit why things can fail.

Also not all browsers may support the sendBeacon API; we should feature detect it and fall back if it doesn't exist.

Exercise 3

Now the final cherry on the sendBeacon cake, is to respect doNotTrack. Caring about privacy means, we should respect people's wishes.

Wrapping up

And that's it! — you now know the ins and outs of navigator.sendBeacon. Google Analytics has a beacon: true flag you can toggle to send things down, and some other providers are working on integrating it. You can be ahead of the pack, and do a better job — today.

If you want to use a module out of the box that does all of this for you, check out nanobeacon. Swooosh.

Edit on GitHub Status: offline