Abonnements RevenueCat : 16 cas limites et nuits blanches
Points cles : Implementer des abonnements in-app avec RevenueCat semble simple : trois tiers, un SDK. En realite, c'est 16 cas limites de changements de plan, des obligations legales francaises sur l'affichage TTC, et un singleton PurchaseService qui doit gerer la restauration des achats en temps reel. Voici tout ce que la documentation ne dit pas.
Quand j'ai decide de monetiser TAMSIV, le choix de RevenueCat s'est impose. Ils gerent la complexite des stores pour toi — les receipts Google Play, la validation serveur, le tracking des abonnements. Enfin, en theorie.
En pratique, j'ai passe trois semaines sur l'implementation. Pas a cause de RevenueCat lui-meme (le SDK est bien fait), mais a cause de tous les cas limites que personne ne mentionne dans les tutoriels. Voici le retour d'experience complet.
Comment structurer les tiers d'abonnement d'une app IA ?
TAMSIV propose trois plans :
- Free — Acces aux fonctions de base avec des limites quotidiennes. Assez pour decouvrir l'app, pas assez pour un usage intensif.
- Pro — Tout est debloque : generation d'images IA, STT cloud Deepgram (meilleur que le natif dans les environnements bruyants), memos illimites, toutes les voix TTS.
- Team — La couche collaborative complete : groupes hierarchiques sur 6 niveaux, assignations, checklists de groupe, permissions avancees.
Le choix de trois tiers n'est pas arbitraire. Les etudes montrent que trois options maximisent la conversion — l'effet d'ancrage pousse les utilisateurs vers le plan du milieu. Le Free attire, le Pro convertit, le Team monetise les equipes.
Le fichier planLimits.ts
Cote code, un fichier config/planLimits.ts centralise toutes les feature gates. Chaque fonctionnalite verifie le plan actif avant de s'executer :
// Exemple simplifie
const PLAN_LIMITS = {
free: { dailyVoiceTasks: 5, aiImages: 0, cloudSTT: false },
pro: { dailyVoiceTasks: -1, aiImages: 20, cloudSTT: true },
team: { dailyVoiceTasks: -1, aiImages: 50, cloudSTT: true },
};
Ce fichier unique est la source de verite. Pas de conditions if (plan === 'pro') dispersees dans le code — tout passe par les limites configurees. Quand je modifie un plan, je touche un seul fichier.
Quels sont les 16 cas limites des changements de plan ?
C'est la ou ca devient cauchemardesque. Un utilisateur peut :
- Upgrader : Free → Pro, Free → Team, Pro → Team
- Downgrader : Team → Pro, Team → Free, Pro → Free
- Changer de periode : Mensuel → Annuel, Annuel → Mensuel
- Combiner les deux : Upgrade + changement de periode
- Annuler : Avec acces jusqu'a la fin de la periode
- Reactiver : Avant ou apres l'expiration
- Restaurer : Sur un nouveau telephone
J'ai compte 16 cas distincts. Pour chacun, il faut gerer :
- Le moment d'activation : Un upgrade prend effet immediatement. Un downgrade est differe a la fin de la periode en cours.
- Le prorata : Google Play calcule automatiquement le prorata pour les upgrades. Mais tu dois l'afficher correctement dans l'UI.
- La mise a jour des feature gates en temps reel : Quand un utilisateur upgrade, les nouvelles fonctionnalites doivent se debloquer instantanement, sans redemarrage de l'app.
- L'affichage correct : Le bon plan, la bonne date d'expiration, le bon prix, le bon statut.
Trois jours de tests pour tout couvrir. C'est ennuyeux, methodique, et absolument indispensable. Un seul cas manque, et tu recois un email d'un utilisateur furieux qui a paye pour un Pro et qui est toujours en Free.
Comment gerer les obligations legales francaises pour les abonnements ?
Si tu vends en France, la DGCCRF impose des regles strictes :
- Prix TTC obligatoire : En France, on affiche toujours les prix TTC (Toutes Taxes Comprises) pour les consommateurs. Les stores fournissent les prix localises, mais tu dois verifier que l'affichage respecte la legislation.
- Mention "Prix TTC" : Le texte doit etre explicite.
- Lien vers les CGV : Les Conditions Generales de Vente doivent etre accessibles depuis l'ecran de paiement.
- Information sur le droit de retractation : Pour les achats numeriques, le droit de retractation s'applique sous certaines conditions. Tu dois en informer l'utilisateur.
- Duree d'engagement : L'utilisateur doit savoir clairement s'il souscrit un abonnement mensuel ou annuel, et comment le resilier.
Ne pas respecter ces regles, c'est risquer un rejet de l'app par Google ou une amende de la DGCCRF. Les CGV et mentions legales de TAMSIV sont accessibles depuis le site web et depuis l'app.
Comment architecturer le PurchaseService en React Native ?
Tout passe par un singleton PurchaseService. C'est le pattern que j'utilise pour tous les services dans TAMSIV — ConversationService, CalendarService, GamificationService, tous suivent le meme modele (j'en parle dans l'article sur le refactoring clean architecture).
Le PurchaseService fait 4 choses :
- Initialise RevenueCat au demarrage de l'app avec la cle API du projet.
- Ecoute les changements d'etat : upgrade, downgrade, expiration, restauration. Chaque changement declenche une mise a jour des feature gates.
- Expose le plan actif via un hook :
usePurchase()retourne le plan courant, la date d'expiration, et les fonctionnalites disponibles. - Synchronise avec Supabase : Le plan actif est aussi stocke en base de donnees pour que le backend puisse verifier les permissions (par exemple, limiter le nombre de requetes vocales pour le plan Free).
La restauration des achats
C'est le cas le plus piege. Un utilisateur change de telephone, reinstalle l'app, et s'attend a retrouver son abonnement Pro. RevenueCat gere ca via restorePurchases(), mais le timing est critique : la restauration peut prendre quelques secondes, pendant lesquelles l'utilisateur est en mode Free. Si tu ne geres pas cet etat intermediaire, l'utilisateur voit un ecran "Upgrade vers Pro" alors qu'il est deja Pro.
La solution : un etat "chargement" explicite au demarrage, qui bloque l'affichage des feature gates jusqu'a ce que RevenueCat ait confirme le plan actif.
Quelles metriques suivre pour les abonnements ?
RevenueCat fournit un dashboard excellent. Les metriques que je suis quotidiennement :
- MRR (Monthly Recurring Revenue) : Le revenu recurrent mensuel. La metrique reine.
- Conversion Free → Pro : Quel pourcentage des utilisateurs gratuits upgradent ?
- Churn rate : Combien d'abonnes annulent chaque mois ?
- Trial conversion : Si tu offres un essai gratuit, quel pourcentage convertit ?
- Revenue per user : Le revenu moyen par utilisateur actif.
Ces metriques alimentent le dashboard admin que j'ai construit pour monitorer la sante du projet en temps reel.
Quelles erreurs eviter avec RevenueCat ?
Voici les pieges dans lesquels je suis tombe :
- Ne pas tester en sandbox : Google Play a un mode sandbox pour les achats. Utilise-le systematiquement. Un bug de paiement en production, c'est un remboursement + un utilisateur perdu.
- Oublier la migration des utilisateurs existants : Si tu ajoutes des abonnements a une app existante, les utilisateurs actuels doivent etre migres vers le plan Free proprement. Pas de downgrade silencieux.
- Ne pas gerer le mode avion : RevenueCat met en cache le plan actif localement. Mais si l'utilisateur est hors-ligne pendant un upgrade, les feature gates peuvent etre desynchronisees. Prevois un mecanisme de reconciliation au retour online.
- Ignorer les webhooks : RevenueCat envoie des webhooks pour chaque evenement (achat, annulation, renouvellement). Le backend doit les traiter pour garder Supabase synchronise.
Comment le systeme de parrainage interagit-il avec les abonnements ?
TAMSIV a un systeme de parrainage qui offre un mois gratuit de Pro ou Team quand un utilisateur invite un ami. Ca ajoute une couche de complexite : le code promo RevenueCat doit etre applique correctement, le mois gratuit doit commencer au bon moment, et le retour au plan original doit etre transparent.
L'interaction parrainage + abonnement a genere 3 des 16 cas limites mentionnes plus haut. C'est un excellent levier de croissance, mais ca demande une implementation soignee.
FAQ
Pourquoi RevenueCat plutot que l'API native Google Play Billing ?
L'API native Google Play Billing est complexe, mal documentee, et change regulierement. RevenueCat abstrait cette complexite avec un SDK propre, un dashboard analytique, et le support multi-plateforme (Android + iOS). Le cout (gratuit jusqu'a $2.5k MRR, puis 1% du revenu) est negligeable compare au temps de dev economise.
Faut-il proposer un essai gratuit ?
Ca depend de ton modele. Pour TAMSIV, le plan Free est deja un essai permanent des fonctionnalites de base. Un essai gratuit du Pro pendant 7 jours est en test — les premieres donnees montrent un taux de conversion plus eleve, mais aussi un churn plus important apres l'essai.
Comment afficher les prix dans plusieurs devises ?
Google Play fournit les prix localises via l'API. RevenueCat les expose dans offerings.current.availablePackages. Tu n'as pas a gerer la conversion de devises toi-meme — le store affiche toujours le prix local. En France, c'est en euros TTC.
Que se passe-t-il si Google Play est down ?
RevenueCat met en cache le plan actif sur le device. Si Google Play est temporairement indisponible, l'utilisateur garde son acces. Le risque est minime car Google Play a un uptime de 99.99%. Mais le PurchaseService prevoit un fallback vers le cache local en cas de timeout de l'API.
Comment gerer la TVA pour les ventes internationales ?
C'est le store qui gere la TVA, pas toi. Google Play collecte et reverse la TVA selon le pays de l'acheteur. Tu recois le montant net. Mais tu dois quand meme afficher les prix TTC dans l'app et respecter les regles d'affichage du pays de l'utilisateur.