At Fiverr, we send anonymised metrics from the browser to our servers, using HTTP requests. We use the information we collect to verify that the behaviour of our application is correct, to monitor its quality and speed, to alert us on service degradation, and to improve the platform service quality through statistical analytics and research.
A brief introduction to sendBeacon function.
sendBeacon was created as a way to send [analytical] information back to the server, without expecting a response. This intention alone makes a substantial difference in considerations of behaviour, security, performance and prioritisation, and I’ll elaborate on this later on, but first I want to emphasise the significance of not expecting a response. When a browser expects a response from a web server, it assumes that the application will act upon that information. That’s why vendors have implemented some defence mechanisms in place, to protect the user. The sendBeacon API is not limited by the same constraints.
The Network panel showed below captured requests going to our monitoring services during the transition from XHR (XMLHttpRequest) to sendBeacon, described herein as “ ping ”. We can see both kinds of requests and the differences between them.
CORS dictates an elaborate protocol for sending data between domains (or subdomains). This includes a preflight OPTIONS request and omitting the cookie header.
You can see the preflight requests accompanying each XHR request in the Network panel. You can also see that the XHR requests omit the entire cookie header.
Given that analytics data are often sent to different subdomains or even different domains, dropping these restraints resulted in omitting the OPTIONS request and allowing relevant cookies to be sent.
Understanding that these requests do not affect user experience, the browser can now prioritise accordingly, allowing experience related requests to be executed and completed first.
You can see in the Network tab how these requests are prioritised differently.
Since these requests require no response, the browser will not abort them upon page unload, as it would for XHR or fetch requests. The Network tab includes one request with the status (unknown) and the time (unknown). This request was executed before navigation but was not aborted. The browser completed it in the background while the next page request was already being processed.
In the example displayed below, we send a cumulative metric from the lifespan of the page. We collect the information throughout the page’s lifecycle and send it when the page visibility changes to hidden. This event occurs when users change tabs — and, more crucially, before the page unloads while navigating away. This also means that you can send a beacon on navigation links with no race condition.
The following graph displays how rolling out this feature affected the number of cumulative metrics we were able to collect.
Since this request function does not accept a response, we have no way for the browser to know whether the request has failed on our servers. This is something you simply have to tolerate when switching to beacons. We will be able to tell if the transmission itself has succeeded by the function’s return value.
Although the sendBeacon specification does not define body size limitations, vendors may choose to limit the size of the request, in which case the sendBeacon function will return false for failing to transmit the data. Otherwise, it will return true.
If these limitations are too much to bear, the “fetch” function offers a “keepalive” flag, which allows the request to outlive the page.
In this last example, I added three listeners to a link navigating from the page; (1) regular fetch request, (2) fetch request with keepalive flag set to true, and (3) beacon (ping).
sendBeacon is made for sending analytical information over HTTP. Using the appropriate interface can improve the user experience on your site and increase the application visibility.