SDK
Onboarding e dropout
Descubra em qual tela do seu onboarding os usuários estão desistindo. O SDK rastreia cada step e o dashboard monta o funil automaticamente.
Como funciona
Em cada tela do seu fluxo de onboarding, você chama onboardingManager.step("nome_do_step", order). Quando o usuário termina, chama complete(). O abandono é detectado automaticamente pelo servidor. Não é necessário nenhuma chamada explícita. O dashboard usa esses eventos pra montar o funil de conversão e mostrar onde o dropout tá acontecendo.
O universo do funil são os installs do período, não só quem mandou evento de onboarding. Todo usuário instalado entra na base, e a posição dele no funil vem do step mais avançado que ele reportou. Quem nunca reportou step nenhum fica parado no step 0.
Antes de começar
- O SDK precisa estar inicializado (
<PaywalloProvider>) antes de qualquer chamada. Chamar antes disso lançaONBOARDING_NOT_INITIALIZED. Se quiser garantir, useawait Paywallo.waitUntilReady()antes. - Se o SDK ainda não tem um
distinctId(init em andamento), o evento é descartado em silêncio. Mais um motivo pra esperar owaitUntilReady()em telas que aparecem logo no boot do app. - O dashboard fica em
/dropoute precisa do feature flag dropout ativo no seu app (fala com a gente se não tiver).
Marcando steps
Em cada tela do onboarding, chama step(nome, order) com um nome único e o order da tela no fluxo (0, 1, 2...). O segundo argumento é obrigatório: sem ele o backend não consegue montar a sequência do funil corretamente. Pode chamar dentro de um useEffect no mount da tela. Chamar de novo pro mesmo step (usuário voltou uma tela, por exemplo) não tem problema: o backend guarda o progresso mais avançado.
import { onboardingManager } from "@virex-tech/paywallo-sdk";
// chama em cada tela do seu onboarding, passando o order da tela
await onboardingManager.step("welcome", 0);
await onboardingManager.step("age_selection", 1);
await onboardingManager.step("goal", 2);Teste A/B
A forma recomendada de modelar variantes A/B é passar o parâmetro variantKey (string) no terceiro argumento de step(). O order permanece um inteiro indicando a posição no funil. Não misture posição e variante no mesmo número. Passe o mesmo variantKey em complete() para fechar o funil identificado pela variante correta.
import { onboardingManager } from "@virex-tech/paywallo-sdk";
// Forma recomendada para teste A/B: order inteiro (posição no funil) + variantKey (string)
await onboardingManager.step("pricing", 2, { variantKey: "control" });
await onboardingManager.step("pricing", 2, { variantKey: "variant_b" });
// Opcional: tempo gasto na tela anterior (em segundos)
await onboardingManager.step("goal", 2, { variantKey: "control", timeOnPrevS: 12 });No funil de dropout, steps com o mesmo order e variantKey diferente colapsam no step pai e aparecem como uma única barra. A comparação granular entre variantes fica por conta da tela de Testes A/B.
O campo order também aceita decimais (ex: 2.1, 2.2) como forma alternativa de identificar variantes: a parte inteira define a posição; o decimal, a variante. Prefira o variantKey pra novos fluxos: é mais legível e não sofre com arredondamento de ponto flutuante.
Passos que se dividem
Às vezes o onboarding ramifica: telas diferentes aparecem para usuários diferentes na mesma posição do fluxo. Um app de parar de fumar mostra "cigarros por dia" para fumantes e "puffs por dia" para quem usa vape; um app de peptídeos mostra uma tela para quem já tem protocolo e outra para quem não tem. Se você numerar cada tela com um orderinteiro sequencial, o funil "esparrama": a mesma etapa vira várias linhas, cada uma com só uma fração dos usuários.
A solução é dar o mesmo order inteiro à posição e um decimal a cada variante. O Paywallo faz Math.floor no order, então todas as variantes entram na mesma etapa do funil, e o decimal registra qual tela cada usuário viu (visível no detalhamento do passo).
// Ramificacao: cada usuario ve UMA das telas na mesma posicao.
// Mesmo inteiro, decimal por variante.
await onboardingManager.step("cigsPerDay", 8.1); // fumante
await onboardingManager.step("puffsPerDay", 8.2); // vape
// No funil ambos contam como "passo 8"; o decimal aparece no detalhamento.Não confunda com o variantKey de teste A/B: o variantKey é para a mesma tela testando conteúdos diferentes (ex: dois preços). O decimal é para telas genuinamente diferentes que ocupam a mesma posição por causa de uma ramificação do fluxo.
Use decimais só para telas alternativas: o usuário vê uma ou outra, nunca as duas. Telas que todos veem em sequência devem ter orders inteiros distintos.
Finalizando o fluxo
Quando o usuário chega no fim do onboarding (última tela, paywall, home), chama complete(). Isso marca o fluxo como concluído pra esse usuário, fecha o funil dele e alimenta o card de taxa de conclusão. Sem o complete() a taxa de conclusão fica em 0% mesmo com os steps chegando.
import { onboardingManager } from "@virex-tech/paywallo-sdk";
// quando o usuário termina o fluxo (chegou na última tela ou no paywall)
await onboardingManager.complete();
// Em teste A/B, passe o mesmo variantKey usado nos steps
await onboardingManager.complete({ variantKey: "variant_b" });Abandono (automático)
Não existe mais drop() no SDK. O abandono é inferido pelo servidor por tempo: se o usuário iniciou o onboarding, não chamou complete() e ficou mais de 1 hora sem avançar (sem novo step()), o servidor marca o fluxo como abandonado automaticamente. Fechar o app não conta como abandono: só o tempo sem avançar. Se o usuário voltar e mandar um novo step(), ele sai do estado de abandono e o fluxo continua normalmente.
Nomes de step
- Precisa ser uma string não vazia (senão a chamada lança
ONBOARDING_INVALID_STEP_NAME). - O agrupamento ignora maiúsculas e minúsculas:
introHomeeintrohomecaem no mesmo step. Renomear de verdade (trocar a palavra) quebra o histórico, então mantenha os nomes consistentes entre releases. - Use nomes descritivos da tela (
"age_selection","goal"), não genéricos tipo"step1". É esse nome que aparece no funil.
Exemplo completo
Um fluxo de 3 telas (welcome, age, goal):
import { useEffect } from "react";
import { onboardingManager } from "@virex-tech/paywallo-sdk";
function WelcomeScreen({ navigation }) {
useEffect(() => {
onboardingManager.step("welcome", 0);
}, []);
return (
<View>
<Text>Bem-vindo!</Text>
<Button title="Continuar" onPress={() => navigation.navigate("Age")} />
</View>
);
}
function AgeScreen({ navigation }) {
useEffect(() => {
onboardingManager.step("age_selection", 1);
}, []);
return (
<View>
<Text>Qual sua idade?</Text>
<Button title="Continuar" onPress={() => navigation.navigate("Goal")} />
</View>
);
}
function GoalScreen({ navigation }) {
useEffect(() => {
onboardingManager.step("goal", 2);
}, []);
return (
<View>
<Text>Qual seu objetivo?</Text>
<Button
title="Finalizar"
onPress={async () => {
await onboardingManager.complete();
navigation.navigate("Paywall");
}}
/>
</View>
);
}Em componentes React você também pode usar o hook useOnboarding(), que expõe os mesmos step e complete com referências estáveis:
import { useOnboarding } from "@virex-tech/paywallo-sdk";
function AgeScreen() {
const { step, complete } = useOnboarding();
useEffect(() => {
step("age_selection", 1);
}, [step]);
// ...
}Quando o funil aparece
O funil é montado a partir de um catálogo de etapas que exige massa mínima de eventos pra desenhar cada step. Se você acabou de integrar o SDK e está testando com poucos dispositivos (por exemplo, em Sandbox com 1 tester), é esperado ver a mensagem "dados insuficientes" no lugar do funil. Isso não significa que os eventos não chegaram. Eles estão sendo recebidos normalmente. O funil simplesmente aguarda amostra suficiente pra exibir as etapas com significância estatística. Confira os eventos chegando com debug: true e aguarde o volume crescer em produção.
Validando a integração
- Inicialize o SDK com
debug: truenuma build de teste: cada evento aceito loga[Paywallo:Onboarding] event emittedno console, e eventos descartados (sem distinctId) logamskipped. - No dashboard, confira se o filtro de environment no topo da página bate com o ambiente da build que você está testando. O SDK detecta sandbox e production automaticamente, e evento marcado como sandbox não aparece com o filtro Production ativo.
- Se o funil mostra um único step_0 com 100% dos usuários e conclusão 0%, o app não está enviando os eventos de onboarding. Como o universo são os installs, o funil nunca fica vazio: sem eventos, todo mundo aparece empilhado no step 0 com um nome genérico.
- O nome real de um step só aparece no funil depois que ele acumula pelo menos 20 usuários no histórico do app. Até lá a posição aparece com o nome genérico
step_N. Em app novo ou de baixo volume, é esperado ver nomes genéricos nos primeiros dias depois de integrar.
Pegadinhas
- Mande o step pro Paywallo mesmo que você já rastreie onboarding em outra ferramenta (PostHog, Firebase, etc). Evento custom com outro nome não alimenta o funil: só a família canônica emitida por
step()ecomplete()conta. complete()marca o fluxo como concluído. Chame no máximo uma vez por usuário.- Os dados não são retroativos. Usuários que passaram pelo onboarding antes da integração continuam aparecendo no step 0, e o funil só reflete os steps reais pra quem instalou uma build com o SDK chamando
step().
Essa página foi útil?
Desenvolvido e mantido por Virex