Analytics

Cancellation Survey Questions That Become a Dataset

One required question plus one optional comment is the whole form. The real work is the reason coding rubric: separate reason from free text, track request versus effective cancellation, validate against behavior.

Alex KhvoinitskiiAugust 11, 202515 min read

TL;DR: A cancellation survey is only useful if answers land as coded data: one required multiple-choice question plus optional open text, reason and comment in separate fields, request versus effective cancellation tracked, and stated reasons validated against behavior.

Your cancel flow probably already asks why the customer is leaving. The problem is what happens next: the answer lands in a dropdown label and a text blob, someone exports it once a quarter, and the "why people cancel" conversation stays a wall of text. This guide is for lifecycle, product, and subscription operations leads at mobile and consumer subscription businesses who need to design subscription cancellation surveys you can use for reporting, save offers, and product decisions — not just for optics.

The fix is not a longer survey. It is a measurement design: the right questions, the right fields, and a coding rubric that turns answers into rows you can query. Teams usually justify this kind of lifecycle instrumentation with business process automation ROI; a cancellation survey earns it when every reason maps to an action you can measure.

Which cancellation survey questions to ask

The answer: one required multiple-choice question — "What is your main reason for cancelling?" — plus at most one optional open-text field. That is the whole form for most products. The customer came to cancel; every extra required question is another chance to abandon the flow, and the person answering has already decided to leave, as cancellation-survey practitioners like AcornRetain and ChurnIntel both advise.

Build the reason list from what your customers actually say, not from what you imagine. Most cancellation survey examples stop at the question list; the list is the easy part, and getting it roughly right matters less than keeping it short. Start with four to six options and cap the list around eight to ten. A working starter set, grouped the way operators group them:

Reason group Example options customers understand
Price and value Too expensive for what I get; found a cheaper alternative; need to cut spend
Product fit and usage Not using it enough; missing a feature I need; too hard to use
Onboarding and support Never got set up properly; support did not resolve my issue; bugs or reliability problems
Competition Switching to a different service
Business context Project or season ended; no longer need this

Then the rules that keep answers usable:

  • Keep the reason list short and scannable. Refine it from what people type into the open field — the free text is where tomorrow's new codes come from.
  • Make the follow-up optional and conditional. After "too expensive," ask what they would pay. After "missing a feature," ask which one. Leave the box off answers you would do nothing with.
  • Route every option to an action. Price earns a discount or plan-change path, a temporary need earns a pause, a missing feature earns a roadmap note, and a payment problem earns a card-update link — not a discount, per Swipe Again's exit-survey design rules. An answer you cannot act on is a question you should not ask.
  • Keep a visible exit on every screen. "Continue cancelling" must be one tap away at all times. A survey that blocks the exit collects the fastest available answer — garbage data — and, in the US, a hard-to-cancel flow still carries legal exposure even after the FTC's click-to-cancel rule was vacated in July 2025, because ROSCA and state auto-renewal laws remain in force, per Latham & Watkins' analysis of the ruling. That is a compliance boundary, not legal advice — confirm your own counsel's read.

If you run your cancellation survey through the Stripe customer portal, the same structure applies — a Stripe cancellation survey there collects one fixed reason list plus an optional comment, which is exactly the one-question-plus-text pattern.

Separate the selected reason from the free text

The answer: store two fields, never one. The multiple-choice answer is a coded enum — countable, groupable, safe to chart. The open-text answer is a comment — qualitative context you read, not a column you average. The moment you parse prose to fill a report, you are back to the wall of text.

Stripe's own data model is the cleanest public example of this split. When a subscription is canceled, the Subscription object carries a cancellation_details object with three parts, per the Stripe API reference:

  • feedback — the customer-submitted reason, a fixed enum: too_expensive, missing_features, switched_service, unused, customer_service, too_complex, low_quality, or other.
  • comment — free text the customer added, populated only when they bother to write it.
  • reason — why the subscription was canceled at the system level: cancellation_requested, payment_disputed, payment_failed, or canceled_by_retention_policy.

Notice what Stripe separates that a naive survey does not: the customer's stated reason (feedback), the customer's own words (comment), and the system's reason (reason). A card that failed three times and auto-canceled never saw your survey at all — it lands in reason, not feedback. Mirror that split in your own table and your voluntary-churn reporting stops lying about payment churn.

One more practical detail: nothing routes these answers anywhere by default. Stripe stores the feedback on the subscription object until something reads it — your backend should listen for customer.subscription.updated and copy cancellation_details into your analytics pipeline, as Modem's routing guide describes. The same is true of any survey tool: capture is a data decision, routing is a separate build.

Track the cancel request, not just the cancellation

The answer: a voluntary cancellation has two timestamps — the moment the customer asked to leave and the moment access actually ends — and your dataset needs both. They are different events, sometimes weeks apart, and the gap between them is where save offers and win-back timing live.

Both billing platforms in a typical subscription stack expose this split:

  • Stripe: setting cancel_at_period_end fires customer.subscription.updated; the subscription actually ends later, when customer.subscription.deleted fires, per Stripe's subscription webhook docs. An updated-with-pending-cancel is a request. A deleted is an effective cancellation.
  • RevenueCat: a CANCELLATION webhook fires when the customer cancels or a refund lands, but the user keeps access until EXPIRATION at period end — and an UNCANCELLATION event fires if they re-enable auto-renew before then, per the RevenueCat event reference. A request that gets reversed is not churn at all; it is a save.

Two consequences for the dataset. First, count survey responses against requests, not effective cancels: the customer answered at request time, and a later UNCANCELLATION or a successful save does not erase what they told you. Second, involuntary cancels never pass through your survey. Stripe marks them in reason as payment_failed or payment_disputed; RevenueCat sends BILLING_ISSUE plus a CANCELLATION with cancel_reason=BILLING_ERROR, per the RevenueCat webhook flow docs. Keep those out of the survey denominator — your "top cancel reasons" chart describes voluntary exits only. The involuntary side is a different problem with its own machinery, covered in failed payment recovery.

Timing caveat worth encoding: RevenueCat says most webhooks arrive within 5–60 seconds, but cancellation events can take up to about 2 hours after the user cancels, per its webhooks overview. If your save offer or Slack alert keys off the survey click rather than the webhook, it will often beat the billing event.

Validate stated reasons with behavior

The answer: a selected reason is a hypothesis, not a fact. Exit answers are filled in by people who are already leaving — they have every incentive to pick the fastest socially acceptable option, which is why "too expensive" tops almost every churn survey, as Startup Fortune's churn-reason tracking guide points out. One public Indie Hackers post describes a SaaS founder finding the same gap in his own data: users selected "long file processing failed" while their task history showed dozens of successful jobs — the stated reason was whatever got them out of the modal fastest, per his write-up. One anecdote is not a benchmark, but the mechanism is common enough that you should design for it.

Cross-check each stated reason against what the customer actually did:

Stated reason Behavioral signature that should co-occur If the signature is missing
Too expensive / not enough value Usage declining before the request; price-sensitive plan tier Often an engagement problem wearing a price excuse — check last-active date first
Not using it enough Low sessions or stalled activation milestones Genuine low usage; look at onboarding drop-off, not features
Missing a feature Searched for or attempted the workflow; support tickets naming it Vague "missing feature" with no search or ticket may mean wrong-product-fit acquisition
Poor support / bugs Recent unresolved tickets or error-heavy sessions No contact history means the complaint is probably proxy for something else
Switching to a competitor Tenure, prior engagement, pricing-page visits Confirm with the optional "what are you switching to" follow-up

The point is not to call customers liars. It is to route each reason to the right fix — a discount cannot repair an onboarding gap, and a feature sprint cannot fix a customer who never activated. Compare stated reasons across cohorts before acting on them; the cohort view in subscription cohort LTV analysis is what turns "price is our top cancel reason" into "price is our top cancel reason in month-one paid cohorts," which is a different decision.

Watch the "other" bucket as your taxonomy health check. When "other" climbs to one of your top reasons, the list failed — mine the free text for the missing code, add it, and stop shipping surveys whose most common answer is a shrug.

The reason coding rubric

This is the working asset: a field spec plus coding rules that turn survey answers into queryable rows. The example rows are a synthetic illustration built on documented platform fields — a planning model, not a measured customer result.

Fields to store per response:

Field Type Rule
selected_reason enum One of 8–10 internal codes; required; mapped from the survey option
free_text string Optional comment; never parsed into reports
follow_up_answer string Optional conditional detail (which feature, what price)
cancel_requested_at timestamp When the customer asked to cancel (survey submit / pending-cancel event)
effective_end_at timestamp When access actually ends (period end); null while pending
voluntary boolean False when the cancel is payment-driven (Stripe payment_failed/payment_disputed, RevenueCat BILLING_ERROR)
outcome enum canceled, saved, rescinded (UNCANCELLATION), expired involuntary
save_offered / save_accepted enum Which offer branched on the reason, if any
survey_version string Reason lists change; version them or trends break silently

Coding rules:

  1. Map survey options to a fixed internal enum — not to raw display labels, which drift when copy changes. Stripe's feedback values are a reasonable seed list; add only codes you will act on.
  2. Free text informs, never overrides, selected_reason. A comment saying "actually I loved it" does not recode a too_expensive selection; it annotates it.
  3. The voluntary flag comes from billing events, not the survey. Payment-driven cancels have no survey answer; forcing one contaminates the data.
  4. Outcome is written by the lifecycle events, not the survey: request sets it to pending, UNCANCELLATION or a save sets saved/rescinded, effective end sets canceled.
  5. Re-validate codes quarterly against behavior. Retire reasons nobody picks; split reasons whose behavioral signature is inconsistent.

Synthetic worked rows (labeled synthetic — a format example, not measured data):

selected_reason free_text voluntary outcome Validation flag
too_expensive "love it but can't justify $30/mo" true saved (discount) Check usage — if low, flag as engagement churn
missing_feature "needs offline mode" true canceled Confirmed: 3 support tickets naming offline mode
— — false (payment_failed) expired involuntary No survey row; routes to dunning, not the survey report
other "moving abroad, app not available" true canceled Free-text mined → candidate new code availability

With these rows, the weekly question "why did people cancel" becomes three better questions: which voluntary reasons are growing, which stated reasons fail their behavioral check, and how much churn was never the survey's to measure. That is the difference between a dataset and a wall of text — the same discipline that turns closed-lost CRM reasons into follow-up actions in a reason taxonomy, or return codes into fixes in return reason analysis.

Where to place the survey in the cancel flow

The answer: timing is a tradeoff, so pick by what you will do with the answer. Ask at cancel intent — inside the flow, before the final confirm — if the reason should branch a save offer, because you cannot branch an offer on an answer you do not yet have. Ask after the cancellation is confirmed if you want purer research, because nothing rides on the answer and people respond more freely. Both are defensible; AcornRetain's guidance is explicit that they serve different purposes.

Two placement rules are not a tradeoff:

  • Do not hard-block the exit. One required tap-through question is fine; a required essay or a hidden "continue cancelling" link is not. Beyond the data-quality problem (trapped users pick the fastest answer), US auto-renewal rules — ROSCA, FTC Act Section 5, and state laws — still govern cancel-flow obstruction even though the FTC's standalone click-to-cancel rule was vacated on July 8, 2025, days before it was to take effect, as Reuters reported.
  • Survey once, store forever. The response row you write at request time should survive the outcome — save, uncancel, or effective end. The dataset outlives the save offer.

If your cancel reasons today live in a dropdown export nobody opens, a bounded audit of the flow — fields, events, routing — is usually a one-week fix. That'sGonnaHelp runs that kind of automation audit for subscription teams; the output is the coding rubric above wired to your actual stack.

FAQ

What is a churn survey?

A churn survey — also called a customer churn survey, cancellation survey, or customer exit survey — is the short questionnaire shown when a customer cancels a subscription. Its job is to capture the stated reason for leaving as structured data, so the business can route saves, fix causes, and report trends. It is not the same as an HR exit survey for departing employees, which is what most generic "exit survey" advice covers.

How many cancellation survey questions should you ask?

One required question plus one optional open-text field is enough for most subscription products — a single-select reason list of four to ten options, optionally followed by a conditional detail prompt on the answers you can act on. Every additional required question trades response rate for little extra signal.

What if most people pick "other"?

Then the reason list failed, not the customers. A top-ranked "other" means your options do not match the reasons people actually have; read the free-text comments, extract the missing code, add it as a real option, and re-run. Treat the "other" share as the survey's own quality metric.

If Stripe already collects a cancellation reason, do we still need a survey?

The Stripe customer portal's reason list is a fixed enum with an optional comment — useful as a baseline, but it has no conditional follow-ups, no product context, and only covers cancels that happen through that portal. Keep it as a supplementary source and mirror cancellation_details into your dataset; run your own survey if you need richer or branched answers.

Can we require an answer before the customer can cancel?

You can require a single selection, but pair it with a permanently visible "continue cancelling" path. Trapping people behind multi-step forms degrades the data — they pick the first option to escape — and keeps your flow on the wrong side of US auto-renewal and deceptive-practices rules.

Answer clarity notes

  • Dates: this article's publish date is August 11, 2025. Vendor documentation is living documentation checked on November 10, 2026 — field names, enum values, and webhook behavior can change; verify against current Stripe and RevenueCat docs before building. The FTC click-to-cancel vacatur (July 8, 2025) predates this article; the remaining legal framework described is accurate as of that ruling's reporting.
  • Scope: written for lifecycle, product, and subscription operations leads at mobile and consumer subscription businesses. It covers survey measurement design — questions, fields, event tracking, and validation — not B2B cancellation interviews, legal compliance advice, or a full cancel-flow UX spec. US legal references are planning context, not legal advice.
  • Evidence: platform behavior (Stripe cancellation_details, Stripe subscription events, RevenueCat event types, flows, and delivery timing) is verified against public vendor documentation. Survey-design practices (one required question, option counts, timing tradeoff, reason-to-action routing) come from linked practitioner and vendor guides. The Indie Hackers example is a public community post cited as illustration, not a That'sGonnaHelp customer result.
  • Synthetic examples: the rubric's worked rows are explicitly synthetic — a format model showing how fields should look populated, not measured data and not guarantees of what your data will show.
  • Do not infer: option lists, validation checks, and thresholds here are starting points to calibrate on your own data, not guarantees. Demand estimates for this topic (a US provider estimate of roughly 10 monthly searches for the exact phrase, versus a broader ~320 for "cancellation survey") are directional planning inputs, not traffic promises.

Sources

A

Alex Khvoinitskii

Founder, That'sGonnaHelp

Founder of That'sGonnaHelp. Building growth and automation systems since 2021 — GTM, traction, retention, and revenue — for SaaS, FinTech, and e-commerce clients, from early-stage brands to global exchanges.

Related articles

Support

Failed Payment Recovery That Keeps Customers

A failed renewal needs more than another email. Learn how to coordinate eligible retries, make card updates reach the right subscription, hand exceptions to support, and measure recovered cash without double counting.

December 25, 202520 min
Sales

Closed Lost Reasons: A Follow-Up Taxonomy

Closed lost reasons should do more than explain a failed deal. This practical taxonomy maps 8-12 CRM options to evidence, ownership, timing, suppression, and follow-up actions, with a decision matrix, pilot metrics, and automation safeguards.

March 15, 202616 min
Discuss your project