Analytics Overview
Privacy-friendly analytics providers and custom event tracking.
The analytics adapters live in apps/web/modules/analytics/provider. Choose none, google, plausible, pirsch, posthog, amplitude or custom through config.analytics.provider. none disables tracking by default.
Configure an adapter
Set the variable that matches the selected adapter before building the web app:
| Adapter | Public environment variable |
|---|---|
| Google Analytics | NEXT_PUBLIC_GOOGLE_ANALYTICS_ID |
| Plausible | NEXT_PUBLIC_PLAUSIBLE_URL (the tracked domain) |
| Pirsch | NEXT_PUBLIC_PIRSCH_CODE |
| PostHog | NEXT_PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_POSTHOG_HOST |
| Amplitude | NEXT_PUBLIC_AMPLITUDE_API_KEY, NEXT_PUBLIC_AMPLITUDE_SERVER_ZONE |
The client component in apps/web/modules/analytics/index.tsx loads the selected adapter with server rendering disabled. Merely adding credentials does not select a provider. The root layout currently decides whether to render tracking from config.analytics.provider; the admin analytics module toggle does not gate that script.
PostHog and Amplitude
Select posthog or amplitude in config.analytics.provider, then rebuild with the public project key. For PostHog, use your project's ingestion host; the default is https://us.i.posthog.com, with https://eu.i.posthog.com for EU projects. Amplitude defaults to US; set its server zone to EU for an EU project. These browser keys are public identifiers, never server management keys.
Both adapters wait for consent before initializing or sending custom events. The translated banner remembers the choice for 30 days. Allowing starts tracking immediately; declining keeps these SDKs inactive. Neither adapter auto-records page views, history changes, or sessions: the facade emits one sanitized page view per eligible route (no query string, fragment, or credential-bearing field) and only while consent holds and the route is not sensitive (/auth, /team/invitation, /checkout, /onboarding, /app/settings). Withdrawing consent, or navigating to a sensitive route, stops capture and discards queued events; returning to an eligible route resumes without a reload. These defaults apply to these two adapters; review the behavior of other analytics adapters separately.
Add your own service
Implement AnalyticsScript and useAnalytics in provider/custom.tsx, then select custom. useAnalytics returns trackEvent(event, data?) and must not call React hooks: the facade loads it asynchronously and invokes it conditionally after loading. Match the exported AnalyticsModule type from apps/web/modules/analytics/index.tsx. The current custom adapter is a placeholder that logs events locally.
For another named adapter, add its module, update the resolver in index.tsx and extend analyticsProviderIds in packages/config/providers.ts. Install any required browser SDK in the web workspace and update the lockfile. Umami, Mixpanel and Vercel Analytics are not bundled adapters.
See Structured Logging.