O Navistron rastreia todas as sessões de jogo — mesmo as que o jogador não registra com um nome. Mas diferente da maioria dos sistemas de analytics, o tracking do Navistron é completamente anônimo por design: sem IP, sem cookies, sem fingerprinting de dispositivo, sem localStorage de identificação. Neste artigo, vamos explorar como esse sistema funciona, quais dados são capturados, como são categorizados e para que servem.

Por Que Rastrear Sessões Anônimas?

Nem todo jogador quer registrar seu nome no ranking. Alguns preferem jogar casualmente sem se comprometer com um nome. Outros simplesmente fecham a aba ao terminar. Sem tracking anônimo, esses jogadores seriam invisíveis — o sistema não saberia quantas partidas realmente acontecem, quais tiers são alcançados, quanto tempo as pessoas jogam, ou qual é a distribuição real de dificuldade.

O tracking anônimo permite que o Navistron tenha métricas completas: o total real de partidas é totalRegistered + totalAnonymous, e estatísticas como tempo médio de jogo ou distribuição de tiers consideram todos os jogadores, não apenas os que registraram score.

Unregistered vs Unknown: Dois Tipos de Sessão Anônima

O Navistron classifica sessões anônimas em dois tipos, baseados na ação do jogador após o game over:

  • Unregistered — O jogador viu a tela de game over, teve a oportunidade de digitar um nome, e clicou "Skip". Foi uma decisão consciente de não registrar. Os dados são enviados via fetch padrão para POST /api/anonymous-sessions com type: "Unregistered".
  • Unknown — O jogador não tomou nenhuma ação. Isso inclui: fechar a aba do navegador, navegar para outra URL, ou clicar em "Jogar de Novo" sem ter clicado Save nem Skip. A razão do abandono é desconhecida (daí o nome).

Essa distinção é valiosa para analytics: uma alta proporção de Unregistered sugere que jogadores estão engajados mas preferem privacidade. Uma alta proporção de Unknown pode indicar que o fluxo de game over não está engajando — o jogador abandona antes de interagir.

O Mecanismo de Captura: pendingSession e sessionResolved

O sistema usa duas variáveis de controle no engine do jogo: pendingSession (objeto com dados da partida) e sessionResolved (flag booleana). Quando a nave é destruída, endGame() cria o pendingSession com 7 campos de gameplay e define sessionResolved = false.

A sessão permanece "pendente" até que uma dessas ações ocorra:

  1. Save & Ranking — Chama DB.save() na collection scores. Define sessionResolved = true, pendingSession = null. Nenhuma sessão anônima é criada.
  2. Skip — Chama AnonymousDB.save({ ...pendingSession, type: 'Unregistered' }). Define sessionResolved = true, pendingSession = null.
  3. beforeunload — Se pendingSession existir e !sessionResolved, chama AnonymousDB.saveBeacon({ ...pendingSession, type: 'Unknown' }).
  4. startGame() — Se ainda houver sessão não resolvida, salva como "Unknown" via AnonymousDB.save() antes de resetar tudo.

Isso garante que toda partida gera dados: ou vai para scores (registrado) ou para anonymous_sessions (anônimo). A única exceção é se o navegador crashar antes do beforeunload ser disparado.

sendBeacon: Coletar Dados ao Fechar a Aba

O navigator.sendBeacon() é a peça-chave para capturar sessões Unknown. Diferente do fetch tradicional (que é cancelado quando a página fecha), o sendBeacon é "fire-and-forget" — o navegador garante que a requisição é enviada mesmo durante a destruição da aba.

No Navistron, o handler de beforeunload serializa os dados do pendingSession em um Blob com tipo application/json e envia para /api/anonymous-sessions. Não há resposta — o sendBeacon não retorna uma Promise. Se a requisição falhar (navegador muito antigo, crash forçado), os dados se perdem silenciosamente — mas na vasta maioria dos casos, funciona.

As sessões Unregistered (Skip) e Unknown por novo jogo usam fetch normal, pois a página continua aberta e pode aguardar a resposta.

Os 9 Campos Capturados por Sessão Anônima

Cada documento na collection anonymous_sessions contém exatamente 9 campos:

  • type (String) — "Unregistered" ou "Unknown". Validado no servidor: valores inválidos são convertidos para "Unknown"
  • score (Number) — Pontuação final. Default: 0
  • tier (Number) — Índice do tier alcançado (0–6). Default: 0
  • tierName (String) — Nome legível ("TIER I" a "TIER VII"). Default: "TIER I"
  • boosts (Number) — Total de boosts coletados. Default: 0
  • spread (Number) — Nível de spread final. Default: 1
  • time (Number) — Segundos de sobrevivência (inteiro). Default: 0
  • difficulty (Number) — Multiplicador de dificuldade final. Default: 1
  • playedAt (Date) — Timestamp gerado no servidor via new Date()

Note que não há campo name — essa é a diferença fundamental em relação à collection scores. Sessões anônimas não têm identificador de jogador. Todos os campos numéricos são sanitizados com Number() e defaults seguros no servidor.

Validação do Campo type no Servidor

O servidor não confia no cliente para o valor de type. A API de sessões anônimas valida explicitamente: ['Unregistered', 'Unknown'].includes(body.type) ? body.type : 'Unknown'. Se alguém enviar um tipo inventado (ex: "VIP", "Bot" ou qualquer string arbitrária), o servidor converte para "Unknown". Isso previne poluição dos dados de telemetria e garante que os dashboards sempre funcionem com apenas dois tipos.

Privacidade por Design: O Que NÃO É Coletado

O tracking anônimo do Navistron foi projetado para ser o oposto de surveillance analytics:

  • Sem endereço IP — Nenhuma API armazena o IP do jogador em nenhuma collection
  • Sem cookies — Nenhum cookie de rastreamento é emitido pelo jogo ou pelo site
  • Sem device fingerprinting — Nenhum canvas fingerprint, WebGL hash, ou identificador de hardware
  • Sem localStorage de tracking — O jogo não persiste identificadores locais entre sessões
  • Sem conta ou login — O nome de piloto (apenas em scores registrados) é voluntário e pode ser qualquer texto
  • Sem correlação entre sessões — Não há como vincular duas sessões anônimas ao mesmo jogador

O único dado semi-identificável em todo o sistema é o User-Agent, armazenado exclusivamente na collection sponsor_clicks (cliques em links de patrocinadores) — completamente separado das sessões de jogo.

Como os Dados Anônimos São Usados

Os dados da collection anonymous_sessions alimentam vários componentes do sistema:

  • Stats Pages — As páginas públicas de estatísticas usam getAggregatedStats() que combina scores + anonymous_sessions para calcular o total real de partidas, tempo total jogado e maior score (considerando ambas as fontes)
  • Dashboard — O dashboard exibe gráficos específicos para sessões anônimas: sessões por dia (empilhadas Unregistered vs Unknown), distribuição de tipo (doughnut), distribuição de tiers e de faixas de score
  • API /api/anonymous-sessions GET — Retorna 7 aggregations em paralelo: total de sessões, contagem por tipo, totais/médias de score e tempo, sessões por dia (30 dias), distribuição de tiers, últimas 15 sessões, e distribuição de scores por faixa (0–50, 50–100, ..., 50K+)

Ao combinar registrados e anônimos, o Navistron tem uma visão completa: se os anônimos representam 60% das partidas, o score médio real é diferente do score médio apenas dos registrados (que tendem a ser jogadores mais dedicados).

Impacto na Telemetria: Anônimos vs Registrados

A separação em duas collections permite análises comparativas poderosas. As stats pages mostram totalRegistered vs totalAnonymous lado a lado, revelando a proporção de jogadores que se engajam com o ranking versus os que jogam casualmente.

A função getAggregatedStats(period) executa 9 aggregations em paralelo via Promise.all(), consultando ambas as collections para combinar: tempo total ($sum: '$time' de cada), score mais alto (Math.max entre registrado e anônimo), e contagem total (totalRegistered + totalAnonymous). Pilotos únicos, distribuição de tiers, top jogadores e jogos recentes vêm apenas de scores, pois sessões anônimas não têm nome.

FAQ — Perguntas Frequentes sobre o Tracking Anônimo

Posso jogar sem nenhum dado ser salvo?

Na prática, toda partida finalizada (nave destruída) gera dados de telemetria — via Save, Skip ou beforeunload. No entanto, como os dados são puramente de gameplay (score, tier, tempo) e não contêm nenhuma informação identificável, não há impacto na sua privacidade. É impossível vincular uma sessão anônima a uma pessoa real.

Qual a proporção típica de Unregistered vs Unknown?

Varia conforme o perfil dos jogadores. Unregistered indica que o jogador interagiu com o game over (viu os botões e escolheu Skip). Unknown indica abandono — fechou a aba ou começou novo jogo sem agir. Consulte o dashboard público para ver a distribuição atual.

Os dados anônimos influenciam o ranking?

Não. Sessões anônimas são armazenadas na collection anonymous_sessions, completamente separada da collection scores que alimenta o ranking. Anônimos contribuem apenas para estatísticas agregadas (total de partidas, tempo total, distribuição de dificuldade), nunca para posições no ranking.

O sendBeacon funciona em todos os navegadores?

O navigator.sendBeacon() é suportado por todos os navegadores modernos (Chrome, Firefox, Safari, Edge). Pode não funcionar em navegadores muito antigos ou em cenários extremos (crash forçado do processo). Quando não disponível, a sessão Unknown daquela partida se perde — o que é aceitável dado que são dados agregados, não individuais.

Como uma sessão anônima é diferente de um score registrado?

A diferença é de um campo: scores registrados têm name (nome do piloto), sessões anônimas têm type ("Unregistered"/"Unknown"). Os outros 8 campos (score, tier, tierName, boosts, spread, time, difficulty, playedAt) são idênticos. Ambos usam sanitização server-side e timestamp gerado no servidor.