GoatCounter en NixOS: de 2.000 visitas diarias a menos de 200 humanos
Un blog técnico cambia GoAccess por una analítica open source sin cookies y monta un proxy propio en sus cinco servidores para que los scrapers de IA dejen de contaminar las estadísticas.

El autor de un blog técnico llevaba años viendo cifras sin sentido en sus estadísticas: unos 2.000 visitantes al día, casi todos bots. Hace unos meses migró a GoatCounter, una plataforma de analítica web open source y sin cookies, le puso delante un cliente JavaScript propio que exige interacción humana y desplegó un proxy local en cada uno de los cinco servidores que sirven el sitio. El recuento bajó a menos de 200 humanos diarios.
No es su primer cambio. En 2016 echó Google Analytics y se pasó a GoAccess para leer los logs del servidor. El problema llegó después: los scrapers de IA inflaron el tráfico hasta hacer la serie inútil, por mucho que intentara filtrarlos. GoatCounter resuelve el ruido y de paso el problema de privacidad. En lugar de guardar la IP del lector o plantar una cookie, genera un identificador de sesión válido ocho horas a partir del user agent y la IP. Un solo binario y una base SQLite: es de las opciones autoalojadas más ligeras. El autor menciona Umami, Plausible y Rybbit como alternativas, en orden creciente de complejidad.
Filtrado por interacción
El cliente oficial de GoatCounter pesa 2.189 bytes minificado y comprimido con gzip, y trae funciones que este blog no usa. Lo sustituyó por una función de unas pocas líneas que hace un fetch a /count con keepalive. El filtro de bots va un paso más allá: no registra nada hasta que el lector interactúa.
let sendHit = () => (sendHit = () => {}, count());
["touchmove", "mousemove", "keydown", "pointerdown"].forEach((eventName) =>
document.addEventListener(eventName, sendHit, { once: true, passive: true })
);
El razonamiento es que un scraper de bajo esfuerzo no levanta un navegador instrumentado solo para disparar un evento. Ni siquiera Googlebot, que sí ejecuta JavaScript con su Chromium headless, interactúa con la página. Para el 2% de lectores que navega sin JavaScript hay un plan B en CSS: una imagen cargada desde la pseudoclase :hover, que solo se pide cuando hay interacción real.
Proxy en cada servidor y despliegue con NixOS
GoatCounter corre en una sola máquina, así que el autor añadió un proxy local escuchando en /count en cada servidor. Guarda los impactos en memoria con un búfer para varios días de caída y los envía por lotes al backend autenticado en /api/v0/count. Propuso el código en el pull request #909 y el mantenedor lo rechazó: demasiado código para un caso de uso tan concreto. Expone el endpoint en el dominio del sitio con nginx para esquivar los bloqueadores de anuncios, una decisión que justifica porque no recoge datos personales.
Los servidores corren NixOS y se gestionan con Colmena. Cada aplicación vive en un contenedor efímero con systemd-nspawn sobre una instancia recortada de NixOS, con el espacio de nombres de red compartido con el host; la configuración está publicada en su repositorio. La base SQLite se replica con Litestream.
El interés de la pieza no está en el contador de visitas, sino en el patrón: medir tráfico hoy obliga a asumir que la mayoría de las peticiones no son personas. Quien mantenga analítica propia y siga mirando sus números como si lo fueran está tomando decisiones con datos que no describen a nadie. Queda por ver cuánto aguanta el truco de la interacción: es trivial de sortear, pero encarece el scraping y por eso funciona.

