[🛠] Agregar un contador de visitas a un blog de GitHub Pages
✨ Resumen de GPT-5.5
Registro de cómo agregué un Cloudflare Worker y D1 dentro del rango gratuito a un blog estático de GitHub Pages, conservando los acumulados existentes de GA mientras mostraba las visitas de hoy y las vistas por entrada.
Me dieron ganas de agregar un contador de visitas al blog.
No porque la función en sí sea impresionante. Más bien al contrario. Se siente como una función demasiado obvia, pero en un blog estático hecho con GitHub Pages no viene incorporada de forma natural.
Google Analytics ya estaba instalado. Como operador, si entraba a GA podía ver la cantidad de visitantes y de vistas. Pero esos números no se veían dentro del blog. Quien visita el blog no puede saber si todavía se lee hoy, ni cuánto se han leído las entradas recientes.
Quería esa sensación pequeña de los indicadores de Naver Blog: Hoy, Acumulado y vistas por entrada. Más que números para presumir, era una señal de que el blog no es una página estática muerta, sino algo que se sigue leyendo.
Así que el problema era simple.
¿Podía mantener las ventajas de un blog estático gratuito y agregar solo una parte dinámica mínima para las estadísticas de visitas?
Primero definí las condiciones
No quería agrandar la estructura solo por agregar un contador de visitas.
Desde el principio fijé algunas condiciones.
- Mantener el flujo de escritura con GitHub Pages y Jekyll.
- No usar un servidor de pago.
- Resolverlo dentro del rango gratuito, ya fuera con Cloudflare o Firebase.
- Colocarlo pequeño, cerca del perfil.
- Hacer que no se alargue de forma extraña en móvil.
- Mostrar no solo las estadísticas de todo el blog, sino también las vistas por entrada.
- No tirar a la basura los acumulados existentes de GA.
La última condición era especialmente importante.
Si agregaba un contador nuevo y las vistas empezaban desde 0, se vería raro. El blog ya estaba en funcionamiento y GA tenía vistas acumuladas desde antes. Pero seguir leyendo solo desde GA quedaba lejos de la sensación de contador que quería.
Pensé que bastaría con leer GA
Al principio pensé que bastaría con leer la API de Google Analytics.
Como GA ya tenía los datos, parecía que un Cloudflare Worker podría llamar a la API de GA y devolver los números. De hecho, creé una cuenta de servicio, le di permisos sobre la propiedad de GA y logré hacer llamadas a la API.
Pero cuando lo conecté, no era lo que quería.
GA es una herramienta de análisis. Es buena para que el operador mire los flujos más tarde, pero resultaba ambigua como contador de visitas que responde directamente en la pantalla del blog. El número de Hoy era especialmente problemático. Si yo acababa de entrar y aun así el valor de hoy aparecía como 0, desde el punto de vista del visitante simplemente parecía roto.
También confundían los nombres de las métricas. Active users y page views son valores distintos. Si intentaba definir estrictamente la cantidad de visitantes, el número se veía demasiado conservador. Si usaba page views, se sentía más natural, pero había que cuidar la etiqueta.
Al final, el juicio fue simple.
Usar GA como valor base histórico y contar por mi cuenta los incrementos a partir de ahora.
Separé el baseline y el incremento
La estructura final quedó así.
Vistas públicas = baseline de GA + incremento de Cloudflare D1
El baseline de GA es el número ya acumulado. Se fija una fecha de referencia y se guardan las vistas totales y las vistas por entrada acumuladas hasta ese momento.
A partir de ahí, Cloudflare Worker cuenta directamente. Cuando una persona entra al blog, JavaScript llama al Worker, y el Worker registra en D1 los incrementos de hoy, del mes, del total y de cada page path.
Resumido, queda así.
Acumulado existente: baseline de Google Analytics
Incremento nuevo: Cloudflare Worker + D1
API pública: Cloudflare Worker
Visualización en el blog: Jekyll include + JavaScript
Me gustó este método porque no descarta ninguno de los dos lados.
Conserva los datos existentes de GA. Al mismo tiempo, los conteos futuros reaccionan de inmediato en la pantalla del blog.
Por qué Cloudflare Worker y D1
Firebase también era candidato. Pero para una función de este tamaño, el lado de Cloudflare era más simple.
GitHub Pages es un sitio estático, así que no hay ningún lugar donde poner código de servidor. Worker llena ese hueco con una pieza pequeña. D1 está basado en SQLite, así que era suficiente para guardar números simples como los de un contador de visitas.
La condición de costo también encajaba. Un contador de visitas para un blog personal se puede manejar dentro del rango gratuito. Si de repente entra mucha gente, existe la posibilidad de que una parte del conteo sea algo imprecisa, pero las entradas en sí no se rompen. Para empezar, esto no es un sistema de pagos ni un libro contable financiero.
Lo que yo quería no era una contabilidad exacta, sino mostrar el flujo de que el blog se está leyendo.
Bloqueé bots y visitas duplicadas de forma moderada
Si se agrega un contador a una página pública, los bots también pueden subir los números.
Es difícil bloquearlos perfectamente. Y si bloqueo demasiado fuerte, me alejo del contador que quería. Prefería que contara con cierta amplitud, como Naver Blog.
Así que el Worker solo maneja unas pocas cosas.
- Excluye user-agents que son bots evidentes.
- No vuelve a contar la misma combinación de visitante y página dentro de un cierto tiempo.
- Acumula las vistas por entrada del mismo modo, con base en el path.
Es decir, lo ajusté a un contador público de visitas, no a una herramienta de análisis estricta.
Lo puse pequeño en la pantalla
Al principio intenté mostrar las estadísticas en varias columnas. Pero la UI que va junto al perfil tiene que ser pequeña. Si aparecen demasiados números, la primera pantalla del blog se ensucia.
Así que al final dejé tres valores.
Hoy / Mes / Total
Hoy da la sensación de que el blog se está leyendo ahora. Mes muestra la escala reciente. Total muestra el tiempo que el blog ha acumulado.
En la lista de entradas, agregué vistas a cada entrada.
10 vistas
Este valor también usa la misma estructura que las estadísticas generales.
Vistas por entrada = baseline por entrada de GA + incremento por entrada de Cloudflare D1
Por ejemplo, si una entrada tenía 9 vistas según GA y se leyó una vez más después del cambio al contador nuevo, en la pantalla aparece como 10 vistas.
Eso se sentía como lo más natural. No se descartan las vistas pasadas, y las vistas futuras se acumulan de inmediato.
Resultado
Como resultado, cerca del perfil del blog aparecieron números como estos.
Hoy 1 / Mes 66 / Total 4,944
Y en la lista de entradas aparecen vistas de esta forma.
10 vistas
Si miro solo la función, es pequeña. Pero este trabajo me gusta bastante.
El problema era claro. Un blog de GitHub Pages no tenía contador de visitas. GA existía, pero no bastaba como contador visible en la pantalla pública. Aun así, no quería crear un servidor grande solo por un blog.
Así que conservé los datos existentes de GA como baseline y agregué una estructura que cuenta directamente solo los incrementos posteriores con Cloudflare Worker y D1.
Las ventajas del blog estático quedaron tal cual. Escribo en Markdown, despliego con GitHub Pages y el costo de mantenimiento queda cerca de 0 won. En cambio, puse una pequeña pieza serverless solo en la parte exacta que faltaba.
Si más adelante tengo que mostrar este blog como portafolio, creo que trabajos como este pueden ser buenos de explicar. No es una función grandiosa, pero nació de una incomodidad real, limitó el costo y la complejidad, y llegó hasta una forma operable.
Deja un comentario