Nem todo jogador quer criar conta, digitar um nome ou interagir com qualquer tela depois de morrer. Alguns simplesmente fecham a aba. Se o seu jogo só captura dados de quem registra score, você está perdendo a maioria das partidas — e com elas, insights valiosos sobre como os jogadores realmente jogam.
A solução é um sistema de scores anônimos que captura 100% das partidas sem exigir login, cadastro ou qualquer ação do jogador. Neste tutorial, mostramos como o Navistron implementa esse sistema usando três caminhos de captura — incluindo navigator.sendBeacon para sessões abandonadas — garantindo que nenhum dado se perca.
O Problema: Dados que Você Nunca Vê
Em jogos web tradicionais, o fluxo é: jogar → morrer → digitar nome → salvar score. Mas na prática, existem três tipos de jogador:
- O competitivo — digita nome e salva. Aparece no ranking. Fácil de capturar
- O casual — joga por diversão. Quando vê a tela de game over, clica "Skip" ou "Pular". Não quer aparecer em nenhum lugar
- O fantasma — fecha a aba no instante em que morre. Não clica em nada. Para o sistema tradicional, essa partida nunca existiu
Se você só captura o primeiro tipo, está vendo uma fração distorcida dos seus jogadores. Os dados agregados ficam enviesados para cima (só quem tem scores altos se registra) e você perde a visão real do comportamento da base.
A Solução: Três Caminhos de Captura
O Navistron resolve isso com um sistema de dual-track: scores registrados vão para a coleção scores (leaderboard público), e sessões anônimas vão para anonymous_sessions (telemetria interna). Três caminhos cobrem todos os cenários:
| Cenário | Tipo de Sessão | Como é Capturada | Coleção MongoDB |
|---|---|---|---|
| Jogador salva com nome | Registrada | fetch POST para /api/scores | scores |
| Jogador clica "Skip" | Unregistered | fetch POST para /api/anonymous-sessions | anonymous_sessions |
| Jogador fecha a aba | Unknown | navigator.sendBeacon para /api/anonymous-sessions | anonymous_sessions |
| Jogador clica "Jogar de Novo" | Unknown | fetch POST (fire-and-forget, sem await) | anonymous_sessions |
Resultado: 100% das partidas são capturadas. Nenhum registro se perde, independentemente do comportamento do jogador.
Estado Interno: pendingSession e sessionResolved
O sistema funciona com duas variáveis de estado no cliente:
pendingSession— Objeto criado no game over contendo os dados da partida: score, tier (índice e nome), boosts, spread, tempo sobrevivido (inteiro) e dificuldade (float com 2 casas decimais). Ficanullquando não há dados pendentessessionResolved— Flag booleana. Começafalseno game over. Viratruequando a sessão é resolvida (salva, pulada ou capturada via beacon). Impede envio duplicado
A cada game over, pendingSession recebe 7 campos calculados do estado do jogo: score, tier (0–6), tierName ("TIER I" a "TIER VII"), boosts (total coletado), spread (nível atual), time (segundos sobrevividos) e difficulty (multiplicador na morte). O campo type ainda não existe — ele é adicionado no momento da resolução.
Caminho 1: Jogador Salva — Score Registrado
Quando o jogador digita um nome (até 20 caracteres) e clica "Salvar & Ranking":
- O nome é sanitizado:
trim(),toUpperCase(),slice(0, 20). Se vazio, recebe "ANONYMOUS" - O record é enviado via
fetchPOST para/api/scorescom o nome sessionResolved = trueependingSession = null— a sessão foi resolvida- O leaderboard abre com o score do jogador destacado e auto-scrollado
Nenhuma sessão anônima é criada. O jogador optou pelo ranking — seus dados vão para a coleção pública.
Caminho 2: Jogador Pula — Sessão "Unregistered"
Quando o jogador clica "Skip" na tela de game over:
- Verifica:
pendingSessionexiste e!sessionResolved? Se sim, continua - Adiciona
type: 'Unregistered'ao objeto e envia viaAnonymousDB.save()— umfetchPOST padrão para/api/anonymous-sessions sessionResolved = trueependingSession = null- O leaderboard abre sem destaque (o jogador não tem score no ranking)
O jogador conscientemente escolheu não aparecer. O tipo 'Unregistered' reflete essa decisão ativa.
Caminho 3: Jogador Fecha a Aba — navigator.sendBeacon
Este é o caminho mais crítico — e o mais difícil de implementar corretamente. Quando o jogador fecha a aba (ou navega para outro site), a página está sendo destruída. Chamadas fetch tradicionais são canceladas pelo navegador durante o beforeunload.
A solução é navigator.sendBeacon() — uma API projetada especificamente para enviar dados durante o encerramento da página:
- Fire-and-forget — Não retorna response. Não pode falhar. O navegador garante o envio mesmo durante unload
- Non-blocking — Não atrasa o fechamento da aba
- POST body via Blob — O dado é empacotado em um
new Blob([JSON.stringify(session)], { type: 'application/json' }) - Suporte universal — Todos os navegadores modernos suportam sendBeacon (Chrome 39+, Firefox 31+, Safari 11.1+)
O Navistron registra um listener de beforeunload que verifica: se pendingSession existe e !sessionResolved, envia via sendBeacon com type: 'Unknown'. O jogador nunca sabe que seus dados foram capturados.
Caminho 3b: Safety Net — "Jogar de Novo" Sem Salvar
Existe um quarto cenário sutil: o jogador não clica em "Salvar" nem em "Skip" — ele vai direto para "Jogar de Novo". A função startGame() inclui uma safety net:
No início de cada novo jogo, verifica se pendingSession ainda existe e !sessionResolved. Se sim, envia os dados via AnonymousDB.save() com type: 'Unknown' — mas sem await (fire-and-forget para não atrasar o início do novo jogo).
Depois, reseta pendingSession = null e sessionResolved = false para o novo ciclo de jogo.
API: Sanitização e Whitelist de Tipos
A API POST /api/anonymous-sessions aplica as mesmas regras de sanitização que o endpoint de scores registrados, com uma adição: o campo type é validado contra uma whitelist:
- Se
body.typeé'Unregistered'ou'Unknown'→ aceita - Qualquer outro valor → fallback para
'Unknown' - Todos os campos numéricos:
Number() || 0(ou|| 1para spread e difficulty) playedAt: semprenew Date()no servidor — nunca vem do cliente
O documento salvo na coleção anonymous_sessions tem 9 campos: type, score, tier, tierName, boosts, spread, time, difficulty, e playedAt.
Telemetria: Combinando Dados Anônimos e Registrados
Os dados anônimos ganham valor quando combinados com os registrados. A função getAggregatedStats() no data layer do Navistron faz queries em ambas as coleções em paralelo:
| Métrica | Fonte | Combinação |
|---|---|---|
| Total de Jogos | scores + anonymous_sessions | Soma dos dois counts |
| Tempo Total de Jogo | scores + anonymous_sessions | Soma dos totalTime de ambos |
| Maior Score | scores + anonymous_sessions | Math.max entre os dois highestScore |
| Score Médio | scores apenas | Registrados somente (mais representativo) |
| Tempo Médio | scores apenas | Registrados somente |
| Pilotos Únicos | scores apenas | Somente nomes registrados |
A página pública de telemetria exibe ambos separadamente: "Jogos Registrados" (verde) e "Sessões Anônimas" (laranja), com uma nota explicativa: "Nenhum dado pessoal é coletado — apenas métricas de gameplay."
Dashboard: Visualizando Dados Anônimos
O dashboard privado do Navistron tem uma seção dedicada "ANONYMOUS TELEMETRY" que busca dados de GET /api/anonymous-sessions — 7 aggregations paralelas do MongoDB:
- 7 cards de métricas: Total Anônimos, Unregistered ("Clicked Skip"), Unknown ("Left Without Action"), Tempo de Jogo, Score Médio, Tempo Médio, Maior Score
- Gráfico de linha empilhada: Sessions por dia nos últimos 30 dias, com Unregistered (laranja) e Unknown (rosa) empilhados
- Gráficos de rosca: Distribuição por tipo de sessão e por tier alcançado
- Gráfico de barras: Distribuição de scores em faixas (0-50, 50-100, ..., 10K+)
- Tabela de sessões recentes: 15 últimas com emoji indicador — ⏭ para Unregistered, ❓ para Unknown
Esses dados revelam padrões invisíveis: em que tier os jogadores abandonam? Qual o score médio de quem não se registra? Quantas sessões são abandonadas vs. puladas? As respostas informam decisões de design do jogo.
Privacidade: Nenhum Dado Pessoal
O sistema anônimo do Navistron não coleta nenhum dado pessoal:
- Sem IP — O endereço IP não é armazenado no documento
- Sem cookies de tracking — Nenhum cookie é definido em sessões anônimas
- Sem fingerprinting — Nenhuma informação do navegador ou dispositivo é coletada
- Sem identificadores persistentes — Cada sessão é um documento independente, sem link entre partidas do mesmo jogador
- Apenas gameplay — Os 9 campos salvos são puramente métricas do jogo: score, tier, boosts, spread, tempo, dificuldade, tipo e data
Isso mantém conformidade com regulamentações de privacidade (LGPD, GDPR) sem precisar de banners de consentimento — não há dados pessoais para consentir.
FAQ — Perguntas Frequentes sobre Scores Anônimos
O navigator.sendBeacon funciona em todos os navegadores?
Sim, em todos os navegadores modernos: Chrome 39+, Firefox 31+, Safari 11.1+, Edge (Chromium). Cobrindo mais de 98% dos usuários ativos. Para navegadores muito antigos sem suporte, a partida simplesmente não é capturada — o sistema falha silenciosamente sem impactar a experiência.
O sendBeacon pode falhar durante o fechamento da aba?
Raramente. O sendBeacon foi projetado especificamente para esse cenário — ele enfileira a requisição no browser antes da página ser destruída. O navegador garante a entrega mesmo após o unload. No Navistron, a taxa de captura de sessões Unknown é consistente com o esperado.
Por que separar "Unregistered" de "Unknown"?
Porque representam comportamentos fundamentalmente diferentes. Unregistered = o jogador viu a tela de game over e ativamente clicou "Skip". Unknown = o jogador fechou a aba sem interagir. O primeiro grupo tomou uma decisão consciente; o segundo pode ter tido problemas (crash, frustração, distração). Distinguir os dois tipos permite análise de retenção mais precisa.
Os dados anônimos afetam o ranking?
Não. Sessões anônimas vão para a coleção anonymous_sessions, que é completamente separada da coleção scores (usada pelo ranking público). Os dados anônimos alimentam apenas a telemetria agregada — totais, médias e distribuições. Nenhuma sessão anônima aparece no leaderboard.
Preciso de consentimento (LGPD/GDPR) para salvar dados anônimos?
Quando os dados são verdadeiramente anônimos (sem IP, sem cookies, sem identificadores persistentes, sem dados pessoais), geralmente não é necessário consentimento explícito sob a LGPD (Art. 12) e GDPR (Recital 26). O Navistron salva exclusivamente métricas de gameplay — score, tier, tempo — sem qualquer dado que identifique ou possa identificar o jogador. Consulte um jurista para casos específicos.
