# Downgrade and pause options presented before final cancel

- **Pattern:** `ab-002553` (`subscription-compliance.cancellation.downgrade-pause`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002553
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002553)

## Why it matters

The FTC Click-to-Cancel Rule (2024) permits retention offers during the cancellation flow only if they do not add mandatory friction — the consumer must be able to skip any retention step and complete cancellation without taking additional required actions. Absent retention alternatives (downgrade, pause), the application misses a business opportunity to retain users who would have accepted a lighter-weight option. Stripe's `pause_collection` API makes subscription pausing a low-effort implementation. Presenting alternatives also demonstrates good faith in regulatory context: a structured, skippable retention flow is evidence of intent to honor cancellation, which reduces FTC enforcement risk.

## Severity rationale

Low because absent retention alternatives fail a UX best practice and a weak FTC good-faith signal, but do not constitute an affirmative regulatory violation — the user can still cancel without them.

## Remediation

Add a skippable alternatives step before the cancellation confirmation. The step must have a clearly labeled bypass. In `components/CancelFlow.tsx`:

```tsx
if (step === 'alternatives') {
  return (
    <div>
      <h3>Before you go</h3>
      <button type="button" onClick={handleDowngradeToFree}>Switch to the free plan</button>
      <button type="button" onClick={handlePauseSubscription}>Pause for 1–3 months</button>
      {/* Bypass must be clearly labeled and require no additional effort */}
      <button
        type="button"
        className="text-sm text-gray-500 underline mt-4"
        onClick={() => setStep('confirm')}
      >
        No thanks, continue cancelling
      </button>
    </div>
  )
}
```

For pause, use `stripe.subscriptions.update({ pause_collection: { behavior: 'mark_uncollectible' } })` in `app/api/subscription/pause/route.ts`. The 'continue cancelling' path must complete in the same number of total steps as direct cancellation.

## Detection

- **ID:** `downgrade-pause`
- **Severity:** `low`
- **What to look for:** Examine the cancellation flow for retention alternatives offered to the user before they complete cancellation. Look for: (1) a plan downgrade option (if the application has multiple tiers, is the user offered a free or lower tier instead of full cancellation?), (2) a subscription pause feature (Stripe supports pausing subscriptions via `pause_collection`), (3) a "contact support to discuss alternatives" offer. These options reduce churn and are a UX best practice — but the key audit point is that they are offered before the final cancellation step, not presented as obstacles. A "downgrade to free" link should appear in the cancellation flow, not only in account settings. Check whether the Stripe Billing Portal configuration includes plan switching. Count all instances found and enumerate each.
- **Pass criteria:** Before completing cancellation, the user is presented with at least one retention alternative (plan downgrade, subscription pause, or support contact). The alternative is clearly labeled and easy to skip — the user can still complete cancellation without taking the alternative. The offer does not add extra mandatory steps to cancellation. At least 1 implementation must be confirmed.
- **Fail criteria:** No retention alternatives are presented at any point in the cancellation flow. The user goes directly from "cancel" click to confirmation with no options offered.
- **Skip (N/A) when:** The application offers only a single subscription tier with no free tier, no pause functionality, and no meaningful alternative to cancellation. Document why skip applies.
- **Detail on fail:** Example: `"Cancellation flow proceeds directly to confirmation with no downgrade offer, pause option, or support link presented."` or `"Only one plan tier exists and Stripe pause_collection is not implemented."`.
- **Remediation:** Add a lightweight retention step before the cancellation confirmation:

  ```tsx
  // components/CancelFlow.tsx
  type CancelStep = 'reason' | 'alternatives' | 'confirm'

  export function CancelFlow() {
    const [step, setStep] = useState<CancelStep>('reason')

    if (step === 'alternatives') {
      return (
        <div>
          <h3>Before you go — here are some other options</h3>

          {/* Option 1: Downgrade */}
          <button type="button" onClick={handleDowngradeToFree}>
            Switch to the free plan (keep basic access)
          </button>

          {/* Option 2: Pause */}
          <button type="button" onClick={handlePauseSubscription}>
            Pause for 1–3 months (no charges during pause)
          </button>

          {/* Option 3: Support */}
          <a href="mailto:support@example.com?subject=Subscription question">
            Talk to support
          </a>

          {/* Must be easy to skip */}
          <button
            type="button"
            className="text-sm text-gray-500 underline"
            onClick={() => setStep('confirm')}
          >
            No thanks, continue cancelling
          </button>
        </div>
      )
    }

    // ...confirm step
  }
  ```

---

## External references

- external ftc-click-to-cancel-rule-2024 — https://www.ftc.gov/news-events/news/press-releases/2024/10/ftc-announces-final-click-cancel-rule-making-it-easier-consumers-end-unwanted-subscriptions

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-002553
