Footer exposes a "Do Not Sell or Share" / "Your Privacy Choices" opt-out link
Why it matters
CCPA §1798.135(a)(1), as strengthened by the 2023 CPRA amendment, requires a literal-text "Do Not Sell or Share My Personal Information" link (or the state-approved alternate "Your Privacy Choices" link with the official blue-white icon) in the footer of any site that "sells or shares" personal data — and under CPRA, routing any identifier (IP, device ID, cookie ID) to ads, analytics, or retargeting counts as "sharing." Sephora paid $1.2M to the California AG in 2022 for missing exactly this link, and the Connecticut, Colorado, Virginia, and Utah parallel statutes each layer additional $7,500-per-violation exposure on top. AI coding tools reliably bolt Google Analytics, PostHog, Meta Pixel, or TikTok Pixel into a Next.js layout — because "add analytics" is a two-line copy-paste — but almost never scaffold the matching opt-out link, because the obligation only triggers once the pixel is present. The quiet failure mode is a site that successfully tracks California visitors while silently accruing per-visitor violations.
Severity rationale
High because California AG enforcement has shown a clear willingness to settle for seven figures on the missing-link vector alone, the exposure scales linearly with California visitor volume, and parallel CPA / CTDPA / CDPA regimes compound it.
Remediation
Add a /privacy/opt-out (or /do-not-sell) route that handles opt-out requests (cookie drop + downstream pixel disabling), then link to it from the site footer with the exact California-approved text:
// components/Footer.tsx
<Link href="/privacy/opt-out">Do Not Sell or Share My Personal Information</Link>
The alternate compliant text is "Your Privacy Choices" paired with the California blue-white opt-out icon (see oag.ca.gov/privacy/ccpa/icons-download). Deeper coverage of the full CPRA opt-out flow (global privacy control signals, sensitive PI limits, authorized agent handling) lives in the ccpa-readiness Pro audit.
Detection
- ID:
do-not-sell-or-opt-out-link - Severity:
high - What to look for: First determine whether the site "sells or shares" personal data under CPRA — practically, whether any analytics / advertising / retargeting / session-replay library is loaded. Scan
package.jsonfor:posthog-js,@vercel/analytics,@vercel/speed-insights,react-ga,react-ga4,@segment/analytics-next,mixpanel-browser,@hotjar/browser,@amplitude/*,@microsoft/clarity,next-plausible,@intercom/messenger-js-sdk,react-facebook-pixel,react-tiktok-pixel,react-linkedin-insight-tag. Also grep<script>,<Script>, and string literals forgoogletagmanager.com,google-analytics.com,gtag(,fbevents.js,fbq(,tiktok.com/i18n/pixel,snap.licdn.com,analytics.tiktok.com. If any match, the site is in-scope. Then look for the opt-out link: grep the codebase for text matching/Do Not Sell( or Share)?( My Personal Information)?/iOR/Your Privacy Choices/i. Evidence locations:app/layout.tsx,app/_layout.tsx, any component file whose name matches/footer/i, orcomponents/Footer.tsx/components/site-footer.tsx. The match must be inside a rendered link / button, not just a comment. - Pass criteria: Either no tracking/analytics/ad libraries are detected (site out of scope), OR tracking is detected AND a visible footer link containing the exact text "Do Not Sell or Share My Personal Information" or "Your Privacy Choices" is present.
- Fail criteria: Tracking / analytics / ad / retargeting is detected AND no matching opt-out link text is found in the footer or any persistent navigation surface.
- Skip (N/A) when: No analytics, ad, retargeting, or tracking pixel is detected anywhere in the codebase. Quote:
"No analytics or ad pixel detected — CPRA §1798.135 does not apply." - Do NOT pass when: A privacy policy page exists and mentions opt-out rights in prose, but no literal-text link appears in the footer or persistent navigation. CPRA §1798.135 requires a link, not just prose.
- Before evaluating, quote: Quote the tracking evidence (dependency name or script URL) AND the matching footer link text with its surrounding JSX / HTML, or state
"No match for Do-Not-Sell / Privacy-Choices text in any footer or layout file." - Report even on pass:
"Tracking detected: <libraries>; opt-out link text '<exact text>' at <file>:<line>." - Detail on fail:
"Google Analytics 4 loaded via app/layout.tsx (@vercel/analytics in package.json; gtag call in app/_components/Analytics.tsx) but no 'Do Not Sell' or 'Your Privacy Choices' link found in components/Footer.tsx or app/layout.tsx." - Remediation: Add a
/privacy/opt-out(or/do-not-sell) route that handles opt-out requests, then link to it from the site footer with the exact California-approved text (seeremediation_proseabove). Deeper coverage lives in theccpa-readinessPro audit.
External references
- ccpa:cal-civ-1798 · §1798.135 — Methods of submitting requests to opt-out and limit use of sensitive personal information
Taxons
History
- 2026-04-23·v1.0.0·Initial Phase 9.1 v3.1 Stack Scan promotion — CPRA requires literal opt-out link text in any site that shares personal data with analytics/ad pixels.·by phase-9-1-stack-scan-v3-1