iOS subscription dunning and involuntary churn: recovering failed payments on the App Store
Involuntary churn from failed subscription renewals can account for 20–40% of total subscriber loss on iOS. This guide covers Apple's built-in billing retry and grace period mechanics, developer-side dunning strategies, and how to track recovery using App Store Server Notifications.
Subscription developers tracking churn on iOS tend to focus on voluntary cancellations — users who open the Settings app and deliberately cancel. But a quieter category, involuntary churn, bleeds revenue in the background every day: renewals that fail because a card has expired, a bank declines the charge, a spending limit is hit, or there's a temporary payment outage on the user's end. The user never intended to leave. They just disappeared.
Analysis published by RevenueCat has consistently shown that involuntary churn accounts for a substantial share of total subscriber loss — figures of 20–40% of churned subscribers in a cohort are commonly cited in the mobile subscription industry. For many apps, this represents the largest single fixable revenue leak: unlike voluntary cancellations (which reflect dissatisfaction with the product), involuntary churners often have no objection to paying and will resubscribe if prompted. This guide covers how Apple handles failed renewals, what you as a developer can do to complement those mechanics, and how to track what you're actually recovering.
Apple's built-in defences: grace period and billing retry
When a subscription renewal attempt fails, Apple does not immediately lapse the subscription. Two passive mechanisms give the customer time to resolve the issue before access is cut off:
Billing retry. Apple retries the failed charge automatically on a rolling schedule — roughly every 24 hours for the first few days, then at longer intervals — for up to 60 days. If any retry attempt succeeds, the subscription is reinstated and the subscriber never notices the interruption. No developer action is required for this to happen, but you will receive an App Store Server Notification (DID_RENEW with subtype BILLING_RECOVERY) when recovery occurs.
Grace period. If you have enabled the billing grace period in App Store Connect — an opt-in setting per subscription group — Apple continues to grant the subscriber access during the retry window for up to 16 days. Your app detects the IN_BILLING_RETRY_PERIOD state and continues unlocking paid features. The grace period is one of the highest-leverage settings in App Store Connect that most developers leave disabled by default. The dedicated guide on iOS grace periods and billing retry covers the mechanics in full.
These built-in tools are meaningful, but they are entirely passive. Apple does not push a notification to the user on your behalf. It does not display an in-app warning. All in-app communication is your responsibility — and that's where significant recovery opportunity is left on the table.
Developer-side dunning: the communication layer Apple leaves to you
Because Apple handles all payment processing for the App Store, you cannot retry a charge yourself, update a user's payment method, or access their card details. Your lever is communication — making the user aware of the billing problem and motivating them to open Apple's native payment management interface to resolve it. There are three channels available to you.
In-app messaging
The most direct and highest-converting intervention is a banner or modal inside your app that activates when the subscription is in a billing retry state. With StoreKit 2, detecting this is straightforward: when Product.SubscriptionInfo.RenewalState is .inBillingRetryPeriod, render a persistent UI element explaining the situation. A single, clear call to action — "Update payment method" — should open the system sheet via Product.SubscriptionInfo.showManageSubscriptionsSheet(in:).
Effective in-app dunning copy keeps the tone non-accusatory and action-oriented. "We couldn't process your renewal" reads better than "Your payment failed." Include a concrete deadline: "Your access will end on [date] unless your payment information is updated." Show this message on app launch, not hidden inside a settings submenu.
Push notifications
App Store Server Notifications v2 fires a DID_FAIL_TO_RENEW event to your server endpoint at the moment a renewal attempt fails. From your backend, you can trigger a push notification via APNs alerting the user to the billing issue. Keep copy concise and action-oriented: "Payment issue with your [App Name] subscription — tap to resolve."
Frequency discipline matters here. More than two push notifications about a single billing issue risks triggering the user to disable all notifications from your app, which has broader engagement costs. A reasonable cadence: one push at first failure, one reminder 48–72 hours later if still unresolved, then silence until the situation changes. See the post on App Store Server Notifications v2 for the endpoint setup and payload verification details.
Email or out-of-app messaging
If your app collects email addresses — either directly or through Sign in with Apple's relay address — you can send a transactional dunning email sequence. Three-email flows (at failure, day 3, day 7) are standard practice in SaaS and are generally considered transactional (not marketing) communication under most privacy frameworks. This channel becomes especially valuable for users who haven't opened the app since the billing failure occurred.
Important boundary: Never attempt to collect payment details or circumvent Apple's payment infrastructure. Your entire role in the iOS dunning loop is communication — routing users to Apple's system interface where they can update their card or payment method. Attempting to handle payment updates yourself violates App Store guidelines and puts your developer account at risk.
Tracking the lifecycle: App Store Server Notifications you need to handle
Effective dunning depends on accurate, real-time event tracking. The full involuntary churn lifecycle produces a predictable sequence of server notifications — here's what each means and what action to take:
| Notification type | Subtype | What it means | Recommended action |
|---|---|---|---|
DID_FAIL_TO_RENEW |
GRACE_PERIOD |
Renewal failed; grace period active (access continues) | Show in-app billing banner; send first push notification; continue granting access |
DID_FAIL_TO_RENEW |
(none) | Renewal failed; no grace period configured | Restrict content immediately; show in-app prompt to update payment |
DID_RENEW |
BILLING_RECOVERY |
Previously failed renewal succeeded on retry | Restore full access; optionally surface a confirmation in-app; clear any dunning UI |
EXPIRED |
BILLING_RETRY |
60-day retry window exhausted; subscription lapsed | Lock content; transition to win-back campaign with a promotional offer |
GRACE_PERIOD_EXPIRED |
— | Grace period ended without successful payment | Lock content; transition to win-back campaign |
The critical architectural point: your app should be reading subscription state from your server (which processes these notifications) rather than relying solely on local StoreKit queries. A user who resolves their billing issue on another device, or through Apple's own retry logic while the app is backgrounded, should have their access restored the next time they open the app — without needing to re-query StoreKit manually.
Measuring billing recovery rate: building a baseline
Before you can improve involuntary churn, you need to measure it. The core metric is billing recovery rate: the proportion of DID_FAIL_TO_RENEW events that eventually resolve with a BILLING_RECOVERY notification within the 60-day retry window.
Without developer intervention, Apple's built-in retry already recovers a meaningful proportion of failures — particularly in markets with stable banking infrastructure and high credit card penetration. The gains from developer-side dunning tend to be incremental but real. RevenueCat data has suggested that in-app and out-of-app messaging can improve recovery meaningfully over passive retry alone, especially in markets where payment friction is higher.
Market context matters significantly. In territories with higher rates of debit card expiry, bank-side decline rules, or payment infrastructure instability — many markets in South and Southeast Asia, Africa, and Latin America — involuntary churn rates tend to be higher and passive recovery rates lower. If your emerging-market subscriber base is substantial, developer-side dunning is especially worth implementing.
A practical measurement framework
- Log every
DID_FAIL_TO_RENEWevent with a timestamp and theoriginalTransactionId— this is your cohort start point. - Track whether each logged original transaction ID receives a
BILLING_RECOVERYevent within 60 days. - Segment by App Store storefront (the
storefrontfield in the signed transaction payload) — recovery rates differ materially by territory. - Run before/after cohort comparisons once you've implemented dunning messaging to measure your incremental lift.
When retry ends: the handoff to win-back
When EXPIRED (subtype BILLING_RETRY) or GRACE_PERIOD_EXPIRED arrives, the dunning phase is over. Apple has exhausted its retry window. The subscription is lapsed, and the subscriber would need to actively subscribe again — a payment method update alone won't reinstate them.
The moment this notification lands, switch your user-facing flow from a billing-update prompt to a win-back campaign. This is an important distinction: dunning language ("please update your payment method") is wrong once the subscription has fully expired, because updating the payment method won't restore access. The user needs to subscribe again, and for involuntary churners — who never meant to leave — the most effective offer is typically a short discounted or free trial rather than a full-price re-subscribe ask.
Implementation checklist
- Enable billing grace period in App Store Connect for all subscription groups.
- Implement App Store Server Notifications v2: set up the endpoint, verify JWS signatures, and log all events.
- Handle
IN_BILLING_RETRY_PERIODstate in your app: show a persistent in-app billing banner and continue granting access during the grace period. - Trigger one APNs push notification on first
DID_FAIL_TO_RENEWreceipt, with an optional second at 48–72 hours if unresolved. - Send a transactional dunning email sequence if you have user email addresses.
- On
EXPIRED+BILLING_RETRYorGRACE_PERIOD_EXPIRED: lock content and shift to a win-back offer flow — not a billing update prompt. - Log and segment recovery rates by storefront; compare cohorts before and after dunning is live.
Involuntary churn is unavoidable — payment failures happen across every subscription business. But treating it as a passive problem that Apple handles for you leaves recoverable revenue on the table. A well-instrumented notification pipeline and a modest amount of in-app and push messaging can meaningfully move your recovery rate, particularly in markets where payment infrastructure makes billing failures more common than developers expect.
Sources and further reading
- Apple Developer Documentation — Product.SubscriptionInfo.RenewalState (StoreKit 2)
- Apple Developer Documentation — App Store Server Notifications
- Apple — Enable Billing Grace Period (App Store Connect Help)
- RevenueCat Blog — Mobile subscription growth and monetization data
- Apple Developer Documentation — Subscriptions and Offers overview
- Phiture — Subscription churn reduction strategies for mobile apps
Share this post
Ready to put this into practice?
AppsOps is the first App Store ops dashboard — PPP-fair pricing for 175 App Store territories, AI metadata localization in 39 languages, AI screenshot localization for 14 Apple device classes, and one-click App Store Connect API push — all from one dashboard, all for $19/month.
Try AppsOps free — no card →