- Bear Blog a implémenté son propre système d’analytics, qui fonctionne sans JavaScript côté client, en raison de contraintes de vitesse, d’efficacité et de stabilité
- Les scripts d’analytics classiques peuvent être bloqués par les bloqueurs de publicité, et les seuls logs serveur peuvent mélanger crawlers, scrapers et parseurs basés sur GPT, ce qui peut fausser les statistiques de visite
- Quand
body:hover se produit dans le CSS de chaque page, border-image appelle l’endpoint /hit/{{ post.id }}/, utilisant le survol ou le scroll mobile comme signal de lecture
- Le serveur vérifie via le user-agent s’il s’agit d’un bot, ainsi que le navigateur et la plateforme ; l’adresse IP ne sert qu’à déterminer le pays, puis un hash IP+date supprime les lectures en double
- Si plusieurs appareils lisent depuis la même IP le même jour, cela compte pour une seule fois, mais cela permet d’agréger simplement le nombre de lectures uniques par page sans stocker d’informations d’identification
Créer un événement de lecture avec CSS hover
- Le système d’analytics de Bear Blog respecte la contrainte de ne pas utiliser de JavaScript côté client
- Les outils d’analytics classiques peuvent, via JavaScript côté client, évaluer en partie l’authenticité du trafic ou la présence de bots, mais de nombreux bloqueurs de publicité bloquent non seulement Google Analytics, mais aussi des scripts d’analytics comme Fathom ou Plausible
- Se contenter de parser les logs serveur peut mélanger les crawlers de moteurs de recherche, les scrapers et les parseurs basés sur GPT au trafic ordinaire, créant une vision biaisée
- Bear insère le CSS suivant dans chaque page afin que
body:hover se déclenche lorsque l’utilisateur place le curseur sur la page ou fait défiler sur mobile
body:hover {
border-image: url("/hit/{{ post.id }}/?ref={{ request.META.HTTP_REFERER }}");
}
- Quand
body:hover est déclenché, l’URL de hit de l’article concerné est appelée
- L’information explicitement ajoutée à nouveau dans cette requête est le referrer, et l’orthographe
HTTP_REFERER est une faute d’orthographe restée comme une forme standard
- En exploitant le fait que les bots ne survolent pas la page, l’appel basé sur
body:hover sert de signal de lecteur humain
- Ensuite, le serveur vérifie si le user-agent est un bot et extrait le navigateur et la plateforme depuis la chaîne user-agent
Supprimer les lectures en double sans informations d’identification
- La deuxième contrainte consiste à ne pas stocker, dans les cookies du navigateur ni sur le serveur, d’informations permettant d’identifier le lecteur
- L’adresse IP n’est utilisée que pour déterminer le pays et, avant stockage, l’adresse IP et la date sont hashées ensemble
- Les requêtes ultérieures vers la même page sont comparées au hash
adresse IP + date et rejetées s’il s’agit de doublons
- Avec cette méthode, une adresse IP compte pour un seul read par page sur une journée
- L’adresse IP brute n’est pas stockée, et le hash incluant la date produit un effet d’expiration à la journée
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)
- Le hash IP ne sert qu’à empêcher les hits en double pendant une journée, et toutes les consultations de pages sont par défaut traitées comme uniques
- À la fin de chaque journée, une tâche en arrière-plan supprime les hashes des logs de hits afin d’éviter tout conflit avec une interprétation excessivement stricte du RGPD
- Le fait que plusieurs appareils lisant depuis la même adresse IP le même jour ne soient comptés que comme un seul read constitue une limite de cette approche
- Bear estime que ces cas ne représentent qu’une petite partie du trafic, et considère que l’approche basée sur CSS fournit un nombre de lectures plus concis, plus simple et plus exact que de nombreuses méthodes de collecte d’analytics
1 commentaires
Avis sur Hacker News
Je suis l’auteur. Le hachage de l’adresse IP, dans ce contexte, sert uniquement à éviter les vues en double au cours d’une même journée.
Il sert à rendre chaque vue de page unique par défaut, et à la fin de chaque journée une tâche worker vide le hachage tout en conservant les informations de consultation. J’ai ajouté une modification à l’article pour le préciser.
Quand j’ai vu pour la première fois l’idée d’utiliser des requêtes déclenchées par CSS pour l’analytics, j’ai trouvé ça vraiment brillant.
Quelqu’un sur Twitter avait superposé à une page une grille de rectangles invisibles et, au survol de chaque cellule, une image de fond unique se chargeait pour faire du suivi de la souris. Chaque image de fond envoyait une requête spécifique au serveur, que celui-ci interprétait ensuite.
Pour m’amuser, un été, j’ai poussé cette idée plus loin en créant un « chat web asynchrone uniquement en CSS », sans JavaScript : https://github.com/kkuchta/css-only-chat
Dire qu’on anonymise l’adresse IP en ne hachant que la date et l’IP, c’est simplement du théâtre de sécurité.
Les hachages cryptographiques sont conçus pour être calculés rapidement. Avec hashcat, on peut calculer 6 milliards de hachages MD5 par seconde sur un MacBook M1 Pro, et il n’y a que 4 milliards d’adresses IPv4. On peut retrouver l’adresse IP en brute-forçant tout l’espace, ce qui revient en pratique à inverser le hachage.
Même en utilisant un hachage sûr comme SHA-256 au lieu de MD5, qui est cassé, le problème reste le même.
Même si vous hachez le nom complet de quelqu’un, vous pouvez répondre plus tard à la question : « ce hachage correspond-il à ce nom complet précis ? ». Pouvoir répondre à cette question signifie que le processus d’anonymisation est réversible.
Le hachage de l’adresse IP, dans ce contexte, sert uniquement à éviter les vues en double au cours d’une même journée. Il sert à rendre chaque vue de page unique par défaut, et à la fin de chaque journée une tâche worker supprime les hachages d’IP devenus inutiles.
[0] https://news.ycombinator.com/item?id=37596757
Le fait de conserver le sel de façon permanente ou de le renouveler régulièrement relève de détails d’implémentation ; l’essentiel, quand on sale un hachage à des fins d’analytics, est que le sel ne quitte jamais le client.
D’après la description de l’article, on dirait qu’il n’y a pas de sel. Ou alors la date du jour semble servir de sel, mais ce n’est pas un sel aléatoire : toute personne voulant savoir « l’IP x.y.z.w a-t-elle visité le site à la date aa-mm-jj ? » peut facilement le deviner.
Du point de vue d’un attaquant, ce genre de problème est facile à évaluer. Avec les données disponibles, comment pourrais-je apprendre quelque chose sur une personne donnée ? Si ce n’est pas possible, il est généralement assez probable que ces données puissent être stockées sans problème.
Je crains toutefois que ce genre de théâtre de sécurité suffise malgré tout à passer de nombreuses lois et réglementations sur les données personnelles.
Ça a l’air malin, mais
body:hoverrisque de passer presque totalement à côté des utilisateurs au clavier uniquement et des agents utilisateurs qui n’utilisent pas de dispositif de pointage, c’est-à-dire des utilisateurs de technologies d’assistance.Même si ces groupes peuvent être marginaux, voir des personnes exclues d’une manière ou d’une autre est toujours un très mauvais signal.
Je ne sais pas s’il existe, avec du CSS de base, une manière fiable à 100 % de détecter dans tous les agents utilisateurs qu’« un vrai utilisateur est en train de lire cet article » et d’envoyer une requête HTTP ; j’en doute même. Certains ne prennent pas du tout en charge CSS, ou peuvent avoir désactivé le chargement des images décoratives via CSS.
Parmi les sélecteurs modernes qui pourraient aider, il y a
:root:focus-within, mais l’utilisateur doit effectivement donner le focus à un élément interactif, et tous les agents utilisateurs ne le garantissent pas. Les animations dernier cri liées au défilement, comme@scroll-timeline, pourraient aussi être une possibilité, mais les lecteurs braille risquent toujours d’être exclus.:hover, soit plus de 50 % des agents utilisateurs ? À condition, bien sûr, qu’aucune souris ne soit branchée.Cette zone correspond à la largeur de la colonne de contenu plus 20 px de padding de chaque côté. Résultat : certains utilisateurs au clavier seront détectés, tandis que certains utilisateurs de souris, en particulier ceux qui utilisent un grand viewport, ne le seront pas.
Dire que « non seulement les choses néfastes comme Google Analytics, mais aussi Fathom et Plausible ont du mal à enregistrer l’activité dans les navigateurs avec bloqueur de publicité », c’est, à mon avis, parce qu’ils essaient en réalité de survivre dans un désert toxique
Les utilisateurs comme nous en ont assez de tout ce concept, et donc si l’analytics via CSS devient populaire, il y aura aussi des tentatives pour le contourner
J’ai déverrouillé manuellement Piwik/Matomo, Plausible et Fathom dans uBlock. Je ne vois pas en quoi ce qu’ils suivent, ni la manière dont ils le font, est nuisible. Et cela donne aux exploitants de sites des informations utiles pour « améliorer le service »
Par exemple, Plausible collecte moins d’informations sur moi que des logs nginx ou Apache classiques. Pour un blogueur, il est important de voir si un billet est arrivé sur HN, s’il a été lié quelque part, quels contenus sont jugés utiles et lesquels sont ignorés. C’est ce qui permet d’écrire ce que les gens veulent vraiment lire, et de le diffuser via les canaux où ils peuvent effectivement le découvrir
access.logdu serveur web dans un service d’analytics ne bloque rienAu contraire, comme il est pratiquement impossible de filtrer tout le trafic de bots uniquement à partir du user-agent, les chiffres peuvent être gonflés
Je ne sais pas combien de personnes en ont réellement peur. Les réactions iraient sans doute de « oui, c’est glaçant » à « n’importe quoi, c’est juste de la SF »
C’est connu depuis des décennies sous le nom de pixel de suivi
:hover, on peut filtrer les bots qui n’utilisent pas un WebDriver complet, c’est-à-dire la plupart des botsÀ certains égards, il serait peut-être préférable de charger via
@import, avecsupports, un fichier.csspresque vide. Les bloqueurs de publicité repèrent très bien les pixels de suivi transparents de 1 px, mais ils sont moins susceptibles de bloquer des fichiers.csspour éviter de casser la mise en page. En revanche, on perd alors l’avantage astucieux de:hoverVraie question, mais j’ai peur qu’elle soit lue comme un avis méprisant : quel est l’objectif de collecte de données d’analytics sur un blog personnel non commercial qui ressemble à Bearblog ?
La principale raison de s’intéresser à l’analytics est de voir si les textes sont lus. En surface, et aussi d’une certaine manière, c’est de la vanité, mais en réalité cela relève du lien entre l’auteur et ses lecteurs. On veut vraiment savoir à quoi les lecteurs réagissent, et leur en donner davantage. Ce « davantage » peut être un sujet, un ton, une longueur. Cela aide à ajuster les idées à son lectorat. Au fond, je peux écrire sur une douzaine de sujets de vingt-quatre façons différentes. Bien sûr, j’écris ce qui me plaît, mais je l’affine pour que cela résonne mieux auprès des lecteurs
En ce sens, l’analytics est aussi une façon d’apprendre à connaître ses lecteurs. Sur les blogs très actifs, l’analytics donnait une sorte de portrait flou du lectorat. On pouvait voir non seulement ce qu’il aimait, mais aussi quand il l’aimait. S’ils lisaient dès le matin, pendant la pause déjeuner ou tard le soir ; cela aidait à décider de publier à certains moments, ou à conforter cette décision. Bien sûr, tout cela restait flou, mais cela aidait vraiment à créer un lien plus actif avec les lecteurs
Bien sûr, cela peut être utilisé pour la publicité et peut être abusé, mais si l’on veut du feedback sur ce que l’on fait, c’est indispensable
Qu’un site soit lu par 12 personnes ou par 12 000, cela peut n’avoir aucune valeur financière. Mais d’un point de vue personnel, il est agréable de savoir ce que les gens veulent lire chez soi, de sentir que le temps passé à écrire a été bien utilisé, et, si on le souhaite, d’ajuster vers ce qui est plus populaire
Même un blogueur personnel peut vouloir adapter son contenu à son lectorat. C’est appréciable de savoir qu’un billet sur tel sujet a été lu par 500 personnes, tandis qu’un autre n’a été lu que par 3
J’ai essayé de faire quelque chose comme ça plus tôt cette année, mais j’ai perdu ma motivation en construisant l’interface web. Mon approche ne reposait pas sur CSS, mais consistait simplement à charger une fausse image via une balise
https://github.com/nolytics
Pourquoi ne pas simplement obtenir ces informations depuis le serveur HTTP ?
« Il reste toujours l’option de parser les logs serveur, ce qui permet de se faire une idée approximative des types de trafic qui accèdent au serveur. Mais, en général, tout le trafic serveur se ressemble. Techniquement, les bots devraient avoir un user-agent qui les identifie comme tels, mais comme ils essaient de scraper les informations comme le ferait une “personne” utilisant un navigateur, ils s’identifient rarement ainsi. En substance, si l’on utilise uniquement les logs serveur pour l’analytics, les crawlers de moteurs de recherche, les scrapers et désormais les parseurs basés sur GPT sont si nombreux qu’ils faussent la vision du trafic »
Comment stocker les données d’analyse ?
Imaginons qu’on ait un site e-commerce et des produits à vendre. En plus de l’analytics, on décide de journaliser directement certaines actions, comme la visite d’une page de détail produit par un utilisateur connecté. On veut donc stocker des éléments comme l’ID utilisateur, l’ID produit et l’horodatage.
En pratique, comment faut-il les stocker ? Naïvement, je pensais qu’il suffisait de les mettre dans une table. Le DBA a demandé combien de temps les données devaient être conservées, et j’ai répondu au moins un mois. Il a dit d’accord, et j’imagine qu’il a prévu une tâche pour déplacer les données plus anciennes vers une autre table.
En réalité, comment stocke-t-on ce type de logs, et combien de temps les conserve-t-on ?
Je l’ai déjà fait ainsi, et je n’ai même pas eu besoin de penser au partitionnement avant d’atteindre environ 1 milliard de lignes. Cela dit, mieux vaut partitionner plus tôt. Cette expérience n’a pas été agréable.
Ils permettent de faire des agrégations beaucoup plus rapidement et gèrent bien de nombreuses colonnes clairsemées. Par exemple, un événement
paidaura un attributamount, tandis qu’un événementpage_viewaura un attributurl.L’intérêt de TimescaleDB, c’est qu’il prend en charge automatiquement la création de vues matérialisées pour les agrégats qui vous intéressent, comme le nombre de vues produit par heure. Si vous avez beaucoup d’événements et voulez éviter que la base de données ne devienne trop volumineuse, vous pouvez aussi choisir de “jeter” les événements eux-mêmes et de ne conserver que les agrégats.