Tracking Swarm — visitas/ações de landing pages em tempo real
Tracking Swarm
Sistema de rastreamento em tempo real das landing pages da Kodama. Snippet JS injetado na página abre WebSocket pro swarm; toda visita e ação aparece ao vivo em https://swarm.kodama.solutions/sites. Página com o snippet se auto-registra no primeiro evento — zero cadastro manual.
Implementado e deployado em prod: 2026-07-10 (commit 8bc204b no repo kodama1/swarm).
Como usar (qualquer LP)
<script src="https://swarm.kodama.solutions/t.js" data-site="minha-landing" defer></script>
data-siteopcional (default: hostname da página). Convenção: umdata-siteúnico por LP (ex:vek1-lp-pet-shop) pra cada uma virar linha própria no dashboard, em vez de agrupar tudo no hostname.- Em Next.js:
next/scriptcomstrategy="afterInteractive". - Evento manual:
swarmTrack('nome_do_evento', { qualquer: 'meta' }).
O que o snippet captura
| Evento | Quando | Meta |
|---|---|---|
pageview |
load + navegação SPA (pushState/popstate) | title, referrer |
click |
clicks em a, button, [data-track] |
tag, texto, href, data-track |
submit |
submit de form | id/name/action do form |
scroll |
milestones 25/50/75/100% (1x por pageview) | depth |
leave |
pagehide / aba escondida | duração ms, scroll máximo |
custom |
swarmTrack(...) |
livre |
Transporte: WebSocket wss://swarm.kodama.solutions/ws; fallback sendBeacon POST /collect (unload ou WS bloqueado). IDs: visitor persiste em localStorage, session em sessionStorage. Não coleta PII além de user-agent.
Visitantes únicos + geolocalização (2026-07-17)
- Fingerprint server-side estilo Plausible:
hash(dia|site|ip|ua). Quando o browser bloqueia localStorage (vid ausente/anon), o fingerprint vira ovisitor_id— antes cada pageview desses virava um "único" novo, inflando a contagem. IP cru nunca é gravado, só o hash. Salt configurável viaFP_SALT. - Bots dropados no ingest (UA regex: bot/crawl/spider/headless/curl/python-requests/...): WS recusado com code 1008, beacon aceito e descartado. Bot não vira visitante nem presença.
- Geo por IP via
geoip-lite(base MaxMind embutida, lookup local offline, cache por IP): colunascountry/region/cityem cada evento. nginx passaX-Forwarded-Forpro/wse/collect. Container tracker subiu pra 384M (base fica ~120M em RAM). - Migration:
db/migrations/0004_tracking_geo.sql. Dashboard: seção "Localização" no detalhe do site (países+cidades com bandeira, cobertura de geo) e cidade/bandeira no feed ao vivo. Eventos pré-2026-07-17 não têm geo (a página mostra a cobertura). - Gotcha: base do geoip-lite é snapshot da versão do pacote — atualizar o pacote de tempos em tempos se precisão geográfica importar.
Arquitetura
LP (t.js) ──WS──▶ tracker (Node+ws, :4322, container infra-tracker-1)
│ insert
▼
Postgres swarm (tracked_sites, track_events)
│ trigger NOTIFY 'swarm_events'
▼
dashboard Astro ──SSE──▶ página /sites (feed ao vivo)
tracker/no repo swarm: serve/t.js, ingere/ws+/collect, expõe/live(presença = conexões WS abertas = visitantes online agora) e/healthz. Sem auth (snippet público) — allowlist de event types, rate limit por conexão (40 eventos/10s), caps de tamanho.- Retenção: NENHUMA (2026-07-14) — eventos crus ficam pra sempre; são a base das análises temporais por site. O purge de 90 dias que existia foi removido de propósito. Se o volume um dia apertar o Postgres, a saída é rollup agregado + purge do cru, nunca purge silencioso.
- DB: migration
db/migrations/0003_tracking.sql—tracked_sites(auto-registro por upsert com cache de 60s) +track_events. Triggers reusamnotify_swarm_event(). - Dashboard: página
/sites(visitantes online, views/visitantes hoje, feed de ações ao vivo) → clique num site abre/sites/<key>com detalhe completo: série diária de views/visitantes/ações (7d/30d/90d/tudo), views por hora do dia (fuso SP), top páginas/referrers/clicks, submits+customs, tempo médio na página, scroll médio, feed ao vivo do site. APIs/api/track-eventse/api/track-live(proxy autenticado pro tracker interno), canais SSEtracking/sites. - nginx (VPS Hermes,
swarm.kodama.solutions):location = /t.js,= /ws(upgrade headers),= /collect→127.0.0.1:4322. Backup da conf pré-mudança em/root/swarm-nginx.bak.
Onde já é obrigatório
- vek1: issues #94–103 do
kodama1/vek1(LPs de nicho + use-case) têm seção "Tracking swarm (obrigatório)" no checklist, comdata-sitepadrãovek1-lp-<slug>. Comparison pages (#104–108) ficaram de fora por decisão de escopo — adicionar se fizer sentido. - LPs futuras publicadas pelo swarm (
deploy_landing_page) devem incluir o snippet.
Gotchas
- O ingest é público de propósito (auto-registro). Se aparecer site lixo/spam em
tracked_sites, é sódelete from tracked_sites where site_key = '...'— o cascade limpa os eventos. - Presença ("N online") vem das conexões WS vivas no tracker, não do banco — reinício do container zera a presença momentaneamente, sem perder eventos.
heartbeat/ping-pong a cada 30s derruba conexão morta; proxies não inflam a contagem.
Relacionado: projects/swarm/architecture, projects/swarm/dashboard, projects/vek1/seo-market-strategy