Route browser analytics through first-party API
Summary
- Move browser analytics capture to
/api/analytics/browser-events, an allowlisted first-party route that forwards to PostHog server-side. - Disable PostHog browser SDK network capture surfaces while keeping local distinct-id persistence for attribution.
- Send pageviews, clicks, and waitlist signups through the first-party helper instead of direct
r.cmux.comor/e/browser requests.
Testing
bun test tests/browser-analytics-route.test.tsbun run typecheckbunx eslint app/[locale]/posthog.tsx app/[locale]/(landing)/tracked-link.tsx app/[locale]/components/download-button.tsx app/[locale]/components/faq-platform-answer.tsx app/[locale]/components/github-button.tsx app/[locale]/components/github-stars.tsx app/[locale]/components/nav-links.tsx app/[locale]/components/pro-cta-link.tsx app/[locale]/components/waitlist-callout.tsx app/[locale]/components/waitlist-dialog.tsx app/lib/analytics.ts app/api/analytics/browser-events/route.ts services/analytics/browserEventPolicy.ts tests/browser-analytics-route.test.tsbun run lintcurrently fails on unrelated pre-existing lint errors in billing/vault/test files.
Issues
- Related: user-reported uBlock Origin block of
https://r.cmux.com/i/v0/e/?...
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.
[!NOTE]
Medium Risk
Touches all marketing analytics and waitlist person properties in PostHog; misconfiguration of the new rate limiter or forwarding could drop events or block signups in production until env is set.
Overview
Browser analytics no longer posts directly to r.cmux.com from the client. Clicks, pageviews, and waitlist signups go through new helpers in app/lib/analytics.ts that POST to /api/analytics/browser-events, which allowlists events, sanitizes payloads, rate-limits on Vercel via CMUX_BROWSER_ANALYTICS_RATE_LIMIT_ID, and forwards to PostHog /batch/ server-side.
posthog-js is reconfigured so the SDK does not drive ingest: api_host points at a disabled path, autocapture/pageleave/session recording/surveys/flags/decide are off, and $pageview is sent via the first-party helper. The SDK remains mainly for get_distinct_id, with a localStorage/in-memory fallback when that is unavailable.
Waitlist signup stops using a direct browser POST to PostHog’s /e/ endpoint; it uses captureAnalyticsEvent and the route re-validates email, platforms, and distinctId before applying server-controlled $set / Early Access enrollment.
Landing and marketing UI components swap posthog.capture for captureAnalyticsClick (download, GitHub, pricing, pro CTA, tracked links, waitlist opens).
Reviewed by Cursor Bugbot for commit be9c2bc786ce36fdde523c4ffc9e4c41e1091a6b. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Route all browser analytics through a first‑party API that forwards events to PostHog server‑side, with a dedicated Vercel rate limiter, a persistent fallback distinct id, anonymous‑profile behavior for non‑signup events, and strict server validation for waitlist signups. This avoids uBlock/extension blocks on r.cmux.com while keeping attribution via the SDK or a local fallback.
-
New Features
- Added
/api/analytics/browser-eventsto allowlist events, sanitize payloads, rate‑limit via Vercel Firewall usingCMUX_BROWSER_ANALYTICS_RATE_LIMIT_ID, and forward to PostHog/batch/(returns 429 when limited, 503 if misconfigured). Sets$process_person_profile: falsefor forwarded events. - Validates waitlist signups: requires
distinctId === email, allowlists platforms, and normalizes$set/$set_once(adds$feature_enrollment/*); rejects invalid payloads before forwarding while preserving enrollment for valid signups. - Added
app/lib/analytics.tswithcaptureAnalyticsEventandcaptureAnalyticsClick, plus a stored fallback distinct id (localStorage with in‑memory backup).$pageviewand clicks use this helper. Tests cover forwarding, event validation (incl. waitlist), rate limiting, distinct‑id fallback, and profile‑processing behavior.
- Added
-
Refactors
- Replaced direct
posthog-jscaptures withcaptureAnalyticsClickacross links/buttons and routed waitlist signup through the first‑party API; UI waits for server acceptance. - Reconfigured
posthog-jsto not send network analytics (disabled autocapture, pageleave, session recording, surveys, flags/decide, and external dependency loading) and setapi_hostto a disabled path; SDK remains forget_distinct_idonly.
- Replaced direct
Summary by CodeRabbit
- New Features
- Added a browser analytics API endpoint that validates allowlisted events, enforces rate limiting, and forwards approved events for tracking.
- Bug Fixes / Improvements
- Centralized click and pageview tracking through a shared client analytics helper, removing direct third-party tracking calls across key UI flows.
- Improved waitlist tracking to use the shared helper, with safer delivery/acceptance handling.
- Added stricter event allowlisting, payload sanitization, and clearer handling for unknown and rate-limited requests.
- Added distinct-id fallback logic with local persistence when needed.
- Tests
- Added automated coverage for the analytics route and distinct-id behavior.