Ce qui se passe
Vincent Bernat a retiré Google Analytics de son blog en 2016 et suivait depuis son audience avec GoAccess, qui lit les journaux du serveur. Depuis deux ans, les chiffres ne voulaient plus rien dire : les robots qui aspirent le web pour l'IA, passés par des proxys résidentiels et munis de user agents usurpés, portaient le compte à environ 2 000 visiteurs par jour. Avec GoatCounter et un client JavaScript de sa main, il compte désormais moins de 200 humains par jour.
Le filtre : attendre un geste
L'idée vient de Bear Blog. La visite n'est envoyée qu'au premier geste du
lecteur — touchmove, mousemove, keydown ou pointerdown —, une seule
fois. Un robot qui récupère le HTML sans lancer de navigateur ne produit aucun
de ces événements. Googlebot, qui exécute le JavaScript dans un Chromium sans
interface, n'interagit pas non plus avec la page.
Le principe, réduit à l'essentiel :
const events = ['touchmove', 'mousemove', 'keydown', 'pointerdown'];
function recordVisit() {
events.forEach((name) => document.removeEventListener(name, recordVisit));
const url = `/count?p=${encodeURIComponent(location.pathname)}`;
// A lost hit must not bother the reader, but it should stay visible in the console.
fetch(url, { keepalive: true }).catch((err) => console.debug('visit not recorded', err));
}
events.forEach((name) => document.addEventListener(name, recordVisit, { passive: true }));Pour les lecteurs sans JavaScript, environ 2 %, une règle CSS sur
body:hover charge une image de comptage via border-image : le survol tient
lieu de geste.
Pourquoi GoatCounter
Un binaire unique et une base SQLite. Ni cookie ni adresse IP stockée : la session est un identifiant valable 8 heures, dérivé du user agent et de l'IP. L'auteur cite comme alternatives, de la plus simple à la plus lourde, Umami, Plausible et Rybbit.
Le reste de l'article détaille son déploiement : un proxy local sur chacun de
ses 5 serveurs, qui garde les visites en mémoire et les transmet par lots à
l'API /api/v0/count (proposé en amont dans la PR #909, que le mainteneur a
refusée) ; des conteneurs systemd-nspawn éphémères sous NixOS, déployés avec
Colmena ; une réplication continue de la base par Litestream vers un
stockage SFTP.
Les limites
C'est la mesure d'un seul blog, en accès libre. L'auteur suppose que les robots ne lancent pas de navigateur complet quand le contenu est accessible sans obstacle ; un robot qui simule des gestes passerait le filtre. Il sert aussi le point de comptage sur le domaine du blog, ce qui contourne les bloqueurs de publicité — un choix qu'il assume parce que l'outil ne collecte pas de données personnelles.
Source : Bot-free self-hosted analytics with GoatCounter on NixOS, Vincent Bernat, 20 septembre 2026.