Suivre le churn avec les notifications en temps réel de Google Play
Mesurer le churn des abonnements Android avec les notifications en temps réel de Google Play : configuration Pub/Sub, sens de chaque événement, indicateurs.
Google Play informe votre backend des changements d’abonnement via les notifications en temps réel pour les développeurs (real-time developer notifications, RTDN), publiées sur un topic Google Cloud Pub/Sub. Elles sont la base de tout suivi sérieux du churn pour une appli Android : qui a résilié, qui a un problème de facturation, qui a mis en pause, qui est vraiment parti.
Il y a un piège qui conditionne tout le reste : une notification dit seulement que quelque chose a changé. Ce guide couvre la configuration, le traitement de chaque message, la correspondance entre types de notification et indicateurs de churn, et les erreurs qui faussent les chiffres. Il s’appuie sur la documentation de Google : configurer les RTDN, la référence RTDN, le cycle de vie des abonnements et la référence de l’API pour purchases.subscriptionsv2 (tous consultés en novembre 2026).
Configurer les notifications
Le guide de configuration de Google détaille les étapes :
- Créez un topic Pub/Sub dans un projet Google Cloud.
- Donnez au compte de service
google-play-developer-notifications@system.gserviceaccount.comle rôle Pub/Sub Publisher sur le topic. - Créez un abonnement sur le topic : push vers un endpoint HTTPS de votre backend, ou pull depuis un worker.
- Dans la Play Console, saisissez le nom du topic pour votre appli et cliquez sur Send Test Message.
- Choisissez les types de notification : abonnements et achats annulés seulement, ou tout, y compris les produits ponctuels.
Accusez réception de chaque message. Pour les abonnements pull, Google indique d’accuser réception des messages récupérés « pour éviter une livraison répétée par Cloud Pub/Sub » ; pour le push, un code de réponse de succès vaut accusé de réception.
Traiter un message
Chaque message Pub/Sub a un champ data en base64. Décodé, il contient version, packageName, eventTimeMillis et exactement un élément parmi subscriptionNotification, oneTimeProductNotification, voidedPurchaseNotification, pendingRefundReviewNotification ou testNotification.
Une notification d’abonnement ne porte qu’un notificationType et un purchaseToken. La référence de Google est explicite : vous « devez appeler la Google Play Developer API après avoir reçu des notifications en temps réel pour obtenir le statut complet », parce que les notifications « ne vous donnent pas d’informations complètes sur l’achat ». Le guide du cycle de vie qualifie purchases.subscriptionsv2.get de « source de vérité pour la gestion des abonnements ».
La chaîne de traitement est donc :
- Recevoir, vérifier les doublons sur
messageId(Google le recommande), stocker le message brut, accuser réception. - Appeler
purchases.subscriptionsv2.getavec le purchase token. - Stocker l’état obtenu sous forme d’instantané, avec le type de notification et
eventTimeMillis. - Mettre à jour vos droits d’accès et vos indicateurs à partir de l’instantané, pas de la notification seule.
Gardez en tête que le purchase token ne fonctionne que jusqu’à 60 jours après l’expiration. Récupérez l’état à l’arrivée de la notification, pas des semaines plus tard.
Les types de notification d’abonnement
D’après la référence RTDN :
| Code | Type | Ce qui s’est passé |
|---|---|---|
| 1 | SUBSCRIPTION_RECOVERED |
Rétabli après un account hold, ou reprise après une pause |
| 2 | SUBSCRIPTION_RENEWED |
Un abonnement actif s’est renouvelé |
| 3 | SUBSCRIPTION_CANCELED |
Résilié, volontairement ou non |
| 4 | SUBSCRIPTION_PURCHASED |
Nouvel abonnement acheté |
| 5 | SUBSCRIPTION_ON_HOLD |
Entré en account hold |
| 6 | SUBSCRIPTION_IN_GRACE_PERIOD |
Entré en grace period |
| 7 | SUBSCRIPTION_RESTARTED |
L’utilisateur a restauré un abonnement résilié pas encore expiré |
| 9 | SUBSCRIPTION_DEFERRED |
Date de renouvellement repoussée |
| 10 | SUBSCRIPTION_PAUSED |
La pause a pris effet |
| 11 | SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED |
Pause programmée ou modifiée |
| 12 | SUBSCRIPTION_REVOKED |
Révoqué avant l’expiration |
| 13 | SUBSCRIPTION_EXPIRED |
Expiré |
| 18 | SUBSCRIPTION_CANCELLATION_SCHEDULED |
Résiliation d’un paiement échelonné programmée pour la fin de l’engagement |
| 20 | SUBSCRIPTION_PENDING_PURCHASE_CANCELED |
Une transaction en attente a été annulée |
Il en existe quelques autres (éléments modifiés, mises à jour de changement de prix, consentement à une hausse de prix par paliers). Le code 8 est obsolète.
Les états qui comptent pour le churn
Le champ subscriptionState de l’API est plus fiable que le type de notification pour compter. Le guide du cycle de vie décrit ce que chaque état signifie pour l’accès :
| État | L’utilisateur a-t-il accès ? | Signification pour le churn |
|---|---|---|
SUBSCRIPTION_STATE_ACTIVE |
Oui | Abonné |
SUBSCRIPTION_STATE_IN_GRACE_PERIOD |
Oui | À risque : paiement échoué |
SUBSCRIPTION_STATE_ON_HOLD |
Non | À risque : paiement échoué, accès bloqué |
SUBSCRIPTION_STATE_PAUSED |
Non | En pause, pas parti |
SUBSCRIPTION_STATE_CANCELED |
Jusqu’à expiryTime |
À risque : renouvellement arrêté |
SUBSCRIPTION_STATE_EXPIRED |
Non | Parti |
La grace period et l’account hold ont des valeurs par défaut à connaître. La grace period est activée par défaut sur tous les forfaits de base à renouvellement automatique. L’account hold est aussi activé par défaut, avec une durée que Google calcule comme 60 jours moins la grace period. Les deux se modifient dans la Play Console. Avant le début de l’account hold, Google fait des tentatives de débit supplémentaires pendant jusqu’à 48 heures.
Des événements aux indicateurs de churn
Compter le churn à l’expiration
SUBSCRIPTION_CANCELED signifie que le renouvellement s’est arrêté, pas que l’utilisateur est parti. Il garde l’accès jusqu’à expiryTime, et peut restaurer son abonnement (SUBSCRIPTION_RESTARTED). Comptez le churn sur SUBSCRIPTION_EXPIRED, et utilisez les résiliations comme indicateur avancé.
Séparer churn volontaire et involontaire
Le canceledStateContext de la ressource d’abonnement indique qui a résilié :
userInitiatedCancellation: volontaire. Il peut aussi contenir la réponse de l’utilisateur à l’enquête de résiliation.systemInitiatedCancellation: résilié par le système, « par exemple à cause d’un problème de facturation ». C’est votre churn involontaire.developerInitiatedCancellation: vous avez résilié.replacementCancellation: remplacé par un nouvel abonnement, par exemple après un changement d’offre. Ce n’est pas du churn.
Le chemin de la facturation a une séquence reconnaissable : SUBSCRIPTION_IN_GRACE_PERIOD, puis SUBSCRIPTION_ON_HOLD, puis soit SUBSCRIPTION_RECOVERED, soit, à la fin de l’account hold, SUBSCRIPTION_CANCELED immédiatement suivi de SUBSCRIPTION_EXPIRED.
Ne pas compter les pauses comme du churn
SUBSCRIPTION_RECOVERED est envoyé à la fois quand un abonnement sort de l’account hold et quand il reprend après une pause. Vérifiez l’état précédent avant de le compter comme une récupération de facturation.
Gérer les changements d’offre et les réinscriptions
Les montées en gamme, les passages à une offre inférieure et les réinscriptions dans l’appli avant l’expiration créent un nouvel achat avec un nouveau token. Le nouvel abonnement a un linkedPurchaseToken qui pointe vers l’ancien. Si vous ne suivez pas ces liens, chaque changement d’offre ressemble à un abonné parti et un nouvel abonné.
Les réinscriptions depuis le Play Store après l’expiration sont différentes : Google indique qu’elles ne portent pas de linkedPurchaseToken, mais la réponse de l’API inclut outOfAppPurchaseContext avec le token expiré tant que vous n’avez pas accusé l’achat. Comptez-les comme des réactivations.
Les révocations
SUBSCRIPTION_REVOKED signifie que l’accès a pris fin plus tôt : vous l’avez révoqué, ou l’achat a fait l’objet d’un chargeback. L’état passe à expiré. Rapportez-le à part du churn normal, avec les achats annulés.
Un rapport mensuel
- Actifs en début de période : abonnements aux états actif, grace period, ou résilié mais pas encore expiré.
- Churn volontaire : expirations dont le contexte est initié par l’utilisateur.
- Churn involontaire : expirations dont le contexte est initié par le système.
- Taux de récupération de facturation : abonnements entrés en grace period ou en account hold puis rétablis, rapportés à tous ceux qui y sont entrés.
- Restaurations :
SUBSCRIPTION_RESTARTED. - En pause : nombre, et combien reprennent.
- Réactivations : réinscriptions depuis le Play Store et réinscriptions dans l’appli après l’expiration.
Les formules générales se trouvent dans comment calculer le taux de churn.
Erreurs courantes
- Se fier au seul type de notification. Récupérez toujours l’état de l’abonnement.
- Compter les résiliations comme du churn. Cela gonfle le churn et masque les restaurations.
- Ignorer les linked purchase tokens. Les changements d’offre deviennent du faux churn.
- Appeler l’API trop tard. Les tokens cessent de fonctionner 60 jours après l’expiration.
- Ne pas accuser réception des messages Pub/Sub. Vous recevez des doublons et gaspillez votre quota d’API.
- Pas d’ID de compte obfusqué à l’achat. Vous ne pouvez pas croiser les données de Play avec vos propres données utilisateur.
Le faire avec NoChurn
Vous dirigez vos notifications en temps réel Play vers NoChurn et lui donnez un compte de service ayant accès à votre Play Console. NoChurn récupère l’état de l’abonnement pour chaque événement, suit les linked purchase tokens, sépare churn volontaire, churn de facturation et révocations, et tient une chronologie par client, rattachée grâce à l’ID de compte obfusqué que vous définissez à l’achat. Grace period, account hold et résiliations alimentent le score de churn de 0 à 100, et vous pouvez ajouter vos propres attributs par API. Google garde les paiements, les relances et le bouton de résiliation. Voir NoChurn + Google Play.