Analytics Surfaces
The repository audit found PostHog wired into three web surfaces: landing, launchpad, and docs. Admin, annotate, and the Flutter frontend do not currently contain a PostHog SDK or initialization path.
Current wiringโ
| Surface | Initialization | Consent/session behavior | Identity |
|---|---|---|---|
| Landing | lazy @posthog/react provider using Vite env values | explicit analytics opt-in; SDK is not imported before consent; replay disabled | anonymous only |
| Launchpad | @posthog/react provider using Vite env values | loads for authorized users when configured; replay disabled | anonymous only |
| Docs | Docusaurus client module using customFields | loads after the private site hydrates; replay disabled | anonymous only |
| Admin | not wired | n/a | n/a |
| Annotate | not wired | n/a | n/a |
| Flutter frontend | not wired | n/a | n/a |
All three configured surfaces use the EU ingest host
https://eu.i.posthog.com. A PostHog project token is a client-side project
identifier, not a secret; administrative credentials must never be embedded in
a bundle.
Landing consent gateโ
The landing page is strict opt-in:
getConsentPreferences()reads the saved cookie choice.- Without
analytics: true,DeferredPostHogProviderrenders children without importing the PostHog React SDK. - Firebase Analytics follows the same decision and is dynamically imported only after opt-in.
cookieConsentUpdatedmounts analytics after a grant. Withdrawal unmounts PostHog and makestrackEventreject future Firebase events.
Tests in acesense-landing/src/firebase.test.ts and the landing entry/provider
tests pin the no-consent path. The HTML preconnect hints do not initialize an
analytics SDK or send an event, but they still reveal the destination to the
browser; revisit them if policy requires zero pre-consent connection hints.
Private surfacesโ
Launchpad and docs are available only after the server-side admin session gate. They currently collect anonymous page/navigation analytics without a separate cookie preference. Both disable session recording so confidential fundraising and internal documentation content is not replayed to PostHog.
If policy requires consent for workforce/internal analytics, add the same opt-in gate used by landing or remove analytics from these surfaces. That is a product/legal decision and is not implied by the current code.
No cross-surface identity todayโ
Sharing a project token does not by itself join a person across devices or
applications. None of the three wired surfaces calls posthog.identify, and
the Flutter app is not wired, so the earlier claimed web โ app person journey
does not exist.
Before adding identity:
- document the purpose and lawful basis;
- avoid sending email or other direct identifiers unless approved;
- define reset behavior on sign-out/shared devices;
- test aliasing and duplicate-person behavior;
- update the privacy notice and deletion/export path.
CSP and network policyโ
The private docs and launchpad servers use request nonces for every HTML script and style element. Their CSP allowlists exact PostHog ingest/asset origins, exact Firebase Auth API origins, the Firebase auth frame, and same-origin assets. Script attributes and wildcard subdomains are not allowed. Launchpad's replay setting also avoids loading the recorder for confidential pages.
Verificationโ
Run repository checks first:
cd acesense-landing
pnpm test
pnpm build
cd ../acesense-launchpad
pnpm lint
pnpm test
pnpm build:hosting
pnpm --dir functions test
cd ../acesense-docs/website
pnpm test
cd ../functions
pnpm test
Then verify from a clean browser profile:
- Landing before consent: no PostHog/Firebase Analytics SDK request or event.
- Landing after opt-in: expected EU ingest request appears.
- Landing after withdrawal: no new analytics events.
- Docs/launchpad as a non-admin: no private bundle is served.
- Docs/launchpad as an admin: pageview requests use the EU host and no replay recorder loads.
Provider dashboards and live network traces are external sources. Repository code can establish intended configuration, not whether production received an event or applied a specific retention setting.