Skip to main content
ZeroStarter integrates PostHog for comprehensive product analytics, giving you insights into user behavior, feature usage, and application performance.

Setup

PostHog is pre-configured and ready to use. Simply add your PostHog project credentials to enable analytics.
1
Create PostHog project
2
  • Sign up at posthog.com or self-host PostHog
  • Create a new project
  • Copy your Project API Key from Project Settings
  • 3
    Configure environment variables
    4
    Add your PostHog credentials to .env:
    5
    # Optional: PostHog Analytics (https://zerostarter.dev/docs/features/analytics)
    NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
    NEXT_PUBLIC_POSTHOG_KEY=phc_your_project_api_key
    
    6
    PostHog offers multiple hosting regions. Use https://us.i.posthog.com for US hosting or https://eu.i.posthog.com for EU hosting.
    7
    Start tracking
    8
    Once configured, PostHog automatically tracks:
    9
  • Page views
  • User sessions
  • Custom events (when you add them)
  • Feature flag evaluations
  • Architecture

    PostHog is initialized at the application root and provided via React Context.
    app/providers.tsx
    "use client"
    
    import { isProduction } from "@packages/env"
    import { env } from "@packages/env/web-next"
    import { PostHogProvider } from "@posthog/react"
    import posthog from "posthog-js"
    import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
    import { ThemeProvider as NextThemesProvider } from "next-themes"
    import { useState } from "react"
    
    export function OuterProvider({ children }: { children: React.ReactNode }) {
      const [queryClient] = useState(() => new QueryClient())
    
      return (
        <PostHogProvider client={posthog}>
          <QueryClientProvider client={queryClient}>
            {children}
          </QueryClientProvider>
        </PostHogProvider>
      )
    }
    
    PostHog is wrapped in the OuterProvider to ensure it’s available throughout your application, including in Server Components via Client Components.

    Event Tracking

    Track custom events to understand how users interact with your application.

    Client Components

    Use the usePostHog hook in Client Components:
    app/components/signup-button.tsx
    "use client"
    
    import { usePostHog } from "@posthog/react"
    import { Button } from "@/components/ui/button"
    
    export function SignupButton() {
      const posthog = usePostHog()
    
      const handleSignup = () => {
        posthog.capture("signup_clicked", {
          source: "homepage",
          plan: "free",
        })
        // ... signup logic
      }
    
      return <Button onClick={handleSignup}>Sign Up</Button>
    }
    

    Track user properties

    Identify users and set properties:
    import { usePostHog } from "@posthog/react"
    import { useEffect } from "react"
    
    export function UserTracker({ user }: { user: User }) {
      const posthog = usePostHog()
    
      useEffect(() => {
        if (user) {
          posthog.identify(user.id, {
            email: user.email,
            name: user.name,
            created_at: user.createdAt,
          })
        }
      }, [user, posthog])
    
      return null
    }
    

    Common events to track

    // User signs up
    posthog.capture("user_signed_up", {
      provider: "github",
      referrer: document.referrer,
    })
    
    // User upgrades plan
    posthog.capture("plan_upgraded", {
      from_plan: "free",
      to_plan: "pro",
      billing_cycle: "monthly",
    })
    
    // User completes onboarding
    posthog.capture("onboarding_completed", {
      steps_completed: 5,
      time_taken_seconds: 180,
    })
    

    Feature Flags

    Feature flags allow you to control feature rollouts, run A/B tests, and toggle features without deploying code.

    Create a feature flag

    1
    In PostHog Dashboard
    2
  • Go to Feature Flags in your PostHog project
  • Click “New feature flag”
  • Set the flag key (e.g., new-dashboard)
  • Configure rollout percentage or user targeting
  • Save the flag
  • 3
    Use in your application
    4
    Check feature flags in Client Components:
    5
    "use client"
    
    import { useFeatureFlagEnabled } from "@posthog/react"
    import { NewDashboard } from "@/components/new-dashboard"
    import { OldDashboard } from "@/components/old-dashboard"
    
    export default function DashboardPage() {
      const isNewDashboard = useFeatureFlagEnabled("new-dashboard")
    
      if (isNewDashboard) {
        return <NewDashboard />
      }
    
      return <OldDashboard />
    }
    
    6
    Variant flags
    7
    Use multi-variant flags for A/B testing:
    8
    import { useFeatureFlagVariantKey } from "@posthog/react"
    
    export function PricingPage() {
      const pricingVariant = useFeatureFlagVariantKey("pricing-test")
    
      return (
        <div>
          {pricingVariant === "control" && <PricingControl />}
          {pricingVariant === "test-a" && <PricingTestA />}
          {pricingVariant === "test-b" && <PricingTestB />}
        </div>
      )
    }
    

    Session Replay

    PostHog automatically records user sessions, allowing you to replay user interactions and debug issues.
    Session replay is enabled by default in PostHog. You can configure privacy settings like masking sensitive inputs in your PostHog project settings.

    Configure privacy

    Mask sensitive data:
    // In PostHog dashboard, or via code:
    posthog.init("your_api_key", {
      session_recording: {
        maskAllInputs: true,
        maskTextSelector: ".sensitive",
      },
    })
    

    View replays

    1. Go to Session Replay in PostHog
    2. Filter by user, date, or custom events
    3. Watch session recordings with console logs and network activity
    4. Debug issues by seeing exactly what users experienced

    Analytics in Production

    Analytics are only tracked when NEXT_PUBLIC_POSTHOG_KEY is set. Leave it empty in development to avoid polluting your analytics data.

    Environment-specific tracking

    Track different environments separately:
    .env.production
    NEXT_PUBLIC_POSTHOG_KEY=phc_production_key
    
    .env.staging
    NEXT_PUBLIC_POSTHOG_KEY=phc_staging_key
    

    Opt-out support

    Respect user privacy preferences:
    import { usePostHog } from "@posthog/react"
    
    export function CookieConsent() {
      const posthog = usePostHog()
    
      const handleOptOut = () => {
        posthog.opt_out_capturing()
        // or
        posthog.opt_in_capturing() // to opt back in
      }
    
      return (
        <div>
          <button onClick={handleOptOut}>Opt out of analytics</button>
        </div>
      )
    }
    

    Performance Monitoring

    Track application performance metrics:
    import { usePostHog } from "@posthog/react"
    import { useEffect } from "react"
    
    export function PerformanceTracker() {
      const posthog = usePostHog()
    
      useEffect(() => {
        // Track page load time
        if (window.performance) {
          const loadTime = window.performance.timing.loadEventEnd - 
                           window.performance.timing.navigationStart
          
          posthog.capture("page_load_time", {
            load_time_ms: loadTime,
            page: window.location.pathname,
          })
        }
      }, [posthog])
    
      return null
    }
    

    DevTools

    PostHog is integrated with the development tools panel (only shown in development):
    app/providers.tsx
    import { DevTools } from "@/components/devtools"
    import { isProduction } from "@packages/env"
    import { env } from "@packages/env/web-next"
    
    export function OuterProvider({ children }: { children: React.ReactNode }) {
      return (
        <PostHogProvider client={posthog}>
          <QueryClientProvider client={queryClient}>
            {children}
            {!isProduction(env.NEXT_PUBLIC_NODE_ENV) && <DevTools />}
          </QueryClientProvider>
        </PostHogProvider>
      )
    }
    

    Best Practices

    Use clear, consistent naming conventions:
    • user_signed_up, project_created, plan_upgraded
    • click, event1, action
    Add relevant properties to understand the event:
    posthog.capture("feature_used", {
      feature_name: "export",
      export_format: "csv",
      record_count: 100,
      user_plan: "pro",
    })
    
    Track errors to understand where users struggle:
    try {
      await createProject()
      posthog.capture("project_created")
    } catch (error) {
      posthog.capture("project_creation_failed", {
        error_message: error.message,
      })
    }
    
    • Never track PII (passwords, credit cards, SSNs) in events
    • Use PostHog’s masking features for sensitive data
    • Implement opt-out functionality
    • Be transparent about what you track

    Next Steps

    PostHog Docs

    Learn about PostHog’s features and integrations

    UI Components

    Build beautiful interfaces to track user interactions

    Build docs developers (and LLMs) love