From posthog-pack
Provides PostHog reference architecture for Next.js/React apps: event taxonomy, SDK layers (posthog-js/node), feature flags, hooks, file structure, and data pipelines.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin posthog-packThis skill is limited to using the following tools:
Production-grade architecture for PostHog analytics in a web application. Covers file structure, event taxonomy design, SDK initialization layers, feature flag management, group analytics for B2B, and data pipeline integration.
Generates minimal PostHog examples for event capture, identify, and feature flags using posthog-js (browser/React) and posthog-node (Node.js). For quick starts, testing, or learning SDK patterns.
Implements PostHog analytics for event tracking, user identification, feature flags, and dashboards in Next.js and React apps. Use when adding product analytics.
Adds PostHog product analytics events to track user actions. Installs and initializes SDK across frameworks like Next.js, Django, React Native. Use after features or PR reviews.
Share bugs, ideas, or general feedback.
Production-grade architecture for PostHog analytics in a web application. Covers file structure, event taxonomy design, SDK initialization layers, feature flag management, group analytics for B2B, and data pipeline integration.
posthog-js and posthog-node SDKs┌─────────────────────────────────────────────────────┐
│ Browser (posthog-js) │
│ $pageview, $autocapture, custom events, identify │
│ Feature flag evaluation, session recordings │
└────────────┬────────────────────────────────────────┘
│ HTTPS (direct or reverse proxy)
▼
┌─────────────────────────────────────────────────────┐
│ PostHog Cloud (us.i.posthog.com) │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ Events │ │ Feature │ │ Session Replay │ │
│ │ Pipeline │ │ Flags │ │ & Recordings │ │
│ └────┬─────┘ └────┬─────┘ └───────────────────┘ │
│ │ │ │
│ ┌────┴──────────────┴────────────────────────────┐ │
│ │ Analytics: Trends, Funnels, Retention, Paths │ │
│ │ HogQL (SQL), Dashboards, Cohorts │ │
│ └────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────┐ │
│ │ CDP: Destinations (Webhook, Slack, S3, etc.) │ │
│ └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
▲
│ posthog-node (server events, local flag eval)
┌────────────┴────────────────────────────────────────┐
│ Backend (API routes, webhooks, crons) │
│ Server-side capture, group identify, flag eval │
└─────────────────────────────────────────────────────┘
src/
├── analytics/
│ ├── posthog.ts # Browser SDK init (singleton)
│ ├── posthog-server.ts # Server SDK init (singleton)
│ ├── events.ts # Typed event constants
│ ├── flags.ts # Feature flag key constants
│ └── hooks/
│ ├── useFeatureFlag.ts # React hook for boolean flags
│ └── useExperiment.ts # React hook for A/B variants
├── app/
│ ├── providers.tsx # PostHogProvider wrapper
│ └── layout.tsx # Root layout with provider
└── lib/
└── analytics.ts # High-level tracking functions
// analytics/events.ts
// Naming convention: object_action (noun_verb)
export const EVENTS = {
// User lifecycle (track conversion funnel)
USER_SIGNED_UP: 'user_signed_up',
USER_LOGGED_IN: 'user_logged_in',
USER_ONBOARDING_COMPLETED: 'user_onboarding_completed',
USER_INVITED_TEAMMATE: 'user_invited_teammate',
// Core product (track feature adoption)
FEATURE_USED: 'feature_used', // with feature_name property
ITEM_CREATED: 'item_created',
ITEM_UPDATED: 'item_updated',
ITEM_DELETED: 'item_deleted',
SEARCH_PERFORMED: 'search_performed',
EXPORT_COMPLETED: 'export_completed',
// Revenue (track MRR and churn)
SUBSCRIPTION_STARTED: 'subscription_started',
SUBSCRIPTION_UPGRADED: 'subscription_upgraded',
SUBSCRIPTION_DOWNGRADED: 'subscription_downgraded',
SUBSCRIPTION_CANCELED: 'subscription_canceled',
PAYMENT_COMPLETED: 'payment_completed',
// Engagement (track stickiness)
NOTIFICATION_CLICKED: 'notification_clicked',
FEEDBACK_SUBMITTED: 'feedback_submitted',
} as const;
// Standard property schema
interface BaseProps {
source?: 'web' | 'mobile' | 'api';
plan?: 'free' | 'pro' | 'enterprise';
}
// Type-safe capture
type EventMap = {
[EVENTS.USER_SIGNED_UP]: BaseProps & { method: 'email' | 'google' | 'github' };
[EVENTS.FEATURE_USED]: BaseProps & { feature_name: string; duration_ms?: number };
[EVENTS.SUBSCRIPTION_STARTED]: BaseProps & { plan: string; interval: 'monthly' | 'annual'; mrr: number };
};
// analytics/flags.ts
export const FLAGS = {
// Feature rollouts
NEW_DASHBOARD: 'new-dashboard-v2',
AI_SUMMARIZE: 'ai-summarize-beta',
BULK_EXPORT: 'bulk-export',
// Experiments
PRICING_PAGE: 'pricing-page-experiment',
ONBOARDING_FLOW: 'onboarding-flow-v3',
CHECKOUT_LAYOUT: 'checkout-layout-test',
} as const;
// Flag → default value mapping (used when flags fail to load)
export const FLAG_DEFAULTS: Record<string, boolean | string> = {
[FLAGS.NEW_DASHBOARD]: false,
[FLAGS.AI_SUMMARIZE]: false,
[FLAGS.PRICING_PAGE]: 'control',
[FLAGS.ONBOARDING_FLOW]: 'control',
};
// lib/analytics.ts
import posthog from 'posthog-js';
import { getPostHogServer } from '../analytics/posthog-server';
import { EVENTS } from '../analytics/events';
// Client-side tracking
export function trackFeatureUsed(featureName: string, duration?: number) {
posthog.capture(EVENTS.FEATURE_USED, {
feature_name: featureName,
duration_ms: duration,
source: 'web',
});
}
export function trackSignup(method: 'email' | 'google' | 'github') {
posthog.capture(EVENTS.USER_SIGNED_UP, { method, source: 'web' });
}
export function identifyUser(userId: string, properties: {
email: string;
name: string;
plan: string;
companyId?: string;
companyName?: string;
}) {
posthog.identify(userId, {
email: properties.email,
name: properties.name,
plan: properties.plan,
});
if (properties.companyId) {
posthog.group('company', properties.companyId, {
name: properties.companyName,
plan: properties.plan,
});
}
}
// Server-side tracking
export function trackServerEvent(
userId: string,
event: string,
properties?: Record<string, any>
) {
const ph = getPostHogServer();
ph.capture({
distinctId: userId,
event,
properties: { ...properties, source: 'api' },
});
}
// PostHog → External Systems via CDP Destinations
//
// PostHog Cloud Data Pipeline:
// 1. Events captured → PostHog stores in ClickHouse
// 2. CDP Destinations fire webhooks to your endpoints
// 3. HogQL queries available for custom analysis
//
// Common destination patterns:
// - PostHog → Webhook → Your API → CRM sync
// - PostHog → S3 export → Data warehouse
// - PostHog → Slack → Team notifications
// - PostHog → Webhook → Billing system (revenue events)
// Server route to receive PostHog CDP webhooks
export async function handlePostHogWebhook(event: string, payload: any) {
switch (event) {
case EVENTS.SUBSCRIPTION_STARTED:
await syncToStripe(payload);
break;
case EVENTS.USER_SIGNED_UP:
await syncToCRM(payload);
await notifySlack(payload);
break;
}
}
| Issue | Cause | Solution |
|---|---|---|
| Events not appearing | SDK not initialized | Verify posthog.init() runs before capture |
| Flag always returns default | Flags not loaded | Use posthog.onFeatureFlags() callback |
| Identity fragmentation | Inconsistent distinct_id | Use same user ID from auth system everywhere |
| Group analytics empty | posthog.group() not called | Call group() before capture |
| Server events lost | No flush() in serverless | Always await posthog.shutdown() |
object_action naming convention