搜索

PythonReactSEOPDF
GitHub Skill

posthog

Implement PostHog analytics for PhotoVault with dual tracking (client + server). Use when working with event tracking, funnel analysis, user identification, TypeScript event schemas, ad-blocker-proof server-side tracking, or debugging missing analytics data. Includes PhotoVault event definitions and privacy defaults.

nathanielcrowell12-spec☆ 0 仓库 Stars0 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

⚠️ MANDATORY WORKFLOW - DO NOT SKIP

When this skill activates, you MUST follow the expert workflow before writing any code:

  1. Spawn Domain Expert using the Task tool with this prompt:

    Read the expert prompt at: C:\Users\natha\Stone-Fence-Brain\VENTURES\PhotoVault\claude\experts\posthog-expert.md
    
    Then research the codebase and write an implementation plan to: docs/claude/plans/posthog-[task-name]-plan.md
    
    Task: [describe the user's request]
    
  2. Spawn QA Critic after expert returns, using Task tool:

    Read the QA critic prompt at: C:\Users\natha\Stone-Fence-Brain\VENTURES\PhotoVault\claude\experts\qa-critic-expert.md
    
    Review the plan at: docs/claude/plans/posthog-[task-name]-plan.md
    Write critique to: docs/claude/plans/posthog-[task-name]-critique.md
    
  3. Present BOTH plan and critique to user - wait for approval before implementing

DO NOT read files and start coding. DO NOT rationalize that "this is simple." Follow the workflow.


PostHog Analytics Integration

Core Principles

Dual Tracking is Non-Negotiable

Ad blockers block PostHog's client-side library in 30%+ of browsers. Critical funnel events MUST use server-side tracking.

// CRITICAL EVENTS → Server-side (can't be blocked)
// - Signup, payment, churn, subscription changes
// - Anything that affects revenue attribution

// ENGAGEMENT EVENTS → Client-side (okay if some are blocked)
// - Page views, button clicks, gallery browsing

Rule of thumb: If losing 30% of this event would break your funnel analysis, it MUST be server-side.

TypeScript Event Schemas Prevent Chaos

Without strict types, you'll end up with gallery_id, galleryId, gallery-id, and GalleryId in your data.

// src/types/analytics.ts - EVERY event name and properties defined here
import { GalleryViewedEvent } from '@/types/analytics'
trackEvent<GalleryViewedEvent>('gallery_viewed', {
  gallery_id: '123',  // Type error if wrong name
})
Identify Users Early and Consistently
posthog.identify(user.id, {
  user_type: 'photographer' | 'client',
  signup_date: user.created_at,
})

Anti-Patterns

Only client-side tracking for critical events

// WRONG: 30%+ blocked by ad blockers
posthog.capture('payment_completed', { amount: 100 })

// RIGHT: Server-side for critical funnel events
await posthog.capture({
  distinctId: userId,
  event: 'payment_completed',
  properties: { amount: 100, $source: 'server' }
})

Inconsistent property naming

// WRONG: Different properties in PostHog
{ gallery_id: '123' }
{ galleryId: '123' }
{ GalleryId: '123' }

// RIGHT: Use TypeScript types
trackEvent<GalleryViewedEvent>('gallery_viewed', { gallery_id: '123' })

Forgetting to flush server-side events

// WRONG: Events lost if process exits
posthog.capture({ distinctId, event, properties })

// RIGHT: Flush in serverless
posthog.capture({ distinctId, event, properties })
await posthog.flush()

Blocking user actions on analytics

// WRONG: User waits
await posthog.capture('form_submitted')
router.push('/success')

// RIGHT: Fire and forget
posthog.capture('form_submitted')
router.push('/success')

Client-Side Setup

// src/lib/analytics/client.ts
import posthog from 'posthog-js'

export function initPostHog() {
  if (typeof window === 'undefined') return

  posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
    api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://app.posthog.com',
    capture_pageviews: true,
    respect_dnt: true,
    disable_session_recording: true,
    persistence: 'localStorage',
  })
}

export function identifyUser(userId: string, properties: Record<string, unknown>) {
  posthog.identify(userId, properties)
}

export function resetAnalytics() {
  posthog.reset()
}

export function trackEvent(eventName: string, properties?: Record<string, unknown>) {
  posthog.capture(eventName, properties)
}

Server-Side Setup

// src/lib/analytics/server.ts
import { PostHog } from 'posthog-node'

let posthogClient: PostHog | null = null

function getPostHogClient(): PostHog {
  if (!posthogClient) {
    posthogClient = new PostHog(process.env.POSTHOG_API_KEY!, {
      host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://app.posthog.com',
      flushAt: 1,
      flushInterval: 0,
    })
  }
  return posthogClient
}

export async function trackServerEvent(
  userId: string,
  eventName: string,
  properties?: Record<string, unknown>
) {
  const client = getPostHogClient()
  client.capture({
    distinctId: userId,
    event: eventName,
    properties: { ...properties, $source: 'server' },
  })
  await client.flush()
}

usePageView Hook

// src/hooks/useAnalytics.ts
'use client'

import { useEffect, useRef } from 'react'
import { trackEvent } from '@/lib/analytics/client'

export function usePageView(pageName: string, properties?: Record<string, unknown>) {
  const startTimeRef = useRef<number>(Date.now())
  const hasTrackedRef = useRef<boolean>(false)

  useEffect(() => {
    if (!hasTrackedRef.current) {
      trackEvent(`${pageName}_viewed`, properties)
      hasTrackedRef.current = true
      startTimeRef.current = Date.now()
    }

    return () => {
      const durationSeconds = Math.round((Date.now() - startTimeRef.current) / 1000)
      trackEvent(`${pageName}_left`, { ...properties, duration_seconds: durationSeconds })
    }
  }, [pageName])
}

PhotoVault Configuration

Critical Server-Side Events
Event Trigger Why Critical
photographer_signed_up Signup API Top of funnel
photographer_connected_stripe Connect callback Conversion milestone
client_payment_completed Stripe webhook Revenue event
client_payment_failed Stripe webhook Churn risk signal
photographer_churned Cancel subscription Retention metric
Environment Variables
NEXT_PUBLIC_POSTHOG_KEY=phc_...
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
POSTHOG_API_KEY=phc_...  # Same key, server-side
Free Tier Limit

PostHog free tier: 1 million events/month. Set alert at 800K.

Debugging Checklist

  1. Check PostHog Dashboard → Activity → Live Events
  2. Verify user identification with posthog.debug() in dev
  3. Check server-side events have $source: 'server' property
  4. Verify flush is called in serverless functions
  5. Test with ad blocker enabled (server events should still work)

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-01-26
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!