# Cancellation at least as easy as sign-up

- **Pattern:** `ab-001488` (`ftc-consumer-protection.dark-patterns.cancellation-easy`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001488
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001488)

## Why it matters

The FTC's updated Negative Option Rule (2024) — commonly called the Click-to-Cancel rule — explicitly requires that cancellation be 'at least as easy' as the original enrollment. A checkout that takes 2 minutes online but requires a support ticket to cancel is a per-subscriber violation. Cancellation flows with three or more confirmation screens, mandatory 'tell us why' forms, or retention specialist gatekeeping each constitute prohibited friction. Beyond FTC exposure, high-friction cancellation increases chargebacks and negative reviews from frustrated users who feel trapped.

## Severity rationale

Medium because cancellation friction must be evaluated against enrollment complexity to constitute a violation — a subscription with a complex setup might support a more involved cancellation — but online-signup products with support-ticket cancellation clearly fail the FTC's symmetry requirement.

## Remediation

Implement self-service cancellation completable in the account settings UI with a single confirmation step.

```tsx
function CancelSubscriptionSection() {
  const [confirming, setConfirming] = useState(false)
  const [cancelled, setCancelled] = useState(false)

  async function handleCancel() {
    await fetch('/api/subscription/cancel', { method: 'POST' })
    setCancelled(true)
  }

  if (cancelled) {
    return (
      <p>Subscription cancelled. Access continues until the end of
        your current billing period.
      </p>
    )
  }

  return (
    <div>
      {!confirming ? (
        <button onClick={() => setConfirming(true)}>
          Cancel subscription
        </button>
      ) : (
        <div>
          <p>You'll retain access until your billing period ends.
             Resubscribe anytime.
          </p>
          {/* One counter-offer step is acceptable; more screens are not */}
          <button onClick={handleCancel}>Yes, cancel</button>
          <button onClick={() => setConfirming(false)}>Keep subscription</button>
        </div>
      )}
    </div>
  )
}
```

If a retention offer (discount, pause) is shown as one interstitial screen before the final cancel button, that is compliant. Multiple successive retention screens with no direct 'cancel now' path are not.

## Detection

- **ID:** `cancellation-easy`
- **Severity:** `medium`
- **What to look for:** Count all relevant instances and enumerate each. Map the cancellation path. Start from the user's account settings page. Count: how many clicks does it take to complete cancellation? Does the path require: (1) navigating to a non-obvious settings section; (2) calling a phone number or submitting a support ticket (when sign-up was online); (3) waiting for a response before cancellation takes effect; (4) chatting with a retention specialist who must "process" the cancellation; (5) re-entering payment information. Compare this to the signup flow: how many steps did signup take? The FTC's Negative Option Rule explicitly prohibits making cancellation substantially more difficult than enrollment. Also check for cancellation interstitials — additional screens designed to delay or prevent cancellation (counter-offers, "are you sure?" cascades with multiple confirmation steps beyond one).
- **Pass criteria:** Cancellation can be completed entirely through the account settings UI without contacting support, in no more steps than the original signup. A single confirmation dialog (one "are you sure?" prompt) is acceptable. The cancellation takes effect immediately or at the end of the current billing period (user's choice), without delay.
- **Fail criteria:** Cancellation requires opening a support ticket or calling a phone number when signup was entirely online. Cancellation flow has three or more confirmation screens beyond the initial request. Cancellation does not take effect immediately and requires processing time without a clear reason. Users are taken through multiple retention offers with no direct "cancel now" option on each screen.
- **Skip (N/A) when:** The application has no subscriptions or paid recurring services — it is one-time payment or entirely free.
- **Detail on fail:** Example: `"Cancellation requires submitting a support ticket. Signup is completed online in under 2 minutes. This asymmetry is an FTC violation under the Negative Option Rule."` or `"Cancellation flow has 4 confirmation screens and a mandatory 'tell us why you're leaving' form before the final cancel button."` or `"'Cancel Subscription' button in settings opens an Intercom chat that requires speaking with a retention agent."`
- **Remediation:** Implement direct self-service cancellation:

  ```tsx
  // Self-service cancellation — one confirmation, then done
  function CancelSubscriptionSection() {
    const [confirming, setConfirming] = useState(false)
    const [cancelled, setCancelled] = useState(false)

    async function handleCancel() {
      await fetch('/api/subscription/cancel', { method: 'POST' })
      setCancelled(true)
    }

    if (cancelled) {
      return (
        <p>Your subscription has been cancelled. You have access until
          the end of your current billing period.
        </p>
      )
    }

    return (
      <div>
        {!confirming ? (
          <button
            onClick={() => setConfirming(true)}
            variant="destructive"
          >
            Cancel subscription
          </button>
        ) : (
          <div>
            <p>Are you sure? You'll lose access at the end of your
              billing period. This cannot be undone from this screen
              — you can resubscribe anytime.
            </p>
            {/* One counter-offer is acceptable; multiple screens are not */}
            <button onClick={handleCancel}>
              Yes, cancel my subscription
            </button>
            <button onClick={() => setConfirming(false)}>
              Keep my subscription
            </button>
          </div>
        )}
      </div>
    )
  }
  ```

  The counter-offer step (showing a discount or pause option before final cancellation) is acceptable as a single screen. The user must have a clear path to complete cancellation from that screen without additional friction.

---

## External references

- external ftc-click-to-cancel — https://www.ftc.gov/news-events/news/press-releases/2024/10/federal-trade-commission-announces-final-click-cancel-rule-making-it-easier-consumers-end-unwanted
- external ftc-negative-option-rule — https://www.ftc.gov/legal-library/browse/rules/negative-option-rule

Taxons: regulatory-conformance, user-experience

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