Atividade de registro com a API do Web Beacon
Publicados: 2022-03-10 A API Beacon é uma API Web baseada em JavaScript para enviar pequenas quantidades de dados do navegador para o servidor Web sem esperar por uma resposta. Neste artigo, veremos para que isso pode ser útil, o que o diferencia de técnicas familiares como XMLHTTPRequest
('Ajax') e como você pode começar a usá-lo.
Se você já sabe por que deseja usar o Beacon, sinta-se à vontade para pular diretamente para a seção Introdução.
Para que serve a API Beacon?
A API Beacon é usada para enviar pequenas quantidades de dados para um servidor sem esperar por uma resposta . Essa última parte é crítica e é a chave do motivo pelo qual o Beacon é tão útil – nosso código nunca consegue ver uma resposta, mesmo que o servidor envie uma. Beacons são especificamente para enviar dados e depois esquecê-los. Não esperamos uma resposta e não recebemos uma resposta.
Pense nisso como um cartão postal enviado para casa durante as férias. Você coloca uma pequena quantidade de dados nele (um pouco de “Gostaria de estar aqui” e “O tempo está ótimo”), coloca-o na caixa de correio e não espera uma resposta. Ninguém envia um cartão postal de retorno dizendo “Sim, eu gostaria de estar lá, muito obrigado!”
Para sites e aplicativos modernos, há vários casos de uso que se enquadram perfeitamente nesse padrão de enviar e esquecer.
Estatísticas de rastreamento e dados analíticos
O primeiro caso de uso que vem à mente da maioria das pessoas é a análise. Grandes soluções como o Google Analytics podem dar uma boa visão geral de coisas como visitas à página, mas e se quiséssemos algo mais personalizado? Poderíamos escrever algum JavaScript para rastrear o que está acontecendo em uma página (talvez como um usuário interage com um componente, até onde ele rolou ou quais artigos foram exibidos antes de seguir um CTA), mas precisamos enviar esses dados para o servidor quando o usuário sai da página. O Beacon é perfeito para isso, pois estamos apenas registrando os dados e não precisamos de uma resposta.
Não há motivo para não cobrirmos também o tipo de tarefas mundanas geralmente tratadas pelo Google Analytics, relatando o próprio usuário e a capacidade de seu dispositivo e navegador. Se o usuário tiver uma sessão logada, você pode até vincular essas estatísticas a um indivíduo conhecido. Quaisquer que sejam os dados coletados, você pode enviá-los de volta ao servidor com o Beacon.
Depuração e registro
Outro aplicativo útil para esse comportamento é registrar informações do seu código JavaScript. Imagine que você tenha um componente interativo complexo em sua página que funciona perfeitamente para todos os seus testes, mas ocasionalmente falha na produção. Você sabe que está falhando, mas não consegue ver o erro para começar a depurá-lo. Se você puder detectar uma falha no próprio código, poderá coletar diagnósticos e usar o Beacon para enviar tudo de volta para registro.
Na verdade, qualquer tarefa de registro pode ser realizada de maneira útil usando o Beacon, seja criando pontos de salvamento em um jogo, coletando informações sobre o uso de recursos ou registrando resultados de um teste multivariado. Se é algo que acontece no navegador que você deseja que o servidor saiba, então o Beacon é provavelmente um concorrente.
Já não podemos fazer isso?
Eu sei o que você está pensando. Nada disso é novo, não é? Conseguimos nos comunicar do navegador para o servidor usando XMLHTTPRequest
há mais de uma década. Mais recentemente, também temos a API Fetch, que faz a mesma coisa com uma interface mais moderna baseada em promessas. Dado isso, por que precisamos da API Beacon?
A chave aqui é que, como não obtemos uma resposta, o navegador pode enfileirar a solicitação e enviá-la sem bloquear a execução de qualquer outro código. No que diz respeito ao navegador, não importa se nosso código ainda está em execução ou não, ou onde a execução do script deve chegar, pois não há nada para retornar, ele pode apenas enviar o pedido HTTP em segundo plano até que seja conveniente Envie isto.
Isso pode significar esperar até que a carga da CPU seja menor, ou até que a rede esteja livre, ou até mesmo enviá-la imediatamente, se puder. O importante é que o navegador enfileira o beacon e retorna o controle imediatamente. Ele não segura as coisas enquanto o sinalizador envia.
Para entender por que isso é importante, precisamos ver como e quando esses tipos de solicitações são emitidas a partir de nosso código. Veja nosso exemplo de um script de log de análise. Nosso código pode estar cronometrando quanto tempo os usuários passam em uma página, então torna-se crítico que os dados sejam enviados de volta ao servidor no último momento possível. Quando o usuário sai de uma página, queremos parar o tempo e enviar os dados de volta para casa.
Normalmente, você usaria o evento unload
ou beforeunload
para executar o registro. Eles são acionados quando o usuário faz algo como seguir um link na página para navegar. O problema aqui é que o código executado em um dos eventos de unload
pode bloquear a execução e atrasar o descarregamento da página. Se o descarregamento da página estiver atrasado, o carregamento da próxima página também estará atrasado e, portanto, a experiência parecerá muito lenta.
Lembre-se de como as solicitações HTTP podem ser lentas. Se você está pensando em desempenho, normalmente um dos principais fatores que você tenta reduzir são as solicitações HTTP extras, porque ir para a rede e obter uma resposta pode ser muito lento. A última coisa que você quer fazer é colocar essa lentidão entre a ativação de um link e o início da solicitação para a próxima página.

O Beacon contorna isso enfileirando a solicitação sem bloquear, devolvendo o controle imediatamente ao seu script. O navegador então se encarrega de enviar essa solicitação em segundo plano sem bloquear. Isso torna tudo muito mais rápido, o que deixa os usuários mais felizes e nos permite manter nossos empregos.
Começando
Então, entendemos o que é Beacon e por que podemos usá-lo, então vamos começar com algum código. O básico não poderia ser mais simples:
let result = navigator.sendBeacon(url, data);
O resultado é booleano, true
se o navegador aceitar e enfileirar a solicitação e false
se houver algum problema ao fazê-lo.
Usando navigator.sendBeacon()
navigator.sendBeacon
recebe dois parâmetros. O primeiro é o URL para o qual fazer a solicitação. A solicitação é realizada como HTTP POST, enviando todos os dados fornecidos no segundo parâmetro.
O parâmetro de dados pode estar em um dos vários formatos, todos eles obtidos diretamente da API Fetch. Isso pode ser um Blob
, um BufferSource
, FormData
ou URLSearchParams
— basicamente qualquer um dos tipos de corpo usados ao fazer uma solicitação com Fetch.
Eu gosto de usar FormData
para dados básicos de valor-chave, pois é descomplicado e fácil de ler.
// URL to send the data to let url = '/api/my-endpoint'; // Create a new FormData and add a key/value pair let data = new FormData(); data.append('hello', 'world'); let result = navigator.sendBeacon(url, data); if (result) { console.log('Successfully queued!'); } else { console.log('Failure.'); }
Suporte ao navegador
O suporte em navegadores para Beacon é muito bom, com as únicas exceções notáveis sendo o Internet Explorer (funciona no Edge) e o Opera Mini. Para a maioria dos usos, tudo bem, mas vale a pena testar o suporte antes de tentar usar navigator.sendBeacon
.
Isso é fácil de fazer:
if (navigator.sendBeacon) { // Beacon code } else { // No Beacon. Maybe fall back to XHR? }
Se o Beacon não estiver disponível e sua solicitação for importante, você poderá recorrer a um método de bloqueio, como XHR. Dependendo do seu público e propósito, você também pode optar por não se incomodar.
Um exemplo: tempo de registro em uma página
Para ver isso na prática, vamos criar um sistema básico para cronometrar quanto tempo um usuário permanece em uma página. Quando a página for carregada, anotaremos a hora e, quando o usuário sair da página, enviaremos a hora de início e a hora atual para o servidor.
Como nos preocupamos apenas com o tempo gasto (não com a hora real do dia), podemos usar performance.now()
para obter um timestamp básico conforme a página carrega:
let startTime = performance.now();
Se encerrarmos nosso login em uma função, podemos chamá-la quando a página for descarregada.
let logVisit = function() { // Test that we have support if (!navigator.sendBeacon) return true; // URL to send the data to, eg let url = '/api/log-visit'; // Data to send let data = new FormData(); data.append('start', startTime); data.append('end', performance.now()); data.append('url', document.URL); // Let's go! navigator.sendBeacon(url, data); };
Por fim, precisamos chamar essa função quando o usuário sair da página. Meu primeiro instinto foi usar o evento unload
, mas o Safari em um Mac parece bloquear a solicitação com um aviso de segurança, então beforeunload
funciona bem para nós aqui.
window.addEventListener('beforeunload', logVisit);
Quando a página descarregar (ou, pouco antes disso) nossa função logVisit()
será chamada e desde que o navegador suporte a API Beacon nosso beacon será enviado.
(Observe que, se não houver suporte a Beacon, retornaremos true
e fingiremos que tudo funcionou bem. Retornar false
cancelaria o evento e interromperia o descarregamento da página. Isso seria lamentável.)
Considerações ao rastrear
Como muitos dos usos potenciais do Beacon giram em torno do rastreamento de atividades, acho que seria negligente não mencionar as responsabilidades sociais e legais que temos como desenvolvedores ao registrar e rastrear atividades que podem ser vinculadas aos usuários.
GDPR
Podemos pensar nas recentes leis europeias do GDPR relacionadas ao e-mail, mas é claro que a legislação se refere ao armazenamento de qualquer tipo de dados pessoais. Se você souber quem são seus usuários e puder identificar suas sessões, verifique qual atividade está registrando e como ela se relaciona com suas políticas declaradas.
Muitas vezes, não precisamos rastrear tantos dados quanto nossos instintos, como os desenvolvedores nos dizem que deveríamos. Pode ser melhor não armazenar deliberadamente informações que identifiquem um usuário e, assim, reduzir a probabilidade de errar.
DNT: Não rastrear
Além dos requisitos legais, a maioria dos navegadores tem uma configuração para permitir que o usuário expresse o desejo de não ser rastreado. Do Not Track envia um cabeçalho HTTP com a solicitação que se parece com isso:
DNT: 1
Se você estiver registrando dados que podem rastrear um usuário específico e o usuário enviar um cabeçalho DNT
positivo, seria melhor seguir os desejos do usuário e anonimizar esses dados ou não rastreá-los.
Em PHP, por exemplo, você pode facilmente testar este cabeçalho assim:
if (!empty($_SERVER['HTTP_DNT'])) { // User does not wish to be tracked ... }
Para concluir
A API Beacon é uma maneira muito útil de enviar dados de uma página de volta ao servidor, principalmente em um contexto de log. O suporte ao navegador é muito amplo e permite que você registre dados sem afetar negativamente a experiência de navegação do usuário e o desempenho do seu site. A natureza sem bloqueio das solicitações significa que o desempenho é muito mais rápido do que alternativas como XHR e Fetch.
Se você quiser ler mais sobre a API Beacon, vale a pena dar uma olhada nos seguintes sites.
- “Especificação do W3C Beacon”, Recomendação do Candidato W3C
- “Documentação do MDN Beacon”, documentos da web MDN, Mozilla
- “Informações de suporte do navegador”, caniuse.com