← Back to Dimensions

Subscription Cancellation Reason

Also known as: Cancellation Reason, Subscription Churn Reason, Cancel Reason, Churn Reason, cancellation_reason

RetentiondimensionE-commerce: Customer Retention, Loyalty & LTVsubscriptionchurnE-commerce

Reason a subscriber picks in the cancel flow when ending a recurring product subscription, e.g. too_expensive, too_much_product, no_longer_needed. Splits voluntary subscription churn by cause.

Business Use Case

1️⃣ Product: when too_much_product leads cancellations, adds a change-frequency save offer to the cancel flow. 2️⃣ Marketing: when too_expensive share rises after a price change, tests a deeper subscribe-and-save discount tier. 3️⃣ Merchandising: when product_quality cancellations cluster on one SKU, reviews the product with the supplier. 4️⃣ Customer Service: when delivery_issue cancellations rise, escalates the carrier and contacts at-risk subscribers.

Business Criticality

High

Journey / Navigation Area

Engagement

Owning Function

Marketing

Scope

Event

Calculation Notes

1️⃣ Source: cancellation_reason on submit_form (form_type = subscription_cancellation), keyed by subscription_id; one value per cancellation. 2️⃣ Values: too_expensive, too_much_product, no_longer_needed, product_quality, delivery_issue, switched_provider, other. Single-select only. 3️⃣ Send only on confirmed cancellation; subscribers who accept a save offer (skip, pause, discount) have not cancelled and send no reason. 4️⃣ Dunning cancellations run in the billing backend and never fire this submit_form; out of scope and excluded from reconciliation. 5️⃣ Merchant- or agent-initiated cancellations bypass the cancel flow and are excluded likewise; single-order cancellations are out of scope. 6️⃣ Free-text 'other' comments stay in the billing platform (Recharge, Recurly, Chargebee); never send them to analytics, as they may hold PII. 7️⃣ Reconcile weekly to the billing platform's voluntary cancellation log by subscription_id; a cancellation with no reason is a tagging gap.

Technical Details

Data Typestring
Lookback WindowEvent, Weekly, Monthly

Events

PlatformEvent
Google Analytics 4submit_form
Adobeform_submit

Data Mappings

W3 Data Layer
{
  "event": [
    {
      "eventInfo": {
        "eventName": "submit_form"
      },
      "attributes": {
        "form_type": "subscription_cancellation",
        "subscription_id": "SUB-1",
        "cancellation_reason": "too_expensive"
      }
    }
  ]
}
GA4 Data Layer
{
  "event": "submit_form",
  "form_type": "subscription_cancellation",
  "subscription_id": "SUB-1",
  "cancellation_reason": "too_expensive"
}
Adobe Client Data Layer
{
  "event": "form_submit",
  "eventInfo": {
    "form_type": "subscription_cancellation",
    "subscription_id": "SUB-1",
    "cancellation_reason": "too_expensive"
  }
}
XDM Mapping
{
  "eventType": "web.formFilledOut",
  "_tenant": {
    "form_type": "subscription_cancellation",
    "subscription_id": "SUB-1",
    "cancellation_reason": "too_expensive"
  }
}

SQL Queries

Google Analytics 4 (BigQuery)
-- ==========================================
-- 1. GOOGLE BIGQUERY SQL
-- ==========================================
-- Relative reporting window: last 90 complete days
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY);
DECLARE end_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);

-- Subscription-cancellation submit_form events with subscription_id and cancellation_reason pivoted from event_params
WITH cancel_events AS (
  SELECT
    event_timestamp,
    (SELECT COALESCE(ep.value.string_value, CAST(ep.value.int_value AS STRING)) FROM UNNEST(event_params) ep WHERE ep.key = 'subscription_id') AS subscription_id,
    (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'cancellation_reason') AS cancellation_reason
  FROM `your-project.analytics_123456789.events_*`
  WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', start_date) AND FORMAT_DATE('%Y%m%d', end_date)
    AND event_name = 'submit_form'
    AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'form_type') = 'subscription_cancellation'
),
-- One value per cancellation: keep the last submit per subscription_id
cancellations AS (
  SELECT
    subscription_id,
    cancellation_reason,
    ROW_NUMBER() OVER (PARTITION BY subscription_id ORDER BY event_timestamp DESC) AS rn
  FROM cancel_events
  WHERE subscription_id IS NOT NULL
)
-- Reason per cancellation; a missing reason is reported as (not set) to flag tagging gaps
SELECT
  subscription_id,
  COALESCE(cancellation_reason, '(not set)') AS cancellation_reason
FROM cancellations
WHERE rn = 1;
Adobe Experience Platform (AEP Query Service)
-- ==========================================
-- 2. ADOBE AEP QUERY SERVICE SQL
-- ==========================================
-- Relative reporting window: last 90 complete days
WITH params AS (
  SELECT
    CAST(DATE_SUB(CURRENT_DATE, 90) AS DATE) AS start_date,
    CAST(DATE_SUB(CURRENT_DATE, 1) AS DATE) AS end_date
),
-- Subscription-cancellation form submits with subscription_id and cancellation_reason
cancel_events AS (
  SELECT
    w.timestamp AS event_ts,
    w._tenant.subscription_id AS subscription_id,
    w._tenant.cancellation_reason AS cancellation_reason
  FROM aep_web_events_dataset w
  CROSS JOIN params p
  WHERE w.eventType = 'web.formFilledOut'
    AND w._tenant.form_type = 'subscription_cancellation'
    AND CAST(w.timestamp AS DATE) BETWEEN p.start_date AND p.end_date
),
-- One value per cancellation: keep the last submit per subscription_id
cancellations AS (
  SELECT
    subscription_id,
    cancellation_reason,
    ROW_NUMBER() OVER (PARTITION BY subscription_id ORDER BY event_ts DESC) AS rn
  FROM cancel_events
  WHERE subscription_id IS NOT NULL
)
-- Reason per cancellation; a missing reason is reported as (not set) to flag tagging gaps
SELECT
  subscription_id,
  COALESCE(cancellation_reason, '(not set)') AS cancellation_reason
FROM cancellations
WHERE rn = 1;

Source Data

Digital Analytics (GA4)

Dependencies

Prerequisite: List the dependencies required for this Dimension

Report Attributes

Subscription Status Customer Tenure Band Item Category Device Category Traffic Source

Segment Eligibility

true

Governance

Data SensitivityInternal

Governance

Created bydevyendarm
Created on10/12/2026
Last modified bydevyendarm
Last modified on10/12/2026
StatusPUBLISHED

GitHub

View related Pull Requestcatalog/dimensions/subscription-cancellation-reason.yml

Community Discussion