Misurare il churn con le App Store Server Notifications V2
Misurare il churn iOS con le App Store Server Notifications V2: configurazione, significato delle notifiche, churn volontario o da fatturazione, lacune.
App Store Connect ti dà report su vendite e abbonamenti, ma se vuoi numeri sul churn di cui fidarti e su cui agire (chi se n’è andato, perché e chi sta per farlo), ti serve un tuo registro di eventi. Su iOS, quel registro arriva dalle App Store Server Notifications V2: il server di Apple chiama il tuo ogni volta che un abbonamento cambia stato.
Questa guida mostra come configurarle in modo affidabile, come ogni notifica corrisponde a una metrica di churn e come colmare le lacune. Si basa sulla documentazione di Apple: Enabling App Store Server Notifications, Responding to App Store Server Notifications, il riferimento di notificationType e Get Notification History (tutti consultati a novembre 2026).
Configurare l’endpoint
I requisiti di Apple sono pochi:
- Un URL HTTPS sul tuo server, con TLS 1.2 o successivo. Se indichi una porta, deve essere 443 oppure 1024 o superiore.
- Scegli la versione 2 per l’URL in App Store Connect. Apple consiglia la V2 per tutte le nuove implementazioni. Puoi impostare un URL sandbox separato o riusare lo stesso.
- Se il tuo firewall usa una lista di indirizzi consentiti, aggiungi
17.0.0.0/8, che copre sia sandbox sia produzione. - Restituisci un HTTP da 200 a 206 quando hai salvato la notifica. Qualsiasi altro codice conta come errore.
- Testa con l’endpoint Request a Test Notification, che invia una notifica
TEST, poi controlla il risultato con Get Test Notification Status.
Ogni notifica arriva come signedPayload in formato JWS. Verifica la firma prima di fidarti di qualsiasi contenuto, poi decodifica il payload.
Consegna, nuovi tentativi e duplicati
Le cose vanno storte: deploy, interruzioni, timeout. La documentazione di Apple descrive cosa succede in quei casi.
- Nuovi tentativi. Per la V2, se il tuo server non restituisce un codice di successo, Apple riprova cinque volte, a 1, 12, 24, 48 e 72 ore dal tentativo precedente. I nuovi tentativi avvengono solo in produzione; in sandbox Apple invia ogni notifica una volta.
- Duplicati. Ogni payload ha un
notificationUUID, che Apple dice di usare per identificare i duplicati. Salvalo con un vincolo di unicità e ignora le ripetizioni. - Cronologia. Get Notification History restituisce le notifiche che Apple ha tentato di inviare negli ultimi 180 giorni in produzione (30 giorni in sandbox), 20 record per pagina, con filtro facoltativo per tipo, subtype o transazione. Eseguilo dopo ogni interruzione.
- Lo stato attuale. I record della cronologia riflettono lo stato al momento dell’invio. Per lo stato attuale di un abbonamento, Apple rimanda a Get All Subscription Statuses.
Un buon schema: salva prima la notifica grezza, restituisci 200, poi elaborala da una coda. Non fare mai lavoro lento prima di rispondere ad Apple.
Cosa c’è in una notifica
Il payload decodificato ha un notificationType, un subtype facoltativo, un signedDate e un oggetto data. Per gli abbonamenti, data contiene:
signedTransactionInfo: la transazione (prodotto, date, offerta usata, eventuale revoca).signedRenewalInfo: cosa succederà al prossimo rinnovo, compresiautoRenewStatus,expirationIntent,isInBillingRetryPeriod,gracePeriodExpiresDateedeligibleWinBackOfferIds.status: lo stato dell’abbonamento alla data disignedDate:1attivo,2scaduto,3in billing retry,4in Billing Grace Period,5revocato.
Per collegare un abbonamento a uno dei tuoi utenti, imposta un appAccountToken all’acquisto. Apple lo restituisce nelle informazioni di transazione e di rinnovo. Senza di esso, hai solo gli ID di transazione di Apple.
Associare le notifiche alle metriche di churn
Ecco come i tipi di notifica di Apple si traducono nei numeri che la maggior parte dei team segue. Le descrizioni seguono la tabella notificationType di Apple.
| Metrica | Notifica | Subtype |
|---|---|---|
| Nuovo abbonato | SUBSCRIBED |
INITIAL_BUY |
| Abbonato di ritorno (comprese le offerte win-back) | SUBSCRIBED |
RESUBSCRIBE |
| Rinnovo | DID_RENEW |
nessuno |
| Intenzione di disdire (rinnovo disattivato) | DID_CHANGE_RENEWAL_STATUS |
AUTO_RENEW_DISABLED |
| Disdetta annullata | DID_CHANGE_RENEWAL_STATUS |
AUTO_RENEW_ENABLED |
| Errore di fatturazione | DID_FAIL_TO_RENEW |
GRACE_PERIOD o nessuno |
| Fatturazione recuperata | DID_RENEW |
BILLING_RECOVERY |
| Churn volontario | EXPIRED |
VOLUNTARY |
| Churn involontario (fatturazione) | EXPIRED |
BILLING_RETRY |
| Churn da aumento di prezzo | EXPIRED |
PRICE_INCREASE |
| Prodotto ritirato dalla vendita | EXPIRED |
PRODUCT_NOT_FOR_SALE |
| Rimborso | REFUND |
nessuno, o SEATS per il multiseat |
| Downgrade programmato | DID_CHANGE_RENEWAL_PREF |
DOWNGRADE |
L’expirationIntent nelle informazioni di rinnovo dà la stessa suddivisione come numero: 1 disdetta del cliente, 2 errore di fatturazione, 3 nessun consenso a un aumento di prezzo o alla conversione di un’offerta, 4 prodotto non disponibile, 5 altro (riferimento).
Conta il churn alla scadenza, non alla disdetta
Sull’App Store una disdetta ferma solo il rinnovo. Il cliente mantiene l’accesso fino alla fine del periodo e può riattivare il rinnovo. Quindi:
- Usa
AUTO_RENEW_DISABLEDcome indicatore anticipatore: abbonamenti a rischio in questo periodo. - Usa
EXPIREDcome evento di churn: abbonamenti effettivamente terminati.
Se conti il churn su AUTO_RENEW_DISABLED, lo sovrastimerai e perderai ogni cliente che ha cambiato idea.
Il churn da fatturazione ha una coda lunga
Il riferimento di Apple dice che dopo un rinnovo fallito l’App Store continua a ritentare la fatturazione per 60 giorni, o finché il cliente non sistema la fatturazione o disdice. Con il Billing Grace Period attivo, il cliente mantiene l’accesso durante il grace period; GRACE_PERIOD_EXPIRED ne segna la fine mentre i tentativi continuano. Un abbonamento in billing retry non è ancora né attivo né perso. Riportalo in una categoria a sé, e contalo come churn solo quando arriva EXPIRED con BILLING_RETRY.
Nota anche recentSubscriptionStartDate nelle informazioni di rinnovo: Apple lo calcola ignorando le interruzioni di 60 giorni o meno, il che è comodo per anzianità e coorti.
Un semplice report del churn dalle notifiche
Con ogni notifica salvata, un report mensile si riduce a una manciata di query:
- Attivi a inizio mese: abbonamenti il cui ultimo stato prima del mese era attivo, in grace period o in billing retry (decidi una volta se il retry conta come attivo e mantieni la scelta).
- Persi: notifiche
EXPIREDdel mese, suddivise per subtype. - Tasso di churn volontario:
EXPIRED/VOLUNTARYdiviso per gli attivi a inizio mese. - Tasso di churn involontario:
EXPIRED/BILLING_RETRYdiviso per gli attivi a inizio mese. - Recupero della fatturazione:
DID_RENEW/BILLING_RECOVERYdiviso perDID_FAIL_TO_RENEWsulla stessa coorte. - A rischio ora: abbonamenti le cui ultime informazioni di rinnovo hanno il rinnovo automatico disattivato e una scadenza futura.
- Riattivazioni:
SUBSCRIBED/RESUBSCRIBE.
Per le formule generali e le trappole (mescolare piani mensili e annuali, contare le prove), vedi come calcolare il tasso di churn.
Lacune comuni
- Ascoltare solo la V1, o solo la produzione. Testa la V2 in sandbox prima di passare in produzione; Apple consiglia proprio quest’ordine.
- Nessun job di riconciliazione. Anche con i nuovi tentativi, esegui Get Notification History periodicamente e dopo gli incidenti.
- Ignorare In famiglia e i gruppi.
SUBSCRIBEDeREVOKEscattano anche per i membri della famiglia e le postazioni di gruppo. Decidi se contano come abbonati nelle tue metriche. - Trattare i rimborsi come disdette. Un
REFUNDchiude l’accesso e restituisce i soldi; riportalo separatamente. - Nessun
appAccountToken. Ottieni numeri App Store puliti ma non puoi incrociarli con dati di utilizzo, piano o acquisizione, ed è da lì che arrivano le spiegazioni del churn.
Farlo con NoChurn
NoChurn ti dà un URL da incollare come endpoint delle App Store Server Notifications. Verifica e deduplica ogni notifica, mantiene la cronologia per cliente (associata tramite il tuo appAccountToken), separa churn volontario, da fatturazione e da aumento di prezzo, e segnala il rinnovo automatico disattivato come segnale di rischio precoce nel punteggio di churn da 0 a 100. Puoi aggiungere i tuoi attributi via API per vedere cosa determina il churn. Apple tiene fatturazione, nuovi tentativi e pulsante di disdetta. Vedi NoChurn + App Store.