Skip to content

[codex] add cookie consent modal#123

Merged
ohong merged 2 commits into
mainfrom
codex/cookie-consent-gdpr
Jun 2, 2026
Merged

[codex] add cookie consent modal#123
ohong merged 2 commits into
mainfrom
codex/cookie-consent-gdpr

Conversation

@ohong

@ohong ohong commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add a landing-page cookie consent modal with essential-only and all-cookies choices.
  • Gate PostHog and Vercel Analytics behind analytics consent while leaving Supabase Auth cookies operational.
  • Add a consent API route, consent parsing helpers, and focused regression tests.
  • Clean up local Next frontend issues from dev CSP, local Supabase fallback logging, and unsupported OG ImageResponse z-index styles.

Why

The landing page needed a lightweight cookie consent flow that distinguishes essential platform cookies from analytics cookies. The implementation keeps Supabase Auth integrated with Next.js while preventing analytics libraries from initializing until users explicitly opt in.

Validation

  • bun --cwd apps/web test __tests__/unit/cookie-consent.test.ts __tests__/api/cookie-consent.test.ts
  • bun --cwd apps/web lint
  • bun --cwd apps/web typecheck
  • bun --cwd apps/web test:e2e e2e/landing.spec.ts
  • In-app Browser check on http://localhost:3000: no Next issue badge and zero new console warnings/errors after fresh navigation.

Summary by CodeRabbit

  • New Features

    • Cookie consent modal now displays on initial visit, allowing users to choose between essential-only or full cookie acceptance
    • Analytics capabilities now require explicit user opt-in and are disabled by default
    • Referrer functionality respects user cookie preferences
  • Documentation

    • Updated Privacy Policy to document opt-in analytics, cookie practices, and third-party service usage

@vercel

vercel Bot commented Jun 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
straude Ready Ready Preview, Comment Jun 2, 2026 7:33am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements a complete cookie consent system that lets users control analytics data collection. It introduces a consent API endpoint, client-side state management via React hooks, a user-facing modal, and gates Vercel Analytics and PostHog behind the user's preference while updating privacy documentation.

Changes

Cookie Consent Infrastructure

Layer / File(s) Summary
Cookie consent contract, utilities, and API endpoint
apps/web/lib/cookie-consent.ts, apps/web/app/api/cookie-consent/route.ts, apps/web/__tests__/unit/cookie-consent.test.ts, apps/web/__tests__/api/cookie-consent.test.ts
Defines CookieConsentPreference ("essential" | "all"), CookieConsentState with an analytics boolean, and exports serialization/parsing helpers. The POST /api/cookie-consent endpoint validates and persists preferences with secure, environment-aware cookies. Unit and integration tests verify round-trip serialization, cookie extraction, and API validation.
Analytics consent hook and consent-aware providers
apps/web/components/providers/useAnalyticsConsent.ts, apps/web/components/providers/ConsentAwareAnalytics.tsx, apps/web/app/layout.tsx
useAnalyticsConsent tracks analytics state across custom events and cookies via useSyncExternalStore. ConsentAwareAnalytics conditionally renders Vercel Analytics based on the hook. The root layout integrates the gated analytics component.
Consent modal and landing layout integration
apps/web/components/landing/CookieConsentModal.tsx, apps/web/app/(landing)/layout.tsx
CookieConsentModal reads initial consent, renders a dialog with "Accept essential" and "Accept all" buttons, POSTs the preference to the API, dispatches a COOKIE_CONSENT_EVENT on success, and closes. The landing layout renders the modal alongside children.
Existing components consent integration
apps/web/app/(landing)/join/[username]/ref-cookie.tsx, apps/web/components/providers/PostHogProvider.tsx
RefCookie defers cookie setting until consent is present, listening for COOKIE_CONSENT_EVENT if needed. PostHogClientProvider gates initialization on useAnalyticsConsent() and re-runs setup when consent changes.
Documentation, testing, and configuration improvements
apps/web/app/(landing)/privacy/page.tsx, apps/web/app/(landing)/join/[username]/opengraph-image.tsx, apps/web/app/opengraph-image.tsx, apps/web/lib/open-stats.ts, apps/web/next.config.ts
Privacy policy updated with June 2, 2026 date, opt-in analytics language, and PostHog disclosure. Removed unnecessary zIndex styles from OpenGraph images. OpenStats error logging suppresses noisy local Supabase connection failures. CSP script-src now conditionally includes "'unsafe-eval'" only in development.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ohong/straude#90: Fixes build and runtime import errors in PostHogProvider.tsx by declaring posthog-js as a direct dependency, directly relevant to the provider modifications in this PR.
  • ohong/straude#111: Modifies apps/web/lib/open-stats.ts error handling paths, which overlaps with the OpenStats error logging improvements in this PR.

Poem

🐰 A modal springs forth, soft and bright,
"Choose your consent," invites the sight!
Analytics wait for your "aye,"
While cookies stay safe, oh my oh my!
PostHog and Vercel, both polite and true—
Only tracking what you say they'll do.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main change: adding a cookie consent modal to the landing page, which is the core feature of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cookie-consent-gdpr

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ohong ohong marked this pull request as ready for review June 2, 2026 07:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/web/lib/cookie-consent.ts (2)

25-25: 💤 Low value

Consider trimming the decoded value for robustness.

While browsers typically don't include leading/trailing whitespace in cookie values, adding .trim() after decodeURIComponent(value) would make the parser more defensive against edge cases.

♻️ Optional defensive improvement
-  const decoded = decodeURIComponent(value);
+  const decoded = decodeURIComponent(value).trim();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/cookie-consent.ts` at line 25, The decoded cookie value should
be trimmed to guard against stray whitespace: update the assignment to apply
.trim() after decodeURIComponent(value) (i.e., change the usage of the decoded
variable created from decodeURIComponent(value) to
decodeURIComponent(value).trim()) wherever the cookie parsing sets the decoded
variable so the parser becomes more defensive.

37-46: 💤 Low value

Consider using a cookie parsing library for robustness.

The manual string parsing works correctly for standard cookie strings, but a library like cookie would handle more edge cases and be more maintainable. This is a minor nice-to-have improvement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/cookie-consent.ts` around lines 37 - 46, Replace the manual
cookie-string splitting in getCookieConsentFromCookieString with a robust cookie
parser: import a cookie parsing library (e.g., the cookie package) and use its
parse function to extract the COOKIE_CONSENT_COOKIE value, then pass that value
to parseCookieConsent and return the result (or null if undefined). Keep
references to COOKIE_CONSENT_COOKIE and parseCookieConsent unchanged so callers
and downstream parsing remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/web/lib/cookie-consent.ts`:
- Line 25: The decoded cookie value should be trimmed to guard against stray
whitespace: update the assignment to apply .trim() after
decodeURIComponent(value) (i.e., change the usage of the decoded variable
created from decodeURIComponent(value) to decodeURIComponent(value).trim())
wherever the cookie parsing sets the decoded variable so the parser becomes more
defensive.
- Around line 37-46: Replace the manual cookie-string splitting in
getCookieConsentFromCookieString with a robust cookie parser: import a cookie
parsing library (e.g., the cookie package) and use its parse function to extract
the COOKIE_CONSENT_COOKIE value, then pass that value to parseCookieConsent and
return the result (or null if undefined). Keep references to
COOKIE_CONSENT_COOKIE and parseCookieConsent unchanged so callers and downstream
parsing remain consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d9f7a4c0-7cbb-442e-8e92-186414630af0

📥 Commits

Reviewing files that changed from the base of the PR and between a10865c and d4d5cdb.

📒 Files selected for processing (16)
  • apps/web/__tests__/api/cookie-consent.test.ts
  • apps/web/__tests__/unit/cookie-consent.test.ts
  • apps/web/app/(landing)/join/[username]/opengraph-image.tsx
  • apps/web/app/(landing)/join/[username]/ref-cookie.tsx
  • apps/web/app/(landing)/layout.tsx
  • apps/web/app/(landing)/privacy/page.tsx
  • apps/web/app/api/cookie-consent/route.ts
  • apps/web/app/layout.tsx
  • apps/web/app/opengraph-image.tsx
  • apps/web/components/landing/CookieConsentModal.tsx
  • apps/web/components/providers/ConsentAwareAnalytics.tsx
  • apps/web/components/providers/PostHogProvider.tsx
  • apps/web/components/providers/useAnalyticsConsent.ts
  • apps/web/lib/cookie-consent.ts
  • apps/web/lib/open-stats.ts
  • apps/web/next.config.ts
💤 Files with no reviewable changes (2)
  • apps/web/app/opengraph-image.tsx
  • apps/web/app/(landing)/join/[username]/opengraph-image.tsx

@ohong ohong merged commit 7fbaf00 into main Jun 2, 2026
5 of 7 checks passed
@ohong ohong deleted the codex/cookie-consent-gdpr branch June 9, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant