- O Bear Blog implementou um sistema próprio de analytics que funciona sem JavaScript no cliente, por restrições de velocidade, eficiência e estabilidade
- Scripts de analytics comuns podem ser bloqueados por ad blockers, e só logs de servidor podem misturar crawlers, scrapers e até parsers baseados em GPT, distorcendo as estatísticas de visita
- No CSS de cada página, quando
body:hover ocorre, border-image chama o endpoint /hit/{{ post.id }}/, usando hover ou rolagem no celular como sinal de leitura
- O servidor verifica pelo user-agent se é bot, navegador e plataforma, e usa o endereço IP apenas para determinar o país, removendo leituras duplicadas com um hash de IP+data
- Se a leitura vier do mesmo IP no mesmo dia, mesmo em vários dispositivos, conta como uma vez, mas ainda permite contabilizar de forma simples o número de leituras únicas por página sem armazenar informações identificáveis
Criando um evento de leitura com CSS hover
- O sistema de analytics do Bear Blog segue a restrição de não usar JavaScript no cliente
- Ferramentas de analytics comuns conseguem julgar em parte a autenticidade do tráfego ou se é bot com JavaScript no cliente, mas muitos ad blockers bloqueiam não só o Google Analytics como também scripts de analytics como Fathom e Plausible
- Só analisar logs do servidor pode misturar crawlers de mecanismos de busca, scrapers e parsers baseados em GPT como se fossem tráfego normal, gerando uma visão distorcida
- O Bear insere o CSS abaixo em cada página para que
body:hover aconteça quando o usuário passa o cursor sobre a página ou faz rolagem no celular
body:hover {
border-image: url("/hit/{{ post.id }}/?ref={{ request.META.HTTP_REFERER }}");
}
- Quando
body:hover é acionado, a URL de hit daquele post é chamada
- A informação explicitamente adicionada de novo nessa requisição é o referrer, e a grafia
HTTP_REFERER é uma forma com erro ortográfico que acabou permanecendo como padrão
- Partindo do princípio de que bots não fazem hover, o Bear usa a chamada baseada em
body:hover como sinal de leitor humano
- Depois, no servidor, verifica se o user-agent é de bot e extrai navegador e plataforma da string de user-agent
Removendo leituras duplicadas sem informações de identificação
- A segunda restrição é não armazenar no cookie do navegador nem no servidor informações que possam identificar o leitor
- O endereço IP é usado apenas para determinar o país e, antes de ser armazenado, é hasheado junto com a data
- Requisições posteriores para a mesma página são comparadas com o hash de
endereço IP + data e descartadas se forem duplicadas
- Nesse modelo, ao longo de um dia, um endereço IP conta como uma única leitura para uma página
- O IP original não é armazenado, e o hash com a data tem efeito de expiração diária
user_agent = httpagentparser.detect(self.request.META.get('HTTP_USER_AGENT', None))
if user_agent.get('bot', False):
print('Bot traffic')
return
ip_hash = hashlib.md5(f"{client_ip(self.request)}-{timezone.now().date()}".encode('utf-8')).hexdigest()
country = get_user_location(client_ip(self.request)).get('country_name', '')
device = user_agent.get('platform', {}).get('name', '')
browser = user_agent.get('browser', {}).get('name', '')
referrer = self.request.GET.get('ref', '')
if referrer:
referrer = urlparse(referrer)
referrer = '{uri.scheme}://{uri.netloc}/'.format(uri=referrer)
Hit.objects.get_or_create(
post_id=self.pk,
ip_address=ip_hash,
referrer=referrer,
country=country,
device=device,
browser=browser)
- O hash do IP é usado apenas para impedir hits duplicados ao longo do dia, enquanto cada visualização de página é tratada como única por padrão
- No fim de cada dia, uma tarefa em segundo plano apaga o hash dos logs de hit para evitar conflito com interpretações excessivamente rígidas da GDPR
- Uma desvantagem desse método é que, se vários dispositivos lerem no mesmo dia a partir do mesmo IP, isso ainda conta como uma única leitura
- O Bear considera que esses casos são uma pequena parte do tráfego e vê a abordagem baseada em CSS como mais enxuta, simples e capaz de fornecer uma contagem de leituras mais precisa do que vários outros métodos de coleta de analytics
1 comentários
Opiniões no Hacker News
Sou o autor. O hash do endereço IP serve, neste contexto, apenas para impedir visualizações duplicadas no mesmo dia
Ele existe para tornar cada visualização de página basicamente única, e, ao fim de cada dia, uma tarefa de worker limpa o hash enquanto mantém as informações de visualização. Também adicionei uma alteração ao texto para deixar isso claro
Quando vi pela primeira vez a ideia de usar requisições geradas por CSS para analytics, achei realmente incrível
Alguém no Twitter colocou uma grade de retângulos invisíveis sobre a página e a usou para rastreamento do mouse, fazendo com que cada célula carregasse uma imagem de fundo única ao receber hover. Cada imagem de fundo enviava uma requisição específica ao servidor, que então a interpretava
Por diversão, em um verão, expandi essa ideia e criei um “chat web assíncrono só com CSS”, sem JavaScript: https://github.com/kkuchta/css-only-chat
Dizer que anonimiza endereços IP fazendo hash apenas da data e do IP é só teatro de segurança
Hashes criptográficos são projetados para serem calculados rapidamente. Com hashcat, em um MacBook M1 Pro, dá para calcular 6 bilhões de hashes MD5 por segundo, e há apenas 4 bilhões de endereços IPv4. Dá para fazer força bruta em todo o espaço e descobrir os endereços IP, o que na prática equivale a reverter o hash
O mesmo vale mesmo que se use um hash seguro, como SHA-256, em vez do MD5 quebrado
Mesmo que você faça hash do nome completo de alguém, ainda é possível responder depois à pergunta “este hash corresponde a este nome completo específico?”. O fato de ser possível responder a essa pergunta significa que o processo de anonimização é reversível
O hash do endereço IP serve, neste contexto, apenas para impedir visualizações duplicadas no mesmo dia. Ele existe para tornar cada visualização de página basicamente única, e, ao fim de cada dia, uma tarefa de worker remove o hash de IP que já não é mais necessário
[0] https://news.ycombinator.com/item?id=37596757
Se o salt será armazenado permanentemente ou trocado periodicamente é apenas detalhe de implementação; o ponto central ao adicionar salt a hashes para analytics é que o salt nunca sai do cliente
Pela descrição do texto, parece não haver salt. Ou talvez a data atual esteja sendo usada como se fosse um salt, mas isso não é um salt aleatório, então qualquer pessoa que queira saber “o IP x.y.z.w visitou na data aa-mm-dd?” consegue adivinhar facilmente
Do ponto de vista de um atacante, é fácil avaliar esse tipo de problema. Com os dados fornecidos, como eu faria para descobrir algo sobre uma pessoa específica? Se eu não conseguir, então provavelmente esses dados podem ser armazenados de modo geral sem grandes problemas
Porém me preocupa que só esse tipo de teatro de segurança já possa ser suficiente para passar por várias leis e regulações de privacidade
Embora pareça engenhoso,
body:hoverprovavelmente deixa passar quase completamente usuários que usam apenas teclado e agentes de usuário sem dispositivo apontador, ou seja, usuários de tecnologias assistivasMesmo que esses grupos possam ser periféricos, ver qualquer forma de exclusão deles é sempre um sinal muito ruim
Não sei se existe, só com CSS básico, uma forma 100% confiável de detectar em todos os agentes de usuário que “uma pessoa real está lendo este artigo” e enviar uma requisição HTTP; também desconfio que não. Alguns podem nem oferecer suporte a CSS ou podem ter desativado o carregamento de imagens decorativas via CSS
Um seletor moderno que poderia ajudar é
:root:focus-within, mas o usuário precisa de fato focar um elemento interativo, e nem todo agente de usuário garante isso. O moderníssimo@scroll-timeline, para animações vinculadas à rolagem, também poderia funcionar, mas leitores de braille ainda provavelmente ficariam de fora:hover, ou seja, mais de 50% dos agentes de usuário? Claro, no caso de não haver um mouse conectadoEssa área é a largura que inclui a coluna de conteúdo e 20px de padding de cada lado. Então alguns usuários de teclado são capturados, enquanto alguns usuários de mouse, especialmente os que usam viewports grandes, não são
A ideia de que “não só coisas ruins como o Google Analytics, mas também Fathom e Plausible têm dificuldade para registrar atividade em navegadores com bloqueio de anúncios” ocorre, a meu ver, porque eles estão tentando viver, na prática, em um terreno baldio tóxico.
Usuários como nós já se cansaram desse conceito inteiro, então acho que, se a análise via CSS se popularizar, também surgirão tentativas de contorná-la.
Eu desbloqueei manualmente Piwik/Matomo, Plausible e Fathom no uBlock. Não vejo dano no que eles rastreiam nem em como rastreiam. E eles dão aos operadores de sites informações úteis para “melhorar o serviço”.
Por exemplo, o Plausible coleta menos informações sobre mim do que logs comuns do nginx ou do Apache. Do ponto de vista de um blogueiro, é importante ver se um texto chegou ao HN, se foi linkado em algum lugar, que conteúdo é recebido como valioso e qual é ignorado. Assim dá para escrever o que as pessoas realmente querem ler e divulgar pelos canais em que isso pode de fato ser percebido.
access.logdo servidor web em um serviço de analytics não impede nada.Pelo contrário, como é praticamente impossível filtrar todo o tráfego de bots olhando apenas para o user agent, os números podem acabar inflados.
Não sei quantas pessoas de fato temem isso. Imagino reações indo de “sim, é assustador” até “que absurdo, isso é só ficção científica”.
Isso é conhecido há décadas como pixel de rastreamento.
:hoverpermite filtrar bots que não usam um WebDriver completo, ou seja, a maioria dos bots.Em certo sentido, talvez fosse melhor carregar via
@import, comsupports, um arquivo.cssquase vazio. Bloqueadores de anúncios detectam muito bem pixels transparentes de rastreamento de 1px, mas talvez sejam menos propensos a bloquear arquivos.csspara não quebrar o layout. Só que, nesse caso, a vantagem inteligente do:hoverdesaparece.É uma pergunta genuína, mas tenho receio de que soe como um comentário desdenhoso: qual é o objetivo de coletar dados de analytics em um blog pessoal não comercial como o Bearblog parece ser?
O principal motivo para se interessar por analytics é ver se os textos estão sendo lidos. Superficialmente, e em certo sentido, é por vaidade, mas na prática tem a ver com a conexão entre autor e leitor. Tenho curiosidade genuína sobre aquilo a que os leitores reagem e quero entregar mais disso. Esse “disso” pode ser o tema, o tom ou a extensão. Ajuda a ajustar o material ao meu público. No fim, posso escrever sobre uma dúzia de assuntos de vinte e quatro maneiras diferentes. Claro que escrevo sobre o que gosto, mas lapido para ressoar melhor com os leitores.
Nesse sentido, analytics também é uma forma de conhecer os leitores. Em blogs com alto engajamento, a análise me dava algo como um retrato difuso dos leitores. Eu podia ver não só do que gostavam, mas também quando gostavam. Dava para saber se liam logo pela manhã, no horário do almoço ou tarde da noite, e isso ajudava a decidir publicar em certos horários, ou a ter mais confiança nessa decisão. Claro que eram todas informações imprecisas, mas ajudavam muito a me conectar de forma mais ativa com os leitores.
Claro que pode ser usado para publicidade e pode ser abusado, mas, se eu quero feedback sobre o que estou fazendo, é essencial.
Se 12 ou 12.000 pessoas leem o site, isso pode não ter valor monetário. Mas, do ponto de vista pessoal, é bom saber o que as pessoas querem ler vindo de mim, dá para sentir que o tempo gasto escrevendo foi bem aproveitado e, se eu quiser, posso ajustar na direção do que é mais popular.
Mesmo um blogueiro pessoal pode querer ajustar o conteúdo aos leitores. É bom saber que 500 pessoas leram um texto sobre um tema e só 3 leram outro.
Tentei fazer algo assim no começo deste ano, mas perdi a motivação enquanto criava a UI web. Minha abordagem não era CSS; era simplesmente carregar imagens falsas por meio de tags.
https://github.com/nolytics
Por que não obter essas informações diretamente do servidor HTTP?
“Sempre existe a opção de analisar logs do servidor, e isso permite ter uma noção aproximada dos tipos de tráfego que acessam o servidor. Mas, em geral, todo tráfego de servidor parece igual. Tecnicamente, bots deveriam ter um user agent que os identifica como bots, mas, como tentam coletar informações fingindo ser uma ‘pessoa’ usando um navegador, quase nunca se identificam assim. Essencialmente, se você usar apenas logs de servidor para analytics, vai ter uma visão distorcida do tráfego por causa de crawlers de mecanismos de busca, scrapers e, agora, parsers baseados em GPT.”
Como os dados de analytics são armazenados?
Imagine que você tem um site de e-commerce e produtos que quer vender. Além de analytics, decidiu registrar diretamente em logs algumas ações, como visitas à página de detalhes de um produto estando logado. Então você quer armazenar coisas como ID do usuário, ID do produto e timestamp
Na prática, como isso deve ser armazenado? De forma ingênua, achei que bastava colocar em uma tabela. O DBA perguntou por quanto tempo os dados seriam necessários, e respondi que pelo menos um mês. Ele disse tudo bem, e provavelmente agendou um job para mover dados mais antigos para outra tabela
Na prática, como esses logs são armazenados e por quanto tempo são mantidos?
Já fiz isso antes e, até chegar a algo em torno de 1 bilhão de linhas, nem precisei pensar em particionamento. Ainda assim, é melhor particionar antes disso. Essa experiência não foi agradável
Eles fazem agregações muito mais rapidamente e também lidam bem com muitas colunas esparsas. Por exemplo, um evento
paidtem o atributoamount, enquanto um eventopage_viewtem o atributourlO ponto bom do TimescaleDB é que ele cuida da criação de views materializadas para agregações de interesse, como visualizações de produtos por hora. Se houver muitos eventos e você quiser evitar que o banco de dados cresça demais, também pode optar por “descartar” os eventos em si e manter apenas as agregações