- Bear Blog implementó su propio sistema de analítica que funciona sin JavaScript del lado del cliente, debido a restricciones de velocidad, eficiencia y estabilidad
- Los scripts de analítica habituales pueden ser bloqueados por bloqueadores de anuncios, y con solo los logs del servidor pueden mezclarse rastreadores, scrapers e incluso parsers basados en GPT, lo que distorsiona las estadísticas de visitas
- En el CSS de cada página, cuando ocurre
body:hover, se llama al endpoint /hit/{{ post.id }}/ mediante border-image, usando el hover o el scroll en móvil como señal de lectura
- El servidor usa el user-agent para verificar si es un bot, el navegador y la plataforma, y la dirección IP solo se usa para determinar el país; luego elimina lecturas duplicadas con un hash de IP+fecha
- Si se lee desde varios dispositivos el mismo día con la misma IP, se cuenta como una sola vez, pero aun sin guardar información identificable se puede contabilizar de forma simple el número de lecturas únicas por página
Crear eventos de lectura con hover de CSS
- El sistema de analítica de Bear Blog sigue la restricción de no usar JavaScript del lado del cliente
- Las herramientas de analítica convencionales pueden juzgar parcialmente la autenticidad del tráfico o si se trata de bots con JavaScript del lado del cliente, pero muchos bloqueadores de anuncios bloquean no solo Google Analytics, sino también scripts de analítica como Fathom o Plausible
- Parsear únicamente los logs del servidor puede mezclar rastreadores de motores de búsqueda, scrapers y parsers basados en GPT como si fueran tráfico normal, generando una visión distorsionada
- Bear inserta el siguiente CSS en cada página para que, cuando el usuario pase el cursor sobre la página o haga scroll en móvil, se active
body:hover
body:hover {
border-image: url("/hit/{{ post.id }}/?ref={{ request.META.HTTP_REFERER }}");
}
- Cuando se activa
body:hover, se llama a la URL de hit de ese artículo
- La información que se vuelve a agregar explícitamente en esta solicitud es el referrer, y la ortografía
HTTP_REFERER es una forma con un error ortográfico que quedó como estándar
- Aprovechando que los bots no hacen hover, Bear usa la llamada basada en
body:hover como señal de lector humano
- Después, en el servidor se comprueba si el user-agent corresponde a un bot y se extraen de la cadena del user-agent el navegador y la plataforma
Eliminar lecturas duplicadas sin información identificable
- La segunda restricción es no guardar en cookies del navegador ni en el servidor información que pueda identificar al lector
- La dirección IP se usa solo para determinar el país y, antes de almacenarla, se aplica un hash conjunto de la IP y la fecha
- Las solicitudes posteriores a la misma página se comparan con el hash de
dirección IP + fecha y, si están duplicadas, se descartan
- Con este método, durante un día una dirección IP cuenta como una sola lectura por página
- La IP original no se almacena, y el hash que incluye la fecha tiene el efecto de expirar por día
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)
- El hash de la IP se usa solo para evitar hits duplicados durante un día, y por defecto todas las vistas de página se tratan como únicas
- Al final de cada día, una tarea en segundo plano borra el hash de los logs de hits para evitar conflictos con interpretaciones excesivamente estrictas del GDPR
- Una desventaja de este método es que, si se lee desde varios dispositivos el mismo día con la misma IP, solo se registra una lectura
- Bear considera que esos casos representan una pequeña parte del tráfico, y cree que este enfoque basado en CSS ofrece una cifra de lecturas más precisa, además de ser más limpio y simple que varios métodos de recolección de analítica
1 comentarios
Comentarios en Hacker News
Soy el autor. El hash de la dirección IP en este contexto solo sirve para evitar vistas duplicadas dentro del mismo día.
La idea es que cada vista de página sea básicamente única, y al final de cada día una tarea del worker borra el hash mientras conserva la información de vistas. Agregué una aclaración al artículo para dejarlo más claro.
La primera vez que vi la idea de usar solicitudes generadas por CSS para analítica me pareció genial.
Alguien en Twitter puso una cuadrícula invisible de rectángulos sobre la página, e hizo que al pasar el cursor por cada celda se cargara una imagen de fondo única, para usarlo como seguimiento del mouse. Cada imagen de fondo enviaba una solicitud específica al servidor, y el servidor la interpretaba.
Por diversión, un verano extendí esa idea para hacer un “chat web asincrónico solo con CSS” sin JavaScript: https://github.com/kkuchta/css-only-chat
Decir que anonimizar la dirección IP haciendo hash solo de la fecha y la IP es puro teatro de seguridad.
Los hashes criptográficos están diseñados para calcularse rápido. Con hashcat se pueden calcular 6 mil millones de hashes MD5 por segundo en una MacBook M1 Pro, y solo existen 4 mil millones de direcciones IPv4. Puedes hacer fuerza bruta sobre todo el rango y recuperar la IP, así que en la práctica es lo mismo que revertir el hash.
Incluso si usas un hash seguro como SHA-256 en lugar de MD5 roto, el problema sigue siendo el mismo.
Aunque hagas hash del nombre completo de alguien, después aún puedes responder la pregunta “¿este hash coincide con este nombre completo en particular?”. Poder responder esa pregunta significa que el proceso de anonimización es reversible.
El hash de la dirección IP en este contexto solo sirve para evitar vistas duplicadas dentro del mismo día. La idea es que cada vista de página sea básicamente única, y al final de cada día una tarea del worker elimina los hashes de IP que ya no hacen falta.
[0] https://news.ycombinator.com/item?id=37596757
Si el salt se conserva para siempre o se rota periódicamente es solo un detalle de implementación, y el punto clave al agregar salt a hashes para analítica es que el salt nunca salga del cliente.
Por la explicación del artículo, parece que no hay salt. O tal vez se usa la fecha actual como si fuera salt, pero eso no es aleatorio, así que cualquiera que quiera saber “¿la IP x.y.z.w visitó en la fecha aa-mm-dd?” puede adivinarlo fácilmente.
Desde la perspectiva de un atacante, este tipo de problema es fácil de evaluar. ¿Cómo haría para descubrir algo sobre una persona específica con los datos disponibles? Si no puede, probablemente sea relativamente seguro guardar esos datos.
Igual me preocupa que incluso este tipo de teatro de seguridad alcance para pasar varias leyes y regulaciones sobre privacidad.
Se ve ingenioso, pero
body:hoverprobablemente deje fuera casi por completo a usuarios que solo usan teclado y a agentes de usuario sin dispositivo apuntador, o sea, usuarios de tecnologías de asistencia.Aunque ese grupo pueda ser minoritario, siempre es una muy mala señal ver que se les excluye de alguna forma.
No sé si existe una manera con CSS básico de detectar con 100% de fiabilidad en todos los agentes de usuario que “una persona real está leyendo este artículo” y además enviar una solicitud HTTP; de hecho, lo dudo. Algunos quizá ni siquiera soporten CSS, o podrían tener desactivada la carga de imágenes decorativas desde CSS.
Un selector moderno que podría ayudar es
:root:focus-within, pero requiere que el usuario realmente ponga foco en un elemento interactivo, y no todos los agentes de usuario garantizan eso. También podrían servir las animaciones vinculadas al scroll más modernas como@scroll-timeline, pero aun así probablemente dejarían fuera a los lectores braille.:hover? Claro, asumiendo que no tengan un mouse conectado.Esa área corresponde al ancho de la columna de contenido más 20 px de padding a cada lado. Así que algunos usuarios de teclado sí quedarían registrados, mientras que algunos usuarios de mouse, especialmente quienes usan viewports grandes, no.
Que “no solo cosas malas como Google Analytics, sino también Fathom y Plausible, tienen dificultades para registrar actividad en navegadores con bloqueadores de anuncios” me parece que se debe a que básicamente intentan sobrevivir en un yermo tóxico
Usuarios como nosotros ya estamos hartos de todo ese concepto, así que si la analítica con CSS se vuelve popular, creo que también surgirán intentos por esquivarla
Yo desactivé manualmente el bloqueo de Piwik/Matomo, Plausible y Fathom en uBlock. No considero dañino lo que rastrean ni cómo lo hacen. Y además le dan al operador del sitio información útil para “mejorar el servicio”
Por ejemplo, Plausible recopila menos información sobre mí que los logs típicos de nginx o Apache. Desde la perspectiva de un bloguero, es importante ver si una publicación llegó a HN, si fue enlazada desde algún lado y qué contenido se considera valioso y cuál se ignora. Así puedes escribir sobre lo que la gente realmente quiere leer y difundirlo por canales donde realmente se puede dar a conocer
access.logdel servidor web en un servicio de analítica no impide nadaMás bien, como es prácticamente imposible filtrar todo el tráfico de bots mirando solo el user agent, los números pueden inflarse
No sé cuánta gente realmente teme eso. Supongo que las reacciones van desde “sí, qué escalofriante” hasta “ni hablar, eso es pura ciencia ficción”
Esto se conoce desde hace décadas como un rastreador por píxel
:hover, puedes filtrar bots que no usan un WebDriver completo, es decir, la mayoría de los botsEn cierto sentido, quizá sería mejor cargar un archivo
.csscasi vacío con@importjunto consupports. Los bloqueadores de anuncios detectan muy bien los píxeles de seguimiento transparentes de 1px, pero podrían bloquear menos los archivos.csspara no romper el diseño. Aunque en ese caso se pierde la ventaja ingeniosa de:hoverEs una pregunta sinceramente curiosa, aunque me preocupa que suene despectiva. ¿Cuál es el objetivo de recopilar datos analíticos en un blog personal no comercial como Bearblog?
La razón principal para interesarse por la analítica es ver si tus textos se están leyendo. En apariencia, y en parte, puede ser por vanidad, pero en realidad tiene que ver con la conexión entre quien escribe y quien lee. De verdad te da curiosidad saber a qué reaccionan los lectores, y quieres darles más de eso. Ese “eso” puede ser el tema, el tono o la longitud. Ayuda a ajustar el material para tu audiencia. Al final, yo puedo escribir sobre una docena de temas de veinticuatro maneras distintas. Claro que escribo sobre lo que me gusta, pero lo afino para que resuene mejor con mis lectores
En ese sentido, la analítica también es una forma de conocer a tus lectores. En los blogs con más participación, la analítica me daba algo parecido a un retrato borroso del lector. No solo podía ver qué le gustaba, sino también cuándo le gustaba. Podía saber si leían a primera hora de la mañana, en la hora del almuerzo o tarde en la noche, y eso ayudaba a decidir si publicar en cierto momento o a tener más confianza en esa decisión. Claro, toda esa información era difusa, pero realmente ayudaba a conectar de forma más activa con los lectores
Claro que puede usarse para publicidad y puede abusarse de ella, pero si quieres retroalimentación sobre lo que haces, es indispensable
Ya sea que tu sitio lo lean 12 personas o 12,000, puede que no tenga valor económico. Pero desde un punto de vista personal, está bien saber qué quiere leer la gente de ti, sentir que el tiempo que dedicaste a escribir valió la pena y, si quieres, ajustar el rumbo hacia lo más popular
Incluso un bloguero personal puede querer ajustar su contenido a sus lectores. Está bien saber que un texto sobre cierto tema fue leído por 500 personas y que otro sobre un tema distinto solo lo leyeron 3
A principios de este año intenté hacer algo así, pero perdí la motivación mientras construía la UI web. Mi método no usa CSS, sino que simplemente carga una imagen falsa con etiquetas
https://github.com/nolytics
¿Por qué no obtener simplemente esta información desde el servidor HTTP?
“Siempre existe la opción de parsear los logs del servidor y obtener una idea aproximada del tipo de tráfico que llega al servidor. Pero por lo general, todo el tráfico del servidor se ve igual. Técnicamente, los bots deberían tener un user agent que se identifique como bot, pero como intentan extraer información como si fueran una ‘persona’ usando un navegador, casi nunca se identifican así. En esencia, si usas solo los logs del servidor para analítica, vas a ver el tráfico distorsionado por la gran cantidad de rastreadores de motores de búsqueda, scrapers y ahora incluso parsers basados en GPT”
¿Cómo se almacenan los datos de analítica?
Supongamos que existe un sitio de comercio electrónico y hay productos que quieres vender. Además de la analítica, se decide registrar directamente algunos comportamientos, como visitar la página de detalle de un producto mientras se ha iniciado sesión. Entonces se quiere guardar cosas como el ID de usuario, el ID del producto y la marca de tiempo
¿Cómo debería almacenarse esto en la práctica? Ingenuamente, se pensó que bastaba con meterlo en una tabla. El DBA preguntó cuánto tiempo se necesitaban los datos, y la respuesta fue al menos un mes
Entonces dijo que estaba bien, y probablemente dejó programado algún trabajo para mover a otra tabla los datos más antiguos
En la práctica, ¿cómo se almacenan este tipo de logs y durante cuánto tiempo se conservan?
Ya lo hice así antes, y ni siquiera fue necesario pensar en particionado hasta llegar a unos mil millones de filas. Aun así, conviene particionar antes de llegar a ese punto. Esa experiencia no fue agradable
Permiten hacer agregaciones mucho más rápido y manejan bien muchas columnas dispersas. Por ejemplo, un evento
paidtiene la propiedadamount, mientras que un eventopage_viewtiene la propiedadurlLo bueno de TimescaleDB es que se encarga de crear vistas materializadas para agregaciones de interés, como las vistas de productos por hora. Si hay tantos eventos que quieres evitar que la base de datos crezca demasiado, también puedes optar por “descartar” los eventos en sí y quedarte solo con las agregaciones