FTC Click-to-Cancel Rule (2024, effective 2025) requires that if a consumer enrolled online, cancellation must be available through the same online mechanism — routing to email or phone is an explicit violation. California ARL enforces the same standard for California-based consumers. A 'Cancel anytime' marketing claim paired with a mailto:support@example.com cancellation path is both a deceptive trade practice and a regulatory violation. The practical consequence is that support tickets spike at billing cycle, refund rates climb, and dispute rates follow because users who cannot self-cancel dispute the charge instead.
High because requiring support contact for online-enrolled subscriptions is a named violation category in the FTC Click-to-Cancel Rule, triggering enforcement without the proportionality analysis applied to step-count violations.
Replace any mailto: or tel: cancellation links with a self-service flow in app/settings/billing/page.tsx. The minimum viable path is a form post to the Stripe Billing Portal:
<div className="billing-actions">
<form action="/api/billing-portal" method="POST">
<button type="submit">Manage subscription</button>
</form>
</div>
If using Stripe Billing Portal, verify in Stripe Dashboard → Billing → Customer portal that 'Allow customers to cancel subscriptions' is enabled — some portal configurations disable cancellation by default, which means the portal route is present but non-functional. Search src/ for mailto: links adjacent to cancel-related copy to catch any lingering support-redirect patterns.
ID: subscription-compliance.cancellation.online-cancellation
Severity: high
What to look for: Identify how the user enrolled in the subscription (online checkout, in-app purchase, or direct sales). If enrollment was online, cancellation must also be available online — this is required under the FTC's click-to-cancel rule and similar state laws. Check the authenticated user interface for a self-service cancellation path. Look in Settings, Account, Billing, or Subscription pages. Check whether "Cancel" opens a link to the Stripe Billing Portal, a custom cancellation modal, or a mailto: / tel: link (the latter is a violation). If Stripe Billing Portal is used, confirm it is configured in the Stripe Dashboard to allow cancellation (some Portal configurations disable this option). Check the marketing site as well — if there is a "Cancel anytime" claim, verify it is actually true in the product. Count all instances found and enumerate each.
Pass criteria: Self-service online cancellation is available from within the authenticated product. The cancellation path does not require contacting support via email, phone, or chat. If Stripe Billing Portal is used, cancellation is enabled in the portal configuration. At least 1 implementation must be confirmed.
Fail criteria: Cancellation requires sending an email to support. Cancellation requires a phone call. The Settings/Billing page has a "Cancel" button that opens a mailto: or tel: link. "Cancel anytime" is claimed on the marketing site but actual cancellation requires support contact.
Skip (N/A) when: The application's subscriptions are sold exclusively through channels that handle cancellation (e.g., only via the iOS/Android App Store, where Apple/Google handles cancellation).
Detail on fail: Example: "Settings page has 'Cancel subscription' link that opens mailto:support@example.com. No self-service cancellation flow exists." or "Stripe Billing Portal is integrated but portal configuration does not enable cancellation — users reach the portal but cannot cancel from it.".
Remediation: Ensure self-service cancellation is reachable in 2 clicks from the settings page:
// app/settings/billing/page.tsx
export default function BillingSettingsPage() {
return (
<div>
<h2>Subscription</h2>
<p>Current plan: Pro — $29/month</p>
<p>Next billing date: March 15, 2026</p>
<div className="billing-actions">
{/* Primary action: Stripe Billing Portal */}
<form action="/api/billing-portal" method="POST">
<button type="submit">Manage subscription</button>
</form>
{/* Or direct cancel if not using Portal */}
<button type="button" onClick={() => setCancelModalOpen(true)}>
Cancel subscription
</button>
</div>
</div>
)
}
If using Stripe Billing Portal, check your portal settings: Stripe Dashboard → Billing → Customer portal → "Allow customers to cancel subscriptions" must be enabled.