All articles
Playbook8 min read

Subscription cancellation reasons usually reach you before the refund request does, and Google Play hands over far more of them than Apple

Google Play records subscription cancellation reasons from its cancel survey and Apple sends only an expiration code. Here's what each store tells you, which signals point at a coming refund or chargeback, and what each one costs you.

A developer at a desk in early light checking a phone's subscription screen next to a notebook of tally marks, sorting subscription cancellation reasons

Key takeaways

  • Google Play asks subscribers why they're leaving when they cancel, and the answer reaches the developer through canceledStateContext.userInitiatedCancellation.cancelSurveyResult in purchases.subscriptionsv2.
  • Google Play's cancel survey has five answers a developer can read: not enough usage, technical issues, cost related, found a better app, and other. Free text in reasonUserInput is set only when the user picks other.
  • A SUBSCRIPTION_CANCELED notification from Google Play carries only the purchase token. The cancellation reason has to be fetched with purchases.subscriptionsv2.get, and Google clears every cancellation field if the user restores the subscription.
  • Apple's App Store Server API has no cancel survey. Its expirationIntent field gives one of five codes: customer canceled, billing error, no consent to a price increase or offer conversion, product unavailable, or other.
  • Apple's DID_CHANGE_RENEWAL_STATUS notification with subtype AUTO_RENEW_DISABLED can mean the App Store turned off auto-renewal after the customer requested a refund, not only that the customer switched it off.
  • A cancellation reason never gives a developer a vote on a refund. Only Apple's CONSUMPTION_REQUEST, answered within 12 hours, and Google Play's chargeback review through orders.reviewrefund, answered within 24 hours, ask for evidence.
  • A Google Play subscriber who cancels citing technical issues is the one most likely to want money back, and for orders placed after August 3, 2026, a chargeback they win costs the developer the purchase price less Play's service fee plus the bank's fees.

Most subscribers who end up refunded cancel first. That cancellation carries a reason, and the two stores hand you very different amounts of it. Google Play runs a short survey and passes the answer to your server, free text included. Apple sends a numeric code that says how the subscription ended, not why the customer wanted out. Read both properly and you'll see refund requests coming while there's still something you can do about them.

What Google Play tells you about subscription cancellation reasons

When a user cancels in the Play subscriptions center, Google asks them why. The answer lands in the subscription resource you get from purchases.subscriptionsv2.get, under canceledStateContext. That object only exists while the subscription is in the canceled or expired state, and it says who ended the subscription: the user, Google's system, you, or a replacement such as a plan change.

When the user did it, the userInitiatedCancellation object holds two fields. cancelTime says when they canceled. cancelSurveyResult holds the survey answer.

Survey reasonGoogle's descriptionWhat it often signals
CANCEL_SURVEY_REASON_NOT_ENOUGH_USAGENot enough usage of the subscriptionLow usage, so little cost sunk into the account
CANCEL_SURVEY_REASON_TECHNICAL_ISSUESTechnical issues while using the appThe strongest refund and chargeback signal
CANCEL_SURVEY_REASON_COST_RELATEDCost related issuesPrice sensitivity, sometimes a renewal they didn't expect
CANCEL_SURVEY_REASON_FOUND_BETTER_APPThe user found a better appA competitor won, rarely a dispute
CANCEL_SURVEY_REASON_OTHERSOther reasonsRead reasonUserInput, the user's own words
CANCEL_SURVEY_REASON_UNSPECIFIEDUnspecified cancel survey reasonNo answer to work with

The right-hand column is our reading, not Google's. The first two columns come straight from the API reference.

The notification doesn't carry the reason

A canceled subscription triggers a SUBSCRIPTION_CANCELED real-time developer notification, type 3. Google is explicit that these notifications only say the purchase state changed. The payload gives you a purchase token and nothing else useful, so your handler has to call purchases.subscriptionsv2.get to read the survey answer.

The Play Console view

You don't need code to see the totals. Play Console's subscription reports include a Cancellations card that splits churn into voluntary, involuntary and other, and a Cancellation survey responses card for users who chose to answer. Free-text answers from users who picked other can be downloaded as a CSV from the Other responses card. That download needs the View financial data permission, the same one you'd grant a tool that reads your orders.

What Apple tells you, and what it leaves out

Apple runs no cancellation survey that reports back to developers. The closest field is expirationIntent in the signed renewal info, and it describes how a subscription ended, not what the customer thought.

expirationIntentApple's meaningMatching EXPIRED subtype
1The customer canceled their subscriptionVOLUNTARY
2Billing error, such as invalid payment informationBILLING_RETRY
3No consent to a price increase or offer conversion that required itPRICE_INCREASE
4The product wasn't available for purchase at renewalPRODUCT_NOT_FOR_SALE
5Some other reasonNo subtype

Code 1 is the only one that describes a choice the customer made, and it says nothing about the motive. A customer who left because the app kept crashing and one who simply finished a project look identical.

The signal hiding in AUTO_RENEW_DISABLED

There's one Apple notification worth a closer look. DID_CHANGE_RENEWAL_STATUS with subtype AUTO_RENEW_DISABLED usually means the customer turned off auto-renewal. Apple's documentation adds a second case: the App Store also turns auto-renewal off after the customer requests a refund.

So on iOS, a renewal-off event can be the first trace of a refund request. If the purchase is a consumable or an auto-renewable subscription, a CONSUMPTION_REQUEST may follow, and from that point you have 12 hours to send consumption data. A renewal-off event that arrives with no visible action in your app is worth treating as a heads-up to get that account's usage data ready.

Apple and Google side by side

Google PlayApple App Store
Asks the user whyYes, a cancel surveyNo developer-visible survey
Where the reason livescanceledStateContext in purchases.subscriptionsv2expirationIntent in renewal info
Free textreasonUserInput, only for otherNone
Who canceledUser, system, developer or replacementInferred from the code and subtype
NotificationSUBSCRIPTION_CANCELED, then call getDID_CHANGE_RENEWAL_STATUS, EXPIRED
Lost if the user resubscribesYes, cleared on restoreRenewal info reflects the current state
DashboardCancellation survey responses cardNone for reasons
Printed survey cards sorted into small piles on a wooden table beside a phone and a coffee cup, the way a developer groups subscription cancellation reasons

Where a cancellation turns into a refund

A cancellation stops the next charge. It doesn't return the last one. Whether money goes back depends on which refund flow the customer reaches next, and most of those flows run without you.

  • On Google Play, a buyer can get a refund within 48 hours of purchase on their own, and Google decides it.
  • Refunds through Google's or Apple's support are decided by the store.
  • Apple's CONSUMPTION_REQUEST asks for your consumption data, with a 12-hour window.
  • Google Play's chargeback review asks for evidence through orders.reviewrefund, with a 24-hour window. The bank's decision on a chargeback is final.

A cancellation reason doesn't change any of those rules. What it changes is how early you know which customer is unhappy, and whether your evidence is ready when one of the two flows that ask for it arrives.

What each reason costs you

The survey answer is also a rough guide to what an account has already cost to serve, which is the money a refund leaves you holding.

Technical issues

This is the expensive one. The customer used the product enough to hit problems, so you've paid for the compute behind their sessions, the model API calls their requests made, the storage for whatever they created, and any payout owed to a creator whose content they used. If they then get a refund, the price goes back and those costs stay with you. If they go to their bank on Google Play, an order placed after August 3, 2026 costs you the purchase price less Play's service fee, plus the bank's fees.

Cost related

A price complaint costs you less than it looks, unless it hides an unexpected renewal. That's the classic chargeback story, so check whether the cancel came right after a renewal charge and whether your renewal reminders went out.

Not enough usage

Low usage means low serving costs, so a refund here mostly returns money you didn't spend much to earn. It's also the reason where honest consumption data, if Apple asks for it, shows exactly what the customer did and didn't use.

Found a better app

These customers rarely dispute anything. They left for a competitor. The reason is useful for product decisions and almost never for refund defense.

A routine for reading cancellation reasons

  • On every Google Play SUBSCRIPTION_CANCELED, call purchases.subscriptionsv2.get and save canceledStateContext with the purchase token and cancelTime.
  • Save reasonUserInput verbatim when the reason is other. It's the only free text either store gives you.
  • On every Apple DID_CHANGE_RENEWAL_STATUS with AUTO_RENEW_DISABLED, log the event and pull that account's usage, in case a CONSUMPTION_REQUEST follows.
  • On every Apple EXPIRED notification, record the subtype and expirationIntent so voluntary churn and billing failures don't blur together.
  • For Google Play cancels citing technical issues, check your error logs for that account and reach out before the customer reaches their bank.
  • Keep per-account usage logs, so a CONSUMPTION_REQUEST gets an answer inside 12 hours and a chargeback review inside 24.

Frequently asked questions

How do I see why a Google Play subscriber canceled?
Call purchases.subscriptionsv2.get and read canceledStateContext.userInitiatedCancellation.cancelSurveyResult. The reason field holds the survey answer, and reasonUserInput holds free text when the user picked other. Play Console also shows totals in the Cancellation survey responses card.
Does Apple tell developers why a customer canceled a subscription?
No. Apple has no developer-visible cancel survey. The expirationIntent field says how the subscription ended, with codes for customer canceled, billing error, no consent to a price increase, product unavailable, or other, but not the customer's motive.
Does the SUBSCRIPTION_CANCELED notification include the cancellation reason?
No. Google Play's real-time developer notifications only say the purchase state changed. Fetch the subscription with purchases.subscriptionsv2.get to read the reason, and store it right away, because Google clears cancellation fields if the user restores the subscription.
Can an Apple AUTO_RENEW_DISABLED notification mean a refund request?
Yes. Apple's documentation says the AUTO_RENEW_DISABLED subtype covers both a customer turning off auto-renewal and the App Store turning it off after the customer requested a refund.
Can I revoke access when a subscriber cancels?
Not on Google Play while they're still entitled. Google says a canceled subscriber keeps access until the end of the billing cycle, and removing access early violates Google Play's subscriptions policy. Use expiryTime to decide when access ends.

Sources and further reading

RefundHalt

The refund autopilot for the App Store and Google Play

Keep reading

The next refund request is already on its way.

Set up RefundHalt in the time it takes to read another support email about a refund you didn't get to contest.