2026.06.09 (Mar)

✨ Resumen de GPT-5.5  

Un registro de cómo rastreé un salto extraño en el contador de visitas, bloqueé que el trabajo local se contara, y añadí una página pública de analytics agregados con Cloudflare Worker y D1.

El contador de visitas se veía raro.

El número diario saltó de repente por encima de 80.

Podría haberlo tomado como tráfico de búsqueda. Pero algo no cuadraba. Durante varios días estuve modificando el blog, y durante el trabajo con IA abrí muchas veces tanto el servidor local como la URL pública.

Así que tuve que preguntarme algo simple.

¿Era tráfico real?

¿O mi propio trabajo también estaba entrando en el contador?

El contador era demasiado honesto

Primero volví a mirar la estructura.

El contador creado en /es/devlog/github-pages-blog/github-pages-blog-visitor-counter/ usa Cloudflare Worker y D1.

Cuando una página se carga, JavaScript envía /track al Worker. El Worker incrementa counters, page_counters y dedupe_views en D1. Google Analytics solo sirve como baseline; los incrementos nuevos se guardan en D1.

El problema era que esa estructura era demasiado honesta.

Si un navegador abría una página, contaba.

El servidor local también apuntaba al Worker de producción. En los origins permitidos del Worker estaban localhost:4000 y 127.0.0.1:4000.

Así que una vista previa local podía aumentar el contador real de producción.

La deduplicación también usaba visitorId + path. La misma página en el mismo navegador se deduplica durante 10 minutos, pero abrir muchos posts distintos cuenta cada uno.

D1 lo mostró con claridad.

day:2026-06-06 = 14
day:2026-06-07 = 38
day:2026-06-08 = 81
day:2026-06-09 = 5

El 2026-06-08 aparecían muchos Daily Review antiguos y posts naver-* tocados una vez. Parecía más una sesión de revisión que lectores reales.

El trabajo local debe mostrar, no contar

La primera corrección fue sencilla.

En local se pueden mostrar las estadísticas, pero no se debe enviar /track.

localhost
127.0.0.1
::1

En esos entornos, el script cliente no envía tracking.

Pero no basta con confiar en el cliente. Si el JS cambia o alguien envía una petición manual, el problema vuelve. Por eso el Worker también cuenta /track solo desde el origin de producción.

TRACK_ALLOWED_ORIGIN=https://hyuk.blog

Las peticiones desde local ahora se ignoran con origin_not_tracked.

También añadí un opt-out para revisar producción sin ensuciar el contador.

?hyuk_no_track=1
?visitor_tracking=off
?visitor_tracking=on

No es un sistema de administración oculto. Es solo un interruptor para revisar la página pública sin alterar los números.

Las estadísticas no tenían por qué ser privadas

Al principio pensé en una página de analytics solo para mí.

Pero no era necesario.

Si no guardo IPs en bruto, User-Agent en bruto, full referrer URL ni logs de eventos individuales, la página puede ser pública. Basta con guardar valores agregados que se puedan mostrar.

Así que cambié el rumbo.

No una página privada de logs.

Una página pública de estadísticas del blog.

/analytics/

La añadí a la navegación superior y también al pequeño bloque de visitas del sidebar.

D1 guarda solo agregados

La tabla nueva es simple.

analytics_daily_dimensions

date
dimension
value
count
updated_at

Cuando una page view se cuenta de verdad, el Worker clasifica dimensiones públicas y las acumula por día.

Las dimensiones son:

page
content_group
locale
country
region
continent
colo
asn_org
device
viewport
browser
os
language
client_timezone
color_scheme
connection
traffic_source
referrer_domain
hour
weekday

Lo importante es lo que no se guarda.

El referrer se guarda como dominio, no como URL completa. El User-Agent se clasifica en browser, OS y device. La IP no se guarda.

No es un warehouse de analítica estricta. Es un panel público de flujo para un blog personal.

Hoy, mes, total y rango personalizado

Al principio solo pensé en hoy / mes / total, como el contador existente.

Pero una página de estadísticas necesita rangos.

La API /analytics acepta:

/analytics?range=today
/analytics?range=month
/analytics?range=total
/analytics?range=custom&start=2026-06-09&end=2026-06-12

Aquí total significa el total desde que analytics_daily_dimensions empezó a recoger datos el 2026-06-09. No es lo mismo que el total del sidebar, que sigue incluyendo el baseline de GA.

No mezclé esos dos significados.

Primero usable en móvil

Las páginas de estadísticas se rompen fácil en móvil.

Una tabla grande se vuelve incómoda enseguida. Así que usé tarjetas con barras.

Arriba quedan solo cuatro números.

Rango seleccionado
Hoy
Este mes
Total

Debajo van las tarjetas por dimensión.

En móvil, los botones de rango se dividen en dos filas, los KPI quedan en dos columnas y las tarjetas detalladas bajan a una columna. El formulario de rango personalizado también se apila verticalmente.

En desktop, los KPI quedan en una fila y las tarjetas se abren en dos columnas.

Lo comprobé en el navegador. No había overflow horizontal ni errores de consola.

Lo verificado

La verificación fue:

node --check cloudflare/ga-stats-worker.js
node --check assets/js/custom/visitor-stats.js
node --check assets/js/custom/analytics-dashboard.js
bundle exec jekyll build
npx wrangler d1 execute hyuk-blog-view-counter --remote --file cloudflare/schema.sql
npx wrangler deploy --keep-vars

Después del deploy, /analytics?range=today respondió correctamente.

La nueva tabla agregada aún estaba vacía. Es normal. Las estadísticas detalladas empiezan a llenarse con visitas públicas reales después del deploy.

También probé tracking desde origin local.

{"status":"ignored","reason":"origin_not_tracked"}

Ahora revisar el blog en local no incrementa el contador de producción.

De contador de visitas a analytics público

Al principio eran solo tres números pequeños.

Hoy, mes, total.

Pero al operarlo de verdad, lo importante no era solo el número. Era que el número no estuviera contaminado. Y para un blog público, mostrar flujo agregado seguro encajaba mejor que esconder una página privada de logs.

No es contabilidad exacta.

Pero ahora puede responder preguntas útiles.

Qué posts se leen.

Desde qué países llegan visitas.

Si predomina móvil o desktop.

Si el tráfico viene de búsqueda, directo o referral.

Y, sobre todo, cuánto ruido de mi propio trabajo debo mantener fuera.

Para eso existe /analytics/.

Deja un comentario