Technique

Intégration RevenueCat : De Zéro aux Abonnements en Quelques Heures

Youcef 4 février 2026

Intégration RevenueCat : De Zéro aux Abonnements en Quelques Heures

J’ai shippé 3 apps avec RevenueCat. À chaque fois, l’intégration devient plus rapide.

Muse Otter a pris 4 heures de zéro à des abonnements fonctionnels sur iOS et Android.

Voici comment.


Pourquoi RevenueCat

Avant RevenueCat, j’ai passé des semaines sur StoreKit 1, puis StoreKit 2, puis Google Billing Library. APIs différentes. Edge cases différents. Maux de tête différents.

RevenueCat te donne :

QuoiPourquoi Ça Compte
Un seul SDKMême code pour iOS, Android et Web
Validation des reçusPas de code serveur nécessaire
État d’abonnementGère renouvellements, annulations, périodes de grâce
WebhooksSync temps réel vers ton backend
AnalyticsRevenus, churn, LTV out of the box

Le calcul : 2 semaines d’implémentation native vs 4 heures avec RevenueCat. Choix facile.


L’Architecture

Voici comment Muse Otter gère les abonnements :

┌─────────────┐    Achat     ┌─────────────┐
│ App Flutter │──────────────►│  RevenueCat │
│             │               │             │
│ purchases_  │   Entitle-    │  (gère les  │
│ flutter     │◄──────────────│   stores)   │
└──────┬──────┘    ments      └──────┬──────┘
       │                             │
       │ Lecture depuis              │ Événements
       │ Firestore                   │ Webhook
       ▼                             ▼
┌─────────────────────────────────────────────┐
│                 FIRESTORE                    │
│                                              │
│  users/{userId}                              │
│  └── subscriptionStatus: free | pro | lifetime │
│                                              │
│         ══ Source de vérité unique ══        │
└─────────────────────────────────────────────┘

Insight clé : L’app lit le statut d’abonnement depuis Firestore, pas RevenueCat. Le webhook garde Firestore synchronisé.


Étape 1 : Setup RevenueCat (30 min)

Configuration Dashboard

  1. Créer l’app dans le dashboard RevenueCat
  2. Ajouter les produits :
    • monthly_10 — 9,99$/mois
    • yearly_80 — 79,99$/an
  3. Créer l’entitlement : Muse Otter Pro
  4. Créer l’offering : default
  5. Attacher les produits à l’offering

App Store / Play Store

Configurer les produits dans App Store Connect et Google Play Console. Les IDs doivent correspondre exactement.


Étape 2 : Intégration Flutter (1 heure)

Installer le SDK

# pubspec.yaml
dependencies:
  purchases_flutter: ^9.10.0

Initialiser

Future<void> initRevenueCat() async {
  await Purchases.setLogLevel(LogLevel.debug);

  PurchasesConfiguration config;
  if (Platform.isIOS) {
    config = PurchasesConfiguration('appl_your_api_key');
  } else {
    config = PurchasesConfiguration('goog_your_api_key');
  }

  await Purchases.configure(config);
}

Login Utilisateur

Future<void> loginUser(String firebaseUid) async {
  await Purchases.logIn(firebaseUid);
}

Important : Utilise ton Firebase UID comme user ID RevenueCat. Ça lie tout ensemble.

Récupérer les Offerings

Future<Offerings?> getOfferings() async {
  try {
    return await Purchases.getOfferings();
  } catch (e) {
    logger.e('Failed to fetch offerings: $e');
    return null;
  }
}

Faire un Achat

Future<bool> purchasePackage(Package package) async {
  try {
    await Purchases.purchasePackage(package);
    return true;
  } on PurchasesErrorCode catch (e) {
    if (e != PurchasesErrorCode.purchaseCancelledError) {
      logger.e('Purchase failed: $e');
    }
    return false;
  }
}

Étape 3 : Webhook Firebase (2 heures)

C’est là que Firestore devient la source de vérité.

Cloud Function

import { onRequest } from 'firebase-functions/v2/https';
import { getFirestore } from 'firebase-admin/firestore';

export const revenueCatWebhook = onRequest(
  { region: 'europe-west1', secrets: ['REVENUECAT_WEBHOOK_SECRET'] },
  async (req, res) => {
    // Vérifier l'autorisation
    const authHeader = req.headers.authorization;
    if (authHeader !== process.env.REVENUECAT_WEBHOOK_SECRET) {
      res.status(401).send('Unauthorized');
      return;
    }

    const event = req.body;
    const userId = event.app_user_id;
    const eventType = event.type;

    // Mapper l'événement au statut d'abonnement
    let newStatus: string | null = null;

    switch (eventType) {
      case 'INITIAL_PURCHASE':
      case 'RENEWAL':
      case 'UNCANCELLATION':
        newStatus = 'pro';
        break;
      case 'EXPIRATION':
        newStatus = 'free';
        break;
      // CANCELLATION: pas de changement (user garde l'accès jusqu'à expiration)
      // BILLING_ISSUE: pas de changement (période de grâce)
    }

    if (newStatus) {
      const userRef = getFirestore().doc(`users/${userId}`);
      const userDoc = await userRef.get();

      // Ne pas écraser les statuts protégés
      const currentStatus = userDoc.data()?.subscriptionStatus;
      if (currentStatus === 'donation' || currentStatus === 'lifetime') {
        res.status(200).send('Protected status - no change');
        return;
      }

      await userRef.update({
        subscriptionStatus: newStatus,
        subscriptionUpdatedAt: new Date(),
      });
    }

    res.status(200).send('OK');
  }
);

Configurer le Webhook dans RevenueCat

  1. Aller dans Project Settings → Integrations → Webhooks
  2. Ajouter l’URL de ta Cloud Function
  3. Configurer le header d’autorisation
  4. Sélectionner les événements : INITIAL_PURCHASE, RENEWAL, EXPIRATION, CANCELLATION, UNCANCELLATION

Étape 4 : L’App Lit depuis Firestore (30 min)

Provider Riverpod

@riverpod
Stream<bool> isPro(IsProRef ref) {
  final user = ref.watch(currentUserProvider);
  if (user == null) return Stream.value(false);

  return FirebaseFirestore.instance
    .doc('users/${user.uid}')
    .snapshots()
    .map((doc) {
      final status = doc.data()?['subscriptionStatus'] ?? 'free';
      return status != 'free';
    });
}

Protéger les Features Pro

class ProGate extends ConsumerWidget {
  final Widget child;
  final Widget fallback;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isPro = ref.watch(isProProvider);

    return isPro.when(
      data: (pro) => pro ? child : fallback,
      loading: () => fallback,
      error: (_, __) => fallback,
    );
  }
}

Les Patterns Qui Marchent

1. Firestore comme Source de Vérité

Ne vérifie pas le SDK RevenueCat à chaque fois. Écris le statut dans Firestore une fois, lis depuis là toujours.

Pourquoi : Plus rapide, marche offline, une seule source de vérité.

2. Statuts Protégés

Certains users ont l’accès gratuit (testeurs, juges de concours, supporters). Protège-les :

if (currentStatus === 'donation' || currentStatus === 'lifetime') {
  // Ne rien changer
  return;
}

3. Login avec Firebase UID

Utilise toujours le même user ID dans RevenueCat et Firebase. Rend les webhooks triviaux.

4. Soft Paywall d’Abord

Ne bloque pas immédiatement. Montre la valeur, puis demande l’argent :

Gratuit: 20 messages/jour
Pro: Illimité

Les users atteignent la limite naturellement. Ensuite le paywall semble juste.


Résultats

Système d’abonnement Muse Otter :

  • 4 heures pour intégrer
  • 100% couverture événements via webhooks
  • Marche offline (lit depuis le cache Firestore)
  • Statuts protégés pour les attributions manuelles
  • A/B testable via Firebase Remote Config

Essaie

Le tier gratuit de RevenueCat gère jusqu’à 2.5k$/mois. C’est assez pour valider ton produit.

Ne construis pas d’infrastructure d’abonnement. Ship juste.

Le meilleur système de paiement est celui que t’as pas à maintenir.

Commencez à réfléchir. L'Otter s'occupe du reste.

30 secondes pour capturer. 7 minutes pour revoir. Des patterns à découvrir pour toute une vie.

Aussi sur iPad avec Apple Pencil

Gratuit pour commencer. Sans carte bancaire.