Logging of activity using Web Beacon API

Original author: Drew McLellan
  • Transfer
  • Tutorial


The Beacon API is a JavaScript-based interface for:


sending a small amount of data to the server from a browser, without waiting for a response. In this article, we will look at when the Beacon API will be useful, how it differs from using XMLHTTPRequest(Ajax) for the same purposes and how to use it.


Why do we need another API?


The Beacon API is used to send small data to the server without waiting for a response . The last part of the statement is the most interesting. The Beacon API is designed specifically to send and forget data. No need to expect an answer, as it will not be.


Metaphor with cards, these are the cards that people send / send to each other. As a rule, they wrote a small text on them (“Where are you? And I am lol on the sea.”, “I have great weather here, not like in your office”), they threw me into the mail and forgot it. Nobody expected an answer like "I already left for you," "My office is wonderful."


There are many cases in which the “sent and forgot” approach is appropriate.


Statistics Tracking and Analytical Information


This is the first thing that comes to mind. Big solutions like Google Analytics can provide a good overview of basic things. But if we want something more customized? We need to write some code to keep track of what is happening on the page (how users interact with the components, how far they scroll, which pages were displayed before the first sale), then send this data to the server when the user leaves the page. Beacon is ideally suited for this task, since we simply send the data, and we don’t need a response from the server.


Debag and Logging


Another use is to log information from JavaScript code. Imagine the situation when you have a big application with rich UI / UX. All tests are green, and an error periodically pops up on the sale of which you know, but you cannot prod it because of a lack of information. In this case, you can use Beacon for diagnostics.


In fact, any logging problem can be solved using Beacon. This could be the creation of save points in games, the collection of information about the use of new functionality, the recording of test results, and so on. If this is something that happens in the browser and you want the server to know about it, Beacon is what you need.


Have we not done this before?


I know what you're thinking. None of this is new? We communicate with the north through XMLHTTPRequest for more than 10 years. We recently started using the Fetch API, which in fact does the same thing, just with the new Promise interface. So why do we need another Beacon API?


The key feature is that we do not need a response from the server. The browser can queue the request and send data without blocking the execution of any code. Since the browser is loaded into it, for us it doesn’t matter whether the code is still running or not, the browser will just send itself quietly requests in the background.


C Beacon API does not need to wait for the best moment for the CPU, network. Just adding a request to the queue using beacon is practically worthless.


In order to understand why this is important, it is enough to look at how and where such logic is usually used. For example, in order to measure how long a user is on a page, we need to send a request to the server as close as possible to the end of the session.


This is usually done on unloador beforeunload. Such code can block the execution, and if a page is delayed, then the next page is also delayed. This leads to not the best UX.


You understand how HTTP requests are slow? And the last thing you want is to cram an HTTP request between hops.


We try Beacon API


The basic usage example is very simple:


let result = navigator.sendBeacon(url, data);

resultboolean value If the browser has added a request to the queue - trueif not false.


Using navigator.sendBeacon ()


navigator.sendBeacontakes two parameters. The first is the URL to which the request will be sent, the second is the data to be sent. The request has the form HTTP POST.


data- this parameter can accept several data formats, all those with which the Fetch API works. This can be Blob, BufferSource, FormData or URLSearchParams, etc.


I like to use FormData for simple key-value data, this is not a complicated and easy-to-use class.


// URL куда отправить данныеlet url = '/api/my-endpoint';
// Создание нового FormDatalet data = new FormData();
data.append('hello', 'world');
let result = navigator.sendBeacon(url, data);
if (result) { 
  console.log('Добавлено в очередь!');
} else {
  console.log('Ошибка.');
}

Browser Support


Support for this API is quite solid. The only browser that does not support is Internet Explorer (I did not expect this) and Opera Mini. But in the Edge everything works. In most cases, there is support, but it's better to check just in case:


if (navigator.sendBeacon) {
  // Beacon код
} else {
  // Использовать XHR?
}

Example: log time spent on the page


In order to see the whole thing in practice, let's create a simple system of counting the time that the user is on the page. When the page loads, we look at the time and when it leaves, we send a request from the time it started viewing and the current to the server.


Since we are only interested in the time spent on the page, and not the present time, we can use performance.now()to get the base timestamp when loading the page:


let startTime = performance.now();

Let's wrap a small piece of logic in an easy-to-use feature:


let logVisit = function() {
  // Test that we have supportif (!navigator.sendBeacon) returntrue;
  // URL to send the data to, e.g.let url = '/api/log-visit';
  // Data to sendlet data = new FormData();
  data.append('start', startTime);
  data.append('end', performance.now());
  data.append('url', document.URL);
  // Let's go!
  navigator.sendBeacon(url, data);
};

Finally, we need to call this function when the user leaves the page. The first thought was to use unload, but Safari on Mac seems to be blocking the request for security reasons. For this it is better to use beforeunload:


window.addEventListener('beforeunload', logVisit);

When the page is unloaded (or before it), our function logVisit()will be called and if the browser supports the Beacon API, send a request to the server.


Couple of moments


Since most of the problems for the solution of which the Beacon API will be used, revolve around activity tracking, it will be important to note the social and legal part of this whole kitchen.


GDPR


Just remember about him.


DNT: DO NOT TRACK


In addition, browsers have an option that allows users to designate that they do not want their activity to be monitored. Do Not Tracksends an HTTP header that looks like this:


DNT: 1

If you are tracking data that may indicate a user and there are requests in the headers DNT: 1, then it is better to listen to the user and not save any data. For example using PHP this can be verified as follows:


if (!empty($_SERVER['HTTP_DNT'])) { 
  // Не хочу, не надо
}

Finally


Beacon API is really a very convenient way to send data to the server, especially in the context of logging. Browser support is at a fairly good level and allows you to easily log any information without any negative consequences for the performance and responsiveness of your UI. The non-blocking nature of these queries plays a very good role in this, it is much faster than alternatives to XHR and Fetch.



Also popular now: