Subscrições RevenueCat: 16 casos extremos e noites sem dormir
Pontos-chave: Implementar assinaturas in-app com RevenueCat parece simples: três níveis, um SDK. Na realidade, são 16 casos de limite de mudanças de plano, obrigações legais francesas sobre a exibição de preços com impostos incluídos (TTC), e um singleton PurchaseService que deve gerenciar a restauração de compras em tempo real. Aqui está tudo o que a documentação não diz.
Quando decidi monetizar o TAMSIV, a escolha do RevenueCat foi óbvia. Eles gerenciam a complexidade das lojas para você — os recibos do Google Play, a validação do servidor, o rastreamento de assinaturas. Bem, em teoria.
Na prática, passei três semanas na implementação. Não por causa do próprio RevenueCat (o SDK é bem feito), mas por causa de todos os casos de limite que ninguém menciona nos tutoriais. Aqui está o feedback completo.
Como estruturar os níveis de assinatura de um aplicativo de IA?
TAMSIV oferece três planos:
- Free — Acesso a funções básicas com limites diários. Suficiente para descobrir o aplicativo, mas não para uso intensivo.
- Pro — Tudo desbloqueado: geração de imagens de IA, STT em nuvem Deepgram (melhor que o nativo em ambientes ruidosos), memorandos ilimitados, todas as vozes TTS.
- Team — A camada colaborativa completa: grupos hierárquicos em 6 níveis, atribuições, listas de verificação de grupo, permissões avançadas.
A escolha de três níveis não é arbitrária. Estudos mostram que três opções maximizam a conversão — o efeito de ancoragem empurra os usuários para o plano do meio. O Free atrai, o Pro converte, o Team monetiza as equipes.
O arquivo planLimits.ts
No código, um arquivo config/planLimits.ts centraliza todos os feature gates. Cada funcionalidade verifica o plano ativo antes de ser executada:
// Exemplo simplificado
const PLAN_LIMITS = {
free: { dailyVoiceTasks: 5, aiImages: 0, cloudSTT: false },
pro: { dailyVoiceTasks: -1, aiImages: 20, cloudSTT: true },
team: { dailyVoiceTasks: -1, aiImages: 50, cloudSTT: true },
};
Este arquivo único é a fonte da verdade. Sem condições if (plan === 'pro') espalhadas no código — tudo passa pelos limites configurados. Quando modifico um plano, toco em um único arquivo.
Quais são os 16 casos de limite de mudanças de plano?
É aqui que a coisa fica complicada. Um usuário pode:
- Fazer upgrade: Free → Pro, Free → Team, Pro → Team
- Fazer downgrade: Team → Pro, Team → Free, Pro → Free
- Mudar de período: Mensal → Anual, Anual → Mensal
- Combinar os dois: Upgrade + mudança de período
- Cancelar: Com acesso até o final do período
- Reativar: Antes ou depois da expiração
- Restaurar: Em um novo telefone
Contei 16 casos distintos. Para cada um, é preciso gerenciar:
- O momento da ativação: Um upgrade entra em vigor imediatamente. Um downgrade é adiado para o final do período atual.
- O rateio: O Google Play calcula automaticamente o rateio para upgrades. Mas você deve exibi-lo corretamente na UI.
- A atualização dos feature gates em tempo real: Quando um usuário faz upgrade, as novas funcionalidades devem ser desbloqueadas instantaneamente, sem reiniciar o aplicativo.
- A exibição correta: O plano certo, a data de expiração certa, o preço certo, o status certo.
Três dias de testes para cobrir tudo. É tedioso, metódico e absolutamente indispensável. Um único caso perdido, e você recebe um e-mail de um usuário furioso que pagou por um Pro e ainda está no Free.
Como gerenciar as obrigações legais francesas para assinaturas?
Se você vende na França, a DGCCRF impõe regras estritas:
- Preço TTC obrigatório: Na França, os preços são sempre exibidos com impostos incluídos (TTC - Toutes Taxes Comprises) para os consumidores. As lojas fornecem os preços localizados, mas você deve verificar se a exibição respeita a legislação.
- Menção "Prix TTC": O texto deve ser explícito.
- Link para os CGV: As Condições Gerais de Venda devem ser acessíveis a partir da tela de pagamento.
- Informação sobre o direito de retratação: Para compras digitais, o direito de retratação se aplica sob certas condições. Você deve informar o usuário.
- Duração do compromisso: O usuário deve saber claramente se está assinando um plano mensal ou anual, e como cancelá-lo.
Não respeitar essas regras é arriscar a rejeição do aplicativo pelo Google ou uma multa da DGCCRF. Os CGV e menções legais do TAMSIV estão acessíveis no site e no aplicativo.
Como arquitetar o PurchaseService em React Native?
Tudo passa por um singleton PurchaseService. Este é o padrão que uso para todos os serviços no TAMSIV — ConversationService, CalendarService, GamificationService, todos seguem o mesmo modelo (falo sobre isso no artigo sobre refatoração de arquitetura limpa).
O PurchaseService faz 4 coisas:
- Inicializa o RevenueCat na inicialização do aplicativo com a chave API do projeto.
- Escuta as mudanças de estado: upgrade, downgrade, expiração, restauração. Cada mudança aciona uma atualização dos feature gates.
- Expõe o plano ativo via um hook:
usePurchase()retorna o plano atual, a data de expiração e as funcionalidades disponíveis. - Sincroniza com o Supabase: O plano ativo também é armazenado no banco de dados para que o backend possa verificar as permissões (por exemplo, limitar o número de solicitações de voz para o plano Free).
A restauração de compras
Este é o caso mais complicado. Um usuário troca de telefone, reinstala o aplicativo e espera encontrar sua assinatura Pro. O RevenueCat gerencia isso via restorePurchases(), mas o tempo é crítico: a restauração pode levar alguns segundos, durante os quais o usuário está no modo Free. Se você não gerenciar esse estado intermediário, o usuário verá uma tela "Fazer upgrade para Pro" quando já é Pro.
A solução: um estado explícito de "carregamento" na inicialização, que bloqueia a exibição dos feature gates até que o RevenueCat tenha confirmado o plano ativo.
Quais métricas seguir para assinaturas?
O RevenueCat fornece um painel excelente. As métricas que acompanho diariamente:
- MRR (Monthly Recurring Revenue): A receita recorrente mensal. A métrica principal.
- Conversão Free → Pro: Qual porcentagem dos usuários gratuitos faz upgrade?
- Churn rate: Quantos assinantes cancelam a cada mês?
- Trial conversion: Se você oferece um teste gratuito, qual porcentagem converte?
- Revenue per user: A receita média por usuário ativo.
Essas métricas alimentam o painel de administração que construí para monitorar a saúde do projeto em tempo real.
Quais erros evitar com o RevenueCat?
Aqui estão as armadilhas em que caí:
- Não testar em sandbox: O Google Play tem um modo sandbox para compras. Use-o sistematicamente. Um bug de pagamento em produção significa um reembolso + um usuário perdido.
- Esquecer a migração de usuários existentes: Se você adicionar assinaturas a um aplicativo existente, os usuários atuais devem ser migrados para o plano Free corretamente. Sem downgrade silencioso.
- Não gerenciar o modo avião: O RevenueCat armazena em cache o plano ativo localmente. Mas se o usuário estiver offline durante um upgrade, os feature gates podem estar dessincronizados. Preveja um mecanismo de reconciliação ao retornar online.
- Ignorar os webhooks: O RevenueCat envia webhooks para cada evento (compra, cancelamento, renovação). O backend deve processá-los para manter o Supabase sincronizado.
Como o sistema de indicação interage com as assinaturas?
TAMSIV tem um sistema de indicação que oferece um mês gratuito de Pro ou Team quando um usuário convida um amigo. Isso adiciona uma camada de complexidade: o código promocional do RevenueCat deve ser aplicado corretamente, o mês gratuito deve começar no momento certo, e o retorno ao plano original deve ser transparente.
A interação indicação + assinatura gerou 3 dos 16 casos de limite mencionados acima. É uma excelente alavanca de crescimento, mas exige uma implementação cuidadosa.
FAQ
Por que RevenueCat em vez da API nativa do Google Play Billing?
A API nativa do Google Play Billing é complexa, mal documentada e muda regularmente. O RevenueCat abstrai essa complexidade com um SDK limpo, um painel analítico e suporte multiplataforma (Android + iOS). O custo (gratuito até $2.5k MRR, depois 1% da receita) é insignificante em comparação com o tempo de desenvolvimento economizado.
É preciso oferecer um teste gratuito?
Depende do seu modelo. Para o TAMSIV, o plano Free já é um teste permanente das funcionalidades básicas. Um teste gratuito do Pro por 7 dias está em teste — os primeiros dados mostram uma taxa de conversão mais alta, mas também um churn maior após o teste.
Como exibir os preços em várias moedas?
O Google Play fornece os preços localizados via API. O RevenueCat os expõe em offerings.current.availablePackages. Você não precisa gerenciar a conversão de moedas por conta própria — a loja sempre exibe o preço local. Na França, é em euros TTC.
O que acontece se o Google Play estiver fora do ar?
O RevenueCat armazena em cache o plano ativo no dispositivo. Se o Google Play estiver temporariamente indisponível, o usuário mantém seu acesso. O risco é mínimo porque o Google Play tem um uptime de 99.99%. Mas o PurchaseService prevê um fallback para o cache local em caso de timeout da API.
Como gerenciar o IVA para vendas internacionais?
É a loja que gerencia o IVA, não você. O Google Play coleta e repassa o IVA de acordo com o país do comprador. Você recebe o valor líquido. Mas você ainda deve exibir os preços TTC no aplicativo e respeitar as regras de exibição do país do usuário.