# Opt-out mechanism functional, easy to use, no account required

- **Pattern:** `ab-000632` (`ccpa-readiness.opt-out.opt-out-mechanism-functional`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000632
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000632)

## Why it matters

CCPA § 1798.120(a) grants every consumer — not just authenticated users — the right to opt out of the sale or sharing of their personal information. § 1798.135(a)(2) explicitly prohibits businesses from requiring consumers to create an account or log in to exercise this right. An opt-out page that returns a 404, requires authentication, stores the preference in `sessionStorage` only, or resets on next visit fails on multiple statutory requirements simultaneously. These failures also cannot be fixed client-side at runtime — they require a working deployment, an accessible route, and persistent server-side storage as the fallback when cookies are cleared.

## Severity rationale

Low because functional failures of an existing opt-out mechanism are harder to detect than its total absence, but requiring authentication to opt out is an explicit statutory prohibition under CCPA § 1798.135(a)(2).

## Remediation

Verify the `/do-not-sell` route is deployed and returns a 200, works without authentication, stores preference in a one-year cookie (not `sessionStorage`), and displays an immediate confirmation.

```tsx
// app/do-not-sell/page.tsx — no auth required, persistent storage, clear confirmation
'use client'
import { useState } from 'react'

export default function DoNotSellPage() {
  const [done, setDone] = useState(false)

  async function optOut() {
    document.cookie = 'ccpa_opt_out=1; max-age=31536000; path=/; SameSite=Lax; Secure'
    try { await fetch('/api/privacy/opt-out', { method: 'POST' }) } catch {}
    setDone(true)
  }

  return (
    <main>
      <h1>Do Not Sell or Share My Personal Information</h1>
      <p>No account required to exercise this right (CCPA § 1798.120).</p>
      {done ? (
        <div role="alert"><strong>Opt-out recorded.</strong> Preference saved for one year.</div>
      ) : (
        <button onClick={optOut}>Opt Out of Sale/Sharing</button>
      )}
    </main>
  )
}
```

Test the route with a fresh incognito session — no cookies, no login — and confirm the button works and the confirmation renders.

## Detection

- **ID:** `opt-out-mechanism-functional`
- **Severity:** `low`
- **What to look for:** Test the usability of the opt-out mechanism. Check whether the "Do Not Sell or Share" link navigates to a working page (not a 404 or a page that only describes the right). Verify the opt-out form or button works without the user needing to log in or create an account — CCPA explicitly prohibits requiring authentication to exercise opt-out rights. Check whether the mechanism works with JavaScript disabled or on low-end browsers (it does not need to, but check for graceful degradation). Verify the opt-out confirmation is immediate and clear — the user should know their opt-out was recorded. Check if the opt-out is preserved across sessions (persistent) and across subdomains if applicable. Count all instances found and enumerate each.
- **Pass criteria:** The opt-out mechanism is reachable via the footer link without authentication. The mechanism functions correctly (form submits, preference is stored, confirmation is displayed). Opt-out preference persists across browser sessions. At least 1 implementation must be confirmed.
- **Fail criteria:** The opt-out page returns a 404 or is empty. Opt-out mechanism requires authentication. Form submits but no confirmation is displayed. Opt-out preference is stored only in sessionStorage (clears on tab close) rather than a persistent cookie or server-side record. Do NOT pass if the opt-out mechanism requires authentication — CCPA requires opt-out to work without an account.
- **Skip (N/A) when:** Application does not sell or share PI — document.
- **Detail on fail:** Example: `"'Do Not Sell or Share' link in footer leads to /do-not-sell which returns a 404 error."` or `"Opt-out form requires signing in before submission — this is an impermissible barrier."` or `"Opt-out stored in sessionStorage only; preference lost when browser tab is closed."`.
- **Remediation:** Verify the opt-out route is deployed and accessible, ensure persistent storage, and add clear confirmation UI:

  ```tsx
  // app/do-not-sell/page.tsx — verify this route exists and is functional
  export default function DoNotSellPage() {
    const [status, setStatus] = useState<'idle' | 'done'>('idle')

    async function optOut() {
      // Persistent cookie — survives session
      document.cookie = 'ccpa_opt_out=1; max-age=31536000; path=/; SameSite=Lax; Secure'
      // Also persist server-side for authenticated users
      try {
        await fetch('/api/privacy/opt-out', { method: 'POST' })
      } catch {
        // Best-effort server persistence; cookie is the fallback
      }
      setStatus('done')
    }

    return (
      <main>
        <h1>Do Not Sell or Share My Personal Information</h1>
        <p>
          Under California law (CCPA/CPRA), you have the right to direct us not
          to sell or share your personal information with third parties.
          No account is required to exercise this right.
        </p>
        {status === 'done' ? (
          <div role="alert">
            <strong>Your opt-out has been recorded.</strong> We will not sell or
            share your personal information. This preference is saved for one year.
          </div>
        ) : (
          <button onClick={optOut}>
            Opt Out of Sale/Sharing
          </button>
        )}
      </main>
    )
  }
  ```

---

## External references

- ccpa §1798.120(a)
- ccpa §1798.135(a)(2)
- gdpr Art. 7(3)

Taxons: privacy-consent, regulatory-conformance

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