managarten/apps/picture/docs/POSTHOG_SETUP.md
Wuesteon ff80aeec1f refactor: restructure
monorepo with apps/ and services/
  directories
2025-11-26 03:03:24 +01:00

11 KiB

PostHog Analytics Setup

This document describes how to set up PostHog Analytics for the Picture web application.

Overview

PostHog is a powerful product analytics platform that provides:

  • 📊 Product Analytics: Track user behavior and product usage
  • 🎯 Feature Flags: Roll out features gradually and A/B test
  • 📹 Session Recordings: Watch how users interact with your app
  • 🔥 Heatmaps: Visualize where users click and scroll
  • 👥 User Profiles: Understand individual user journeys

Architecture

Web App (SvelteKit)

  • Location: apps/web/src/lib/analytics/posthog.ts
  • Framework: SvelteKit
  • SDK: posthog-js
  • Integration: Initialized in root layout with automatic user identification

Configuration

PostHog is configured using environment variables:

PUBLIC_POSTHOG_KEY=phc_your_posthog_project_api_key
PUBLIC_POSTHOG_HOST=https://us.i.posthog.com  # or https://eu.i.posthog.com for EU

Environment Variables

Create or update apps/web/.env:

PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxx
PUBLIC_POSTHOG_HOST=https://us.i.posthog.com

Note

: The PUBLIC_ prefix is required in SvelteKit to expose variables to the client.

Features

🔐 Privacy-First Configuration

  • Identified Users Only: person_profiles: 'identified_only' - only tracks logged-in users
  • localStorage Persistence: Uses localStorage instead of cookies
  • No Autocapture: Manual event tracking for better control
  • Session Recording Disabled: Can be enabled if needed

🚀 Automatic Features

  • Pageview Tracking: Automatically tracks page navigation
  • Page Leave Tracking: Tracks when users leave pages
  • User Identification: Automatically identifies users on login/logout
  • User Properties: Tracks email and account creation date

📊 Current Implementation

User Identification

Users are automatically identified on login with:

  • User ID (from Supabase)
  • Email address
  • Account creation timestamp
// Automatically done on login
analytics.identify(user.id, {
  email: user.email,
  created_at: user.created_at
});

Session Management

  • Login: User is identified in PostHog
  • Logout: PostHog session is reset
  • Auth State Changes: PostHog identity is updated automatically

Setup Steps

1. Create PostHog Account

You have two options:

  1. Sign up at posthog.com
  2. Create a new project
  3. Select your region (US or EU)
  4. Copy your Project API Key (starts with phc_)

Option B: Self-Hosted PostHog

  1. Follow the PostHog deployment guide
  2. Deploy to your preferred platform
  3. Create a project
  4. Note your instance URL and API key

2. Configure Environment Variables

Development

  1. Copy .env.example to .env in apps/web:

    cd apps/web
    cp .env.example .env
    
  2. Add your PostHog credentials:

    PUBLIC_POSTHOG_KEY=phc_your_actual_api_key
    PUBLIC_POSTHOG_HOST=https://us.i.posthog.com  # or eu.i.posthog.com
    

Production

Add environment variables to your deployment platform:

Vercel:

vercel env add PUBLIC_POSTHOG_KEY
vercel env add PUBLIC_POSTHOG_HOST

Netlify:

  • Go to Site settings → Environment variables
  • Add PUBLIC_POSTHOG_KEY and PUBLIC_POSTHOG_HOST

Other platforms:

  • Follow your platform's documentation for environment variables
  • Ensure variables are prefixed with PUBLIC_

3. Verify Integration

  1. Start the development server:

    cd apps/web
    pnpm dev
    
  2. Open browser DevTools → Console

  3. Look for "PostHog loaded" message (in dev mode)

  4. Navigate between pages

  5. Log in with a test account

  6. Check PostHog dashboard for events

Usage

Tracking Custom Events

The analytics helper provides easy-to-use methods:

import { analytics } from '$lib/analytics/posthog';

// Track a custom event
analytics.track('button_clicked', {
  button_name: 'sign_up',
  page: '/pricing'
});

// Track image generation
analytics.track('image_generated', {
  model: 'flux-dev',
  prompt_length: 150,
  aspect_ratio: '16:9'
});

// Track feature usage
analytics.track('feature_used', {
  feature: 'batch_generation',
  count: 5
});

User Properties

Set additional user properties:

import { analytics } from '$lib/analytics/posthog';

analytics.setUserProperties({
  plan: 'pro',
  images_generated: 42,
  favorite_model: 'flux-dev'
});

Feature Flags

Use feature flags for gradual rollouts and A/B testing:

import { analytics } from '$lib/analytics/posthog';

// Check if a feature is enabled
const showNewUI = analytics.isFeatureEnabled('new_ui_redesign');

// Get feature flag value (for multivariate flags)
const buttonColor = analytics.getFeatureFlag('button_color_test');

Page View Tracking

Page views are tracked automatically. For manual tracking:

import { analytics } from '$lib/analytics/posthog';

// Track a specific page view
analytics.pageView('/custom-page');

Example Use Cases

Track Image Generation

// In your image generation component
import { analytics } from '$lib/analytics/posthog';

async function generateImage(prompt: string, settings: Settings) {
  // Track the generation attempt
  analytics.track('image_generation_started', {
    model: settings.model,
    prompt_length: prompt.length,
    aspect_ratio: settings.aspectRatio,
    num_images: settings.numImages
  });

  try {
    const result = await generateImageAPI(prompt, settings);

    // Track success
    analytics.track('image_generation_completed', {
      model: settings.model,
      generation_time_ms: result.duration
    });

    return result;
  } catch (error) {
    // Track errors
    analytics.track('image_generation_failed', {
      model: settings.model,
      error: error.message
    });
    throw error;
  }
}

Track User Engagement

// Track when users interact with images
analytics.track('image_liked', {
  image_id: image.id,
  model: image.model
});

analytics.track('image_shared', {
  image_id: image.id,
  platform: 'twitter'
});

analytics.track('image_downloaded', {
  image_id: image.id,
  format: 'png'
});

Track Feature Discovery

// Track when users discover features
analytics.track('feature_discovered', {
  feature: 'batch_generation',
  source: 'tooltip'
});

analytics.track('tutorial_completed', {
  tutorial: 'first_generation'
});

PostHog Dashboard

Key Metrics to Track

  1. User Engagement

    • Daily/Weekly/Monthly Active Users
    • Session duration
    • Pages per session
  2. Feature Usage

    • Image generation count
    • Most used models
    • Popular aspect ratios
    • Batch generation usage
  3. User Journey

    • Signup → First generation time
    • Feature adoption rate
    • Retention cohorts
  4. Errors & Issues

    • Generation failures
    • Error rates by model
    • API timeout frequency

Creating Insights

  1. Funnel Analysis

    Sign Up → First Generation → Image Download → Share
    
  2. Retention

    Track users who return after first generation
    
  3. Trends

    Image generations over time
    Model popularity trends
    

Feature Flags Setup

Create a Feature Flag

  1. Go to PostHog → Feature Flags
  2. Click "New feature flag"
  3. Set flag key (e.g., new_ui_redesign)
  4. Configure rollout percentage
  5. Save and deploy

Use in Code

<script lang="ts">
  import { analytics } from '$lib/analytics/posthog';
  import { onMount } from 'svelte';

  let showNewUI = false;

  onMount(() => {
    showNewUI = analytics.isFeatureEnabled('new_ui_redesign');
  });
</script>

{#if showNewUI}
  <NewUIComponent />
{:else}
  <OldUIComponent />
{/if}

Session Recordings (Optional)

Session recordings are disabled by default for privacy. To enable:

  1. Update apps/web/src/lib/analytics/posthog.ts:

    disable_session_recording: false, // Enable recordings
    
  2. Configure in PostHog dashboard:

    • Set recording sample rate
    • Configure privacy settings
    • Set up retention period
  3. Add privacy notice to your app

Privacy & Compliance

GDPR Compliance

  • Only tracks identified (logged-in) users
  • Users can opt-out via PostHog settings
  • Data retention policies can be configured
  • Personal data can be deleted on request

User Opt-Out

To allow users to opt-out:

import posthog from '$lib/analytics/posthog';

// Opt user out
posthog.opt_out_capturing();

// Opt user back in
posthog.opt_in_capturing();

Data Deletion

To delete user data (on account deletion):

import { analytics } from '$lib/analytics/posthog';

// Reset all user data
analytics.reset();

Troubleshooting

PostHog Not Loading

  • Verify PUBLIC_POSTHOG_KEY is set correctly
  • Check PUBLIC_POSTHOG_HOST matches your region
  • Ensure environment variables have PUBLIC_ prefix
  • Restart dev server after adding env vars

No Events in Dashboard

  • Verify API key matches PostHog project
  • Check browser console for errors
  • Ensure user is logged in (only tracks identified users)
  • Check ad blocker isn't blocking requests

Feature Flags Not Working

  • Wait a few minutes after creating flag
  • Verify flag key matches code
  • Check user is identified
  • Ensure flag is enabled in PostHog

Development vs Production

  • Development: All events are tracked, console logging enabled
  • Production: Production mode, no console logs
  • Testing: Use a separate PostHog project for testing

Advanced Configuration

Custom Initialization

To customize PostHog initialization, edit apps/web/src/lib/analytics/posthog.ts:

posthog.init(PUBLIC_POSTHOG_KEY, {
  api_host: PUBLIC_POSTHOG_HOST,

  // Capture settings
  capture_pageview: true,
  capture_pageleave: true,

  // Session settings
  session_recording: {
    recordCrossOriginIframes: false,
    maskAllInputs: true,
    maskTextSelector: '.sensitive'
  },

  // Privacy settings
  respect_dnt: true,
  opt_out_capturing_by_default: false,

  // Performance
  persistence: 'localStorage',
  autocapture: false,

  // Advanced features
  enable_recording_console_log: true,
  disable_compression: false
});

Proxy Setup (Avoid Ad Blockers)

For production, proxy PostHog through your domain:

  1. Set up a reverse proxy (e.g., Cloudflare Worker)
  2. Update PUBLIC_POSTHOG_HOST to your proxy URL
  3. Configure CORS headers

Example Cloudflare Worker:

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  url.hostname = 'us.i.posthog.com'

  return fetch(url, {
    method: request.method,
    headers: request.headers,
    body: request.body
  })
}

Resources

Support

For issues specific to:

  • PostHog Platform: PostHog Support
  • Integration Code: Create an issue in this repository
  • Privacy/Compliance: Consult with your legal team