Retenção D1, D7 e D30: por que o gráfico de hoje está vazio, e o que fazer
Retenção mede quem volta depois da primeira visita em 1, 7 e 30 dias. O eixo é a data da PRIMEIRA partida, não a do retorno — e é por isso que o D30 de hoje só existe daqui a um mês.
Produzido com IA a partir das fontes citadas abaixo, e conferido por checagens automáticas contra essas mesmas fontes. Nenhuma pessoa leu este texto antes da publicação. Política Editorial

Você abre o painel de retenção pela primeira vez, olha o gráfico de D30, e a ponta direita está vazia. A reação natural é achar que tem algo errado — com o jogo, com a instrumentação, com a Roblox.
Não tem. O vazio é a coisa funcionando, e entender por quê é o que destrava a leitura de todo o resto do painel. Este guia explica o que a retenção mede, como o painel organiza o dado, e o que a documentação recomenda para mexer no número.
O problema
A definição é curta: retenção mede quantos usuários voltam ao jogo depois da primeira visita, em 1, 7 e 30 dias.
O que confunde não é a definição, é o eixo. O eixo horizontal dos coortes é a data da primeira partida do usuário novo — não a data em que ele voltou. A documentação explica o motivo: isso dá uma visão mais precisa de como a mudança feita num dia afeta a retenção daquele grupo ao longo do tempo.
Traduzindo para o dia a dia: quando você olha um ponto no gráfico de D7, aquele ponto não é sobre quem jogou naquela data. É sobre quem estreou naquela data e voltou uma semana depois. O ponto pertence ao dia da estreia, e é por isso que ele diz algo sobre o que o seu jogo era naquele dia.
Com os três gráficos lado a lado, a mesma data conta três histórias do mesmo grupo: quem estreou ali e voltou no dia seguinte, quem voltou depois de uma semana, e quem voltou depois de um mês.
E aí o vazio se explica sozinho. O dado das datas mais recentes nos gráficos de D7 e D30 pode estar vazio simplesmente porque o tempo ainda não passou. O D7 de um grupo aparece sete dias depois da estreia dele; o D30 aparece trinta dias depois. A ponta direita do gráfico de D30 vai estar sempre vazia — é o mês que ainda não aconteceu.
Isso tem uma consequência operacional que vale gravar: não dá para medir o D30 de uma mudança que você fez ontem. Se a sua decisão depende de D30, ela depende de esperar.
Passo a passo
1. Chegue ao painel. Em Creations, escolha o jogo, e no menu Analytics à esquerda escolha Retention. Para jogo de grupo, é preciso ter permissão de analytics no grupo — o que costuma ser a razão de alguém da equipe não conseguir ver nada.
2. Leia os três gráficos como um só. Ache uma data e leia as três linhas dela. Um D1 bom com D7 ruim é um problema diferente de um D1 ruim — o primeiro é falta de motivo para voltar na semana, o segundo é falta de motivo para voltar no dia seguinte.
3. Desça até a tabela de coortes. A tabela de coortes de usuário novo fica no fim do painel de retenção, e é a parte mais útil e menos olhada.
Há duas visões. O coorte diário mostra quantos usuários novos foram retidos nos primeiros dez dias. O coorte semanal acompanha dez semanas, agrupando por semana de entrada, de segunda a domingo.
A diferença de uso é direta: o diário mostra o formato da queda logo depois da estreia; o semanal mostra se o jogo segura gente por mais de dois meses.
4. Use os coortes para medir mudanças. É para isso que eles existem: acompanhar o impacto de atualização grande, evento ou campanha. A pergunta que eles respondem, e que nenhuma métrica agregada responde, é se quem chegou durante o evento ficou mais tempo do que quem já estava.
5. Cruze com dinheiro. Cada coorte traz métricas de funil, entre elas o tempo de jogo acumulado em sete dias por usuário, a taxa de conversão de pagante acumulada em sete dias, e a receita por usuário acumulada em trinta dias.
É aqui que a análise deixa de ser acadêmica. Um evento que trouxe muita gente que não monetiza e um evento que trouxe menos gente que monetiza bem aparecem iguais na contagem de jogadores, e completamente diferentes na tabela de coortes.
Artefato
O módulo abaixo instrumenta o funil da primeira sessão, que é a parte que o painel não faz por você. O painel diz que o D1 está baixo; ele não diz em qual passo do seu loop as pessoas desistiram.
Ele segue a receita oficial na ordem: listar os passos do loop, acompanhar a taxa de conclusão de cada um, acompanhar também o que deu errado, e apontar a maior queda.
Dois detalhes de desenho valem explicação. O primeiro: ele só mede quem está na primeira sessão — quem já jogou antes atravessa o funil rápido e sujaria a medida. O segundo: marcar um passo é idempotente e recusa pulo de ordem, porque passo pulado quase sempre é bug de chamada, não comportamento de jogador, e um funil com dado sujo é pior que nenhum.
Erro comum
O erro mais comum de leitura é entrar em pânico com o mergulho depois de um pico de jogadores.
O padrão é este: você faz uma campanha, ou entra num sort de destaque, e chegam muitos usuários novos de uma vez. No dia seguinte, o gráfico de retenção mergulha naquela data — D1, D7 e D30 juntos.
A documentação diz o que isso é, com todas as letras: um resultado típico e temporário depois de uma grande entrada de usuários novos. Faz sentido. Jogador que chegou por curiosidade, por anúncio ou por acaso é, em média, menos propenso a voltar que quem chegou procurando exatamente o seu jogo. O denominador cresce mais rápido que o numerador, e a taxa cai sem que nada no jogo tenha piorado.
O erro caro é reagir a esse mergulho mudando o jogo. Você conserta algo que não estava quebrado, e ainda por cima atribui a recuperação natural da curva ao conserto — aprendendo uma lição errada que vai custar caro na próxima vez.
A leitura correta é comparar coortes com coortes: o grupo da campanha contra o grupo da semana anterior, na mesma tabela. Se o grupo da campanha retém pior, a pergunta é sobre a origem do tráfego, não sobre o jogo.
O segundo erro de leitura é mais silencioso: comparar D1 de datas que não são comparáveis. Fim de semana, feriado escolar e dia de evento trazem público diferente do de uma terça à tarde, e a curva reflete isso. Comparar terça com terça e sábado com sábado responde perguntas; comparar ontem com hoje responde quase nada.
E há um terceiro, que é de janela: tirar conclusão de um coorte que ainda está se formando. Um ponto de D7 que apareceu hoje é sobre gente que estreou há uma semana — ele está completo. Um ponto de D7 sem dado não é um número ruim, é ausência de número, e tratá-lo como zero puxa qualquer média para baixo. Se você exporta o dado para uma planilha, essa distinção precisa sobreviver à exportação, porque célula vazia e célula com zero se parecem demais.
Próximo passo
Para mexer no D1, a documentação aponta três frentes: loop principal, experiência de primeira vez e desempenho.
O loop principal são as ações que o usuário repete para progredir numa mesma sessão — num jogo de adotar bichos, adotar, treinar e subir de nível; num tycoon, administrar o negócio, equilibrar recursos e competir com outros. O trabalho sobre ele tem três passos: identificar os passos e deixá-los claros e divertidos, equilibrar a dificuldade para evitar frustração e tédio, e recompensar quem completa com retorno, moeda, item e conquista.
A experiência de primeira vez é como o usuário novo vive esse loop pela primeira vez, e as recomendações são quatro: tutorial breve ou informação contextual como dicas de tela; evitar tutorial longo, porque o objetivo é chegar à diversão rápido; entregar um momento de alegria quando o loop é completado pela primeira vez; e mostrar uma prévia do progresso possível se ele for repetido.
E existe um alvo numérico que vale escrever na parede: cinco minutos ou menos para o jogador chegar à diversão depois de entrar. É um teste que dá para fazer hoje, com um cronômetro, sem painel nenhum — entre no seu jogo como se fosse a primeira vez e marque quanto tempo leva. Se passar de cinco minutos, você já sabe onde trabalhar antes de o próximo D1 aparecer.
Fontes
- Retention | Documentation - Roblox Creator Hub — consultada em
Artefato pronto pra usar
-- ServerScriptService: o funil da PRIMEIRA sessão.
--
-- A recomendação oficial para melhorar D1 tem quatro passos, e os três
-- últimos dependem de instrumentação: listar os passos do loop,
-- acompanhar a taxa de conclusão de cada um, acompanhar também o que dá
-- errado, e achar a maior queda.
--
-- Este módulo faz a parte de medir. Ele NÃO substitui o painel de
-- analytics: ele responde a pergunta que o painel não responde, que é
-- "em qual PASSO do meu loop as pessoas desistem".
local Players = game:GetService("Players")
local Funil = {}
-- Os passos do SEU loop, na ordem. Trocar pelos seus.
local PASSOS = { "adotou", "treinou", "subiu_de_nivel" }
local indiceDe = {}
for i, nome in PASSOS do
indiceDe[nome] = i
end
-- Contagem da sessão do servidor. Para valer entre servidores, mande
-- estes números para onde você já manda telemetria.
local chegaram = {} -- passo -> quantos alcancaram
local negativos = {} -- rotulo -> quantas vezes
local entradaEm = {}
local function novo(player)
-- só instrumenta quem está na PRIMEIRA sessão; quem já jogou antes
-- passa pelo funil rápido e sujaria a medida.
if player:GetAttribute("JaJogou") then
return
end
entradaEm[player] = os.clock()
player:SetAttribute("PassoDoFunil", 0)
end
-- Chame quando o jogador COMPLETAR um passo. Idempotente: repetir o
-- mesmo passo não conta duas vezes, e pular passo não é aceito.
function Funil.marcar(player, nome)
local alvo = indiceDe[nome]
if not alvo then
warn("passo desconhecido no funil: " .. tostring(nome))
return
end
local atual = player:GetAttribute("PassoDoFunil")
if atual == nil or atual >= alvo then
return
end
if alvo ~= atual + 1 then
-- pulo de passo quase sempre é bug de chamada, não do jogador
warn("funil fora de ordem: " .. nome .. " depois de " .. atual)
return
end
player:SetAttribute("PassoDoFunil", alvo)
chegaram[nome] = (chegaram[nome] or 0) + 1
if alvo == #PASSOS then
local segundos = os.clock() - (entradaEm[player] or os.clock())
print(string.format("loop completo em %.0f s", segundos))
end
end
-- Chame no que der ERRADO: morreu, perdeu a luta, fechou o menu sem
-- comprar. A recomendação oficial é acompanhar os dois lados.
function Funil.negativo(rotulo)
negativos[rotulo] = (negativos[rotulo] or 0) + 1
end
-- Onde a maior queda está, em porcentagem de quem chegou ao passo anterior.
function Funil.relatorio()
local linhas = {}
local anterior = nil
for _, nome in PASSOS do
local n = chegaram[nome] or 0
local taxa = anterior and anterior > 0 and (n / anterior * 100) or nil
table.insert(linhas, string.format(
"%-18s %5d %s", nome, n,
taxa and string.format("%.0f%% do passo anterior", taxa) or "-"
))
anterior = n
end
for rotulo, n in negativos do
table.insert(linhas, string.format("%-18s %5d (negativo)", rotulo, n))
end
return table.concat(linhas, "\n")
end
Players.PlayerAdded:Connect(novo)
Players.PlayerRemoving:Connect(function(player)
entradaEm[player] = nil
end)
return Funil

