Build apps with PostHog
PostHog is the analytics layer in every Goodspeed app: consent-aware lazy init, a typed EVENTS catalog, feature flags, and A/B testing. Goodspeed generates PostHog as a standard part of every app, so the output is a working codebase from day one, not a scaffold you have to finish yourself.
WHAT GETS GENERATED
Built into every PostHog build
Every app Goodspeed generates with PostHog includes these production-ready patterns, wired together from the first build.
| Item | Description | Strength |
|---|---|---|
| lib/posthog.ts consent-aware lazy init | The PostHog client is not created at module load time. getPostHog() initializes it on first call, but only if GDPR analytics consent has been granted. | Privacy |
| hooks/useAnalytics.ts custom event hook | A React hook that wraps captureEvent and captureScreen from lib/posthog.ts, making event tracking a one-liner in any component. | Hook |
| lib/events.ts typed EVENTS catalog | A string-literal-union EVENTS type exports every declared event name. TypeScript rejects any captureEvent call that uses an undeclared string. | Type Safety |
| gasConfig.backend.posthog keys | PostHog API key and host live in gas.config.ts under backend.posthog, read by lib/posthog.ts on first initialization. | Configuration |
| Feature flags and A/B testing | posthog.isFeatureEnabled and posthog.getFeatureFlag are called in hooks/useFeatureFlag.ts to gate features and split-test UI variants. | Experimentation |
Source: the Goodspeed generation pipeline · Product Analytics
REAL GENERATED CODE
A snippet from a PostHog app the studio shipped
This pattern comes straight out of the production groundwork every Goodspeed app is generated on. The studio generates PostHog code like this for every app in the pipeline, not a hello-world sample you have to grow into a real app.
Consent-aware init
// lib/posthog.ts: lazy, consent-aware PostHog singleton let _posthog: PostHog | null = null; export async function getPostHog(): Promise<PostHog | null> { if (_posthog) return _posthog; const granted = await checkAnalyticsConsent(); if (!granted) return null; if (!apiKey) return null; _posthog = new PostHog(apiKey, { host, persistence: 'memory', bootstrap: { distinctId: await getAnonymousId() }, }); return _posthog; }
Today's log