2026.06.09 (Ter)

✨ Resumo do GPT-5.5  

Um registro de como investiguei um salto estranho no contador de visitas, bloqueei o trabalho local de ser contado e adicionei uma página pública de analytics agregados com Cloudflare Worker e D1.

O contador de visitas parecia errado.

O número diário passou de 80 de repente.

Eu poderia ter pensado que era tráfego de busca. Mas havia algo estranho. Nos últimos dias eu estava mexendo muito no blog e, durante o trabalho com IA, abri várias vezes tanto o servidor local quanto a URL pública.

Então precisei fazer a pergunta.

Isso era tráfego real?

Ou meu próprio trabalho também estava sendo contado?

O contador era honesto demais

Primeiro revisei a estrutura.

O contador criado em /pt-BR/devlog/github-pages-blog/github-pages-blog-visitor-counter/ usa Cloudflare Worker e D1.

Quando a página carrega, o JavaScript envia /track ao Worker. O Worker incrementa counters, page_counters e dedupe_views no D1. Google Analytics entra só como baseline; os incrementos novos ficam no D1.

O problema era que a estrutura era honesta demais.

Se um navegador abria uma página, contava.

O servidor local também apontava para o Worker de produção. A lista de origins permitidos do Worker incluía localhost:4000 e 127.0.0.1:4000.

Então uma prévia local podia aumentar o contador real de produção.

A deduplicação também era por visitorId + path. A mesma página no mesmo navegador é deduplicada por 10 minutos, mas abrir vários posts diferentes conta cada um.

O D1 deixou isso claro.

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

Em 2026-06-08, muitos Daily Review antigos e posts naver-* tinham sido tocados uma vez. Parecia mais uma sessão de revisão do que leitores reais.

Trabalho local deve mostrar, não contar

A primeira correção foi simples.

No local, as estatísticas podem aparecer, mas /track não deve ser enviado.

localhost
127.0.0.1
::1

Nesses ambientes, o script cliente pula o tracking.

Mas confiar só no cliente é frágil. Se o JS mudar ou alguém enviar uma requisição manual, o problema volta. Então o Worker também só conta /track vindo do origin de produção.

TRACK_ALLOWED_ORIGIN=https://hyuk.blog

Requisições de origins locais agora são ignoradas com origin_not_tracked.

Também adicionei um opt-out para revisar produção sem sujar o contador.

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

Não é uma área administrativa escondida. É só um interruptor para verificar a página pública sem alterar os números.

As estatísticas não precisavam ser privadas

No começo pensei em uma página de analytics só para mim.

Mas não precisava.

Se eu não salvo IP bruto, User-Agent bruto, full referrer URL nem logs de eventos individuais, a página pode ser pública. Basta guardar valores agregados que podem ser mostrados.

Então mudei a direção.

Não uma página privada de logs.

Uma página pública de estatísticas do blog.

/analytics/

Adicionei no menu superior e também no pequeno bloco de visitas da sidebar.

O D1 guarda só agregados

A nova tabela é simples.

analytics_daily_dimensions

date
dimension
value
count
updated_at

Quando um page view é realmente contado, o Worker classifica dimensões públicas e acumula por dia.

As dimensões incluem:

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

O ponto importante é o que não é salvo.

O referrer é guardado como domínio, não como URL completa. O User-Agent é classificado em browser, OS e device. IP não é salvo.

Não é um warehouse analítico rigoroso. É um painel público de fluxo para um blog pessoal.

Hoje, mês, total e período personalizado

No começo pensei só em hoje / mês / total, como o contador existente.

Mas uma página de estatísticas precisa de intervalos.

A API /analytics aceita:

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

Aqui, total significa o total desde que analytics_daily_dimensions começou a coletar em 2026-06-09. Não é o mesmo total da sidebar, que ainda inclui o baseline do GA.

Não misturei esses dois sentidos.

Primeiro, usável no celular

Páginas de estatísticas quebram fácil no mobile.

Uma tabela grande fica apertada rápido. Por isso usei cartões com listas de barras.

No topo ficam só quatro números.

Período selecionado
Hoje
Este mês
Total

Abaixo ficam cartões por dimensão.

No mobile, os botões de período viram duas linhas, os KPIs ficam em duas colunas e os cartões detalhados viram uma coluna. O formulário de período personalizado também fica vertical.

No desktop, os KPIs ficam em uma linha e os cartões em duas colunas.

Verifiquei no navegador. Não havia overflow horizontal nem erros no console.

O que foi verificado

As verificações foram:

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

Depois do deploy, /analytics?range=today respondeu corretamente.

A nova tabela agregada ainda estava vazia. Isso é esperado. O analytics detalhado começa a preencher com visitas públicas reais depois do deploy.

Também testei tracking vindo de origin local.

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

Agora revisar o blog localmente não incrementa o contador de produção.

De contador de visitas para analytics público

No começo eram só três números pequenos.

Hoje, mês, total.

Mas operando de verdade, o mais importante não era o número em si. Era se o número estava limpo. E, para um blog público, mostrar fluxo agregado seguro combina melhor do que esconder uma página privada de logs.

Não é contabilidade exata.

Mas agora responde perguntas mais úteis.

Quais posts estão sendo lidos?

De quais países vêm as visitas?

Mobile ou desktop domina?

É busca, direto ou referral?

E, principalmente, quanto ruído do meu próprio trabalho deve ficar fora?

É para isso que existe /analytics/.

Deixe um comentário