How to collect cancellation and churn feedback

Add one optional question to the cancellation flow, then send the answer to your feedback inbox from your backend using the REST API with the account and reason in metadata. Keep the question skippable, never block the exit, and read the answers by reason every month.

By · Last updated

Why cancellation is the most honest feedback you will get

A customer who cancels has already decided to leave, so they have no reason to be polite or to protect your feelings. That makes their reason more direct than almost any other message you will read. The problem is that most products treat cancellation as a button that disappears the account and nothing else. The reasons are lost, and the same problems come back in the next cohort.

Cancellation feedback is different from a general feedback prompt. The question is narrow, the person is leaving, and the answer should inform the product and the team that handles retention. Treat it as its own moment, with its own copy and its own routing.

Add one optional question to the cancellation flow

The flow should ask one question: why are you leaving? Provide a short text box, and make it clear the field is optional. Do not add a list of reasons with checkboxes, a rating or a second screen. A long exit flow makes people feel trapped, and trapped people give false answers just to finish.

Put the question on the page where the cancellation is confirmed, before the final button. Let the user cancel even if they leave the box empty. A question that blocks the exit produces anger, which is the worst input for a churn analysis.

Escuta Produto does not include a cancellation form or a survey builder, so the question is part of your own page. The widget can open from that page as well. A good pattern is a small text area in your own markup that submits to your backend when the user confirms.

Send the reason from your backend

Send the cancellation reason to your feedback inbox from your server, not from the browser. Your server already knows the account, the plan and the cancellation time, and it can attach that context safely. The REST API takes a JSON body with a public key, a message, a kind, an optional email and a metadata object.

// Runs on your server after the cancellation is confirmed
async function sendCancellationReason({ account, reason }) {
  if (!reason || reason.trim().length < 2) return;

  await fetch("https://escutaproduto.com/api/v1/feedback", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      key: process.env.ESCUTA_PUBLIC_KEY,
      kind: "other",
      message: reason,
      email: account.ownerEmail,
      name: account.ownerName,
      metadata: {
        event: "cancellation",
        accountId: account.id,
        plan: account.planName,
        tenureDays: account.tenureDays,
      },
    }),
  });
}

The message must be at least two characters, so the guard in the example skips empty or one-letter answers. The response returns 201 with an id when the item is stored. A 400 means the body was invalid, and a 429 means too many requests came from the same address in one minute, which is unlikely for a single cancellation but worth retrying later if you send in bursts. Read the full field list and error codes in the API docs. The OpenAPI 3.1 file at the openapi.json route describes the same body if you generate a client.

The key is public, which is safe here because it can only create feedback. It cannot read the inbox. Still, keep it in configuration, not in a hard-coded string, so you can rotate it if you ever need to.

Choose the kind carefully

Use other for a general reason such as "too expensive for what I use" or "moved to a different team". Use idea when the reason names a missing capability, such as "I need to export to a spreadsheet and you do not support it". Use bug when the reason is an error the customer could not get past. The kind helps you route the item later, and a missing feature is a much more useful signal than a generic complaint.

Do not argue with the reason in the moment. Record it, thank the person in one line, and let the team decide what to do.

Read churn feedback by reason

Once a month, read the cancellation items together. Filter the inbox to the product, then read the messages in batches of twenty. Group them by reason in a spreadsheet. A simple sheet with three columns works: the reason in the customer's words, the category you assign, and the account tenure from metadata. Use the CSV export for this, because it opens cleanly in Excel and Google Sheets.

Count distinct accounts for each category, not messages. One account can send several notes, and you want to know how many customers left for each reason. For example, if 12 accounts left because a feature was missing and 3 left because of a bug that is now fixed, the feature gap deserves the next planning slot.

Look at tenure too. Reasons from accounts that stayed for a year often point to strategy. Reasons from accounts that left in the first week often point to onboarding. The onboarding guide covers that early stage in more detail.

What to do with churn reasons

Some reasons are fixable: a missing export, a confusing setting or a bug. Put those in the planned queue with a note that links to the cancellation items. Some reasons are not fixable: the customer's business closed or their budget moved. Close those with a short internal note so you stop re-reading them.

Do not reply to a cancellation by email unless the customer asked you to. If they did ask, reply once, honestly and briefly. Escuta Produto does not send automatic emails to customers, so any follow up is written and sent from your own address. The guide to saying no helps when the reason is a feature you will not build.

How to set up cancellation feedback in Escuta Produto

Create a product for your app if you do not have one yet, copy its public key, and add the server call above to the code path that confirms the cancellation. Add the product's notification webhook if you want the team to see cancellation reasons as they arrive, or leave it off and read them in the weekly review.

Read the API docs before you ship, especially the section on error codes, so your code handles a 429 without losing the reason. Set the allowed origins in the product settings only if you also use the widget on the same product, because the server call does not depend on them.

Frequently asked questions

Should the cancellation flow require a reason before the customer can leave?

No. Make the reason field optional and let the customer cancel with an empty box. A required question creates frustration, and frustrated customers give answers that do not help you understand the real reason they left.

How do you send a cancellation reason to a feedback inbox?

Call the REST API from your server after the cancellation is confirmed. Send the public product key, the reason as the message, a kind such as other, and an account id and tenure in metadata. The key can only create feedback, not read it.

How often should a team review churn feedback?

Read it once a month in one batch, grouped by reason and counted by distinct account. Monthly is enough to see patterns, and it keeps the review from becoming a reaction to a single loud cancellation.