Implements product analytics with PostHog including event tracking, feature flags, and session replay. Use when adding analytics, A/B testing, or user behavior tracking to React and Next.js applications.
Adds PostHog product analytics to React/Next.js apps for event tracking, feature flags, and session replay. Use when implementing analytics, A/B testing, or user behavior tracking in client-side components.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Product analytics platform with autocapture, feature flags, session replay, and A/B testing. Open source with self-hosting option.
npm install posthog-js @posthog/react
// src/main.tsx or src/index.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import posthog from 'posthog-js';
import { PostHogProvider } from '@posthog/react';
import App from './App';
posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com',
defaults: '2025-11-30', // Use 2025 defaults
});
createRoot(document.getElementById('root')!).render(
<StrictMode>
<PostHogProvider client={posthog}>
<App />
</PostHogProvider>
</StrictMode>
);
// app/providers.tsx
'use client';
import posthog from 'posthog-js';
import { PostHogProvider as PHProvider } from '@posthog/react';
import { useEffect } from 'react';
export function PostHogProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com',
defaults: '2025-11-30',
capture_pageview: 'history_change', // Auto-capture for App Router
});
}, []);
return <PHProvider client={posthog}>{children}</PHProvider>;
}
// app/layout.tsx
import { PostHogProvider } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<PostHogProvider>
{children}
</PostHogProvider>
</body>
</html>
);
}
import { usePostHog } from '@posthog/react';
function ProductCard({ product }) {
const posthog = usePostHog();
const handleAddToCart = () => {
posthog.capture('add_to_cart', {
product_id: product.id,
product_name: product.name,
price: product.price,
category: product.category,
});
};
const handleView = () => {
posthog.capture('product_viewed', {
product_id: product.id,
product_name: product.name,
});
};
return (
<div onClick={handleView}>
<h3>{product.name}</h3>
<button onClick={handleAddToCart}>Add to Cart</button>
</div>
);
}
const posthog = usePostHog();
// Page views (automatic with defaults: '2025-11-30')
// posthog.capture('$pageview'); // Usually not needed
// User actions
posthog.capture('button_clicked', { button_name: 'signup' });
posthog.capture('form_submitted', { form_name: 'contact' });
posthog.capture('file_downloaded', { file_name: 'report.pdf' });
// Ecommerce
posthog.capture('purchase_completed', {
order_id: 'order_123',
total: 99.99,
currency: 'USD',
items: ['product_1', 'product_2'],
});
// Feature usage
posthog.capture('feature_used', {
feature_name: 'export',
feature_variant: 'csv',
});
const posthog = usePostHog();
// Identify user after login
function onLogin(user) {
posthog.identify(user.id, {
email: user.email,
name: user.name,
plan: user.subscription?.plan,
created_at: user.createdAt,
});
}
// Reset on logout
function onLogout() {
posthog.reset();
}
// Update user properties
posthog.people.set({
plan: 'pro',
last_active: new Date().toISOString(),
});
// Set properties once (won't overwrite)
posthog.people.set_once({
initial_referrer: document.referrer,
signup_date: new Date().toISOString(),
});
import { useFeatureFlagEnabled, useFeatureFlagVariantKey } from '@posthog/react';
function FeatureComponent() {
// Boolean flag
const showNewFeature = useFeatureFlagEnabled('new-feature');
// Multivariate flag
const variant = useFeatureFlagVariantKey('checkout-experiment');
if (!showNewFeature) {
return null;
}
return (
<div>
{variant === 'control' && <OldCheckout />}
{variant === 'test' && <NewCheckout />}
</div>
);
}
import { PostHogFeature } from '@posthog/react';
function App() {
return (
<div>
<PostHogFeature flag="new-dashboard" match={true}>
<NewDashboard />
</PostHogFeature>
<PostHogFeature flag="new-dashboard" match={false}>
<OldDashboard />
</PostHogFeature>
</div>
);
}
import { useFeatureFlagPayload, useFeatureFlagEnabled } from '@posthog/react';
function PricingPage() {
// Use both hooks to track experiment exposure
const isEnabled = useFeatureFlagEnabled('pricing-experiment');
const payload = useFeatureFlagPayload('pricing-experiment');
if (!isEnabled || !payload) {
return <DefaultPricing />;
}
return (
<div>
<h1>{payload.headline}</h1>
<p>Starting at ${payload.startingPrice}/month</p>
</div>
);
}
// app/api/feature/route.ts
import { PostHog } from 'posthog-node';
const posthog = new PostHog(process.env.POSTHOG_API_KEY!, {
host: process.env.POSTHOG_HOST,
});
export async function GET(request: Request) {
const userId = getUserId(request);
const flagEnabled = await posthog.isFeatureEnabled('new-feature', userId);
const variant = await posthog.getFeatureFlag('experiment', userId);
return Response.json({ flagEnabled, variant });
}
const posthog = usePostHog();
// Associate user with a company
posthog.group('company', 'company_123', {
name: 'Acme Inc',
plan: 'enterprise',
employee_count: 50,
});
// Events now include company context
posthog.capture('feature_used', { feature: 'api' });
Enable in PostHog dashboard and configure:
posthog.init(POSTHOG_KEY, {
api_host: POSTHOG_HOST,
defaults: '2025-11-30',
// Session replay options
session_recording: {
maskAllInputs: true,
maskTextSelector: '.sensitive-data',
},
});
const posthog = usePostHog();
// Start/stop recording
posthog.startSessionRecording();
posthog.stopSessionRecording();
// Check if recording
const isRecording = posthog.sessionRecordingStarted();
import { useFeatureFlagVariantKey, usePostHog } from '@posthog/react';
function CheckoutButton() {
const posthog = usePostHog();
const variant = useFeatureFlagVariantKey('checkout-button-experiment');
const handleClick = () => {
posthog.capture('checkout_clicked');
// Process checkout...
};
if (variant === 'control') {
return <button onClick={handleClick}>Checkout</button>;
}
if (variant === 'test') {
return <button onClick={handleClick} className="cta-primary">Buy Now</button>;
}
return <button onClick={handleClick}>Checkout</button>;
}
npm install posthog-node
import { PostHog } from 'posthog-node';
const posthog = new PostHog(process.env.POSTHOG_API_KEY!, {
host: process.env.POSTHOG_HOST,
});
// Capture event
posthog.capture({
distinctId: 'user_123',
event: 'api_called',
properties: {
endpoint: '/api/users',
method: 'POST',
},
});
// Identify user
posthog.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
plan: 'pro',
},
});
// Shutdown (important for serverless)
await posthog.shutdown();
posthog.init(POSTHOG_KEY, {
api_host: 'https://us.i.posthog.com',
defaults: '2025-11-30',
// Autocapture
autocapture: true,
capture_pageview: 'history_change',
capture_pageleave: true,
// Privacy
disable_session_recording: false,
mask_all_text: false,
mask_all_element_attributes: false,
// Performance
loaded: (posthog) => {
// Called when PostHog is ready
},
// Debugging
debug: process.env.NODE_ENV === 'development',
});
# Client-side
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxx
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
# Or for Vite
VITE_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxx
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
# Server-side
POSTHOG_API_KEY=phx_xxxxxxxxxxxxxx
POSTHOG_HOST=https://us.i.posthog.com
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.