From api-analytics-posthog-analytics
PostHog event tracking, user identification, group analytics for B2B, GDPR consent patterns. Use when implementing product analytics, tracking user behavior, setting up funnels, or configuring privacy-compliant tracking.
How this skill is triggered — by the user, by Claude, or both
Slash command
/api-analytics-posthog-analytics:api-analytics-posthog-analyticsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Quick Guide:** Use PostHog for product analytics with structured event naming (`category:object_action`), server-side tracking for reliability, and proper user identification integrated with your authentication flow. Client-side for UI interactions, server-side for business events. Always call `reset()` on logout, never store PII in event properties, and use `captureImmediate()` or `await s...
Quick Guide: Use PostHog for product analytics with structured event naming (
category:object_action), server-side tracking for reliability, and proper user identification integrated with your authentication flow. Client-side for UI interactions, server-side for business events. Always callreset()on logout, never store PII in event properties, and usecaptureImmediate()orawait shutdown()in serverless environments.
Detailed Resources:
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST call posthog.identify() ONLY when a user signs up or logs in - never on every page load)
(You MUST include the user's database ID as distinct_id in ALL server-side events)
(You MUST call posthog.reset() when a user logs out to unlink future events)
(You MUST use the category:object_action naming convention for all custom events)
(You MUST NEVER include PII (email, name, phone) in event properties - use user IDs only)
</critical_requirements>
Auto-detection: PostHog, posthog-js, posthog-node, usePostHog, PostHogProvider, capture, identify, group analytics, product analytics, event tracking, funnel analysis
When to use:
When NOT to use:
Key patterns covered:
category:object_action)object_adjective, is_/has_ booleans)PostHog analytics follows a structured taxonomy approach: consistent naming conventions, meaningful properties, and strategic placement (client vs server). Track what matters for product decisions, not everything.
Core principles:
Use the category:object_action framework for consistent, queryable event names.
// category: Context (signup_flow, settings, dashboard)
// object: Component/location (password_button, pricing_page)
// action: Present-tense verb (click, submit, view)
"signup_flow:email_form_submit";
"dashboard:project_create";
"settings:billing_plan_upgrade";
// Simpler alternative: object_verb
"project_created";
"user_signed_up";
Why good: Category prefix groups related events in PostHog UI, enables wildcard queries like signup_flow:*, consistent naming makes analysis possible at scale.
Property naming rules:
object_adjective: project_id, plan_name, item_countis_ / has_ for booleans: is_first_purchase, has_completed_onboarding_date / _timestamp suffix: trial_end_date, last_login_timestampSee examples/core.md for complete naming examples.
Call identify() only on auth state change (not every render). Use database user ID as distinct_id. Call reset() on logout.
// Check _isIdentified() to prevent duplicate calls
useEffect(() => {
if (session?.user && !posthog._isIdentified()) {
posthog.identify(session.user.id, {
plan: session.user.plan ?? "free",
created_at: session.user.createdAt,
is_verified: session.user.emailVerified ?? false,
});
}
}, [session?.user]);
// Always reset on logout
posthog?.capture("user_logged_out");
posthog?.reset(); // Unlink future events from this user
See examples/core.md for full identification hook and logout handler.
Track business events reliably from your backend with posthog-node.
// Serverless: use captureImmediate (guarantees HTTP completion)
await posthogServer.captureImmediate({
distinctId: user.id,
event: "subscription_created",
properties: { plan: "pro", is_annual: true },
});
// Always call shutdown before returning in serverless
await posthogServer.shutdown();
Key rules:
distinctId (user's database ID)captureImmediate() for serverless (guarantees HTTP completion)shutdown() before returning in serverlessflushAt: 1 and flushInterval: 0 for serverlessSee examples/server-tracking.md for complete server setup and route examples.
Associate events with organizations using PostHog groups for B2B metrics.
// Client-side: identify organization
posthog.group("company", org.id, {
name: org.name,
plan: org.plan ?? "free",
member_count: org.memberCount,
});
// Server-side: include groups in event
posthogServer.capture({
distinctId: user.id,
event: "organization:member_invited",
properties: { role: data.role },
groups: { company: data.organizationId },
});
Limitations: Maximum 5 group types per project. One group per type per event.
See examples/group-analytics.md for complete group patterns.
PostHog supports cookieless tracking and consent management.
// Cookieless mode: "always" (no consent needed) or "on_reject" (with banner)
posthog.init(POSTHOG_KEY, {
cookieless_mode: "on_reject",
person_profiles: "identified_only",
});
// Consent methods
posthog.opt_in_capturing(); // User accepts
posthog.opt_out_capturing(); // User rejects
Key rule: Never store PII (email, name, phone, IP, address) in event properties. Use pseudonymized IDs only.
See examples/privacy-gdpr.md for consent banner integration and before_send filtering.
Web Apps (default batching): Use default settings -- PostHog batches efficiently out of the box.
Serverless (immediate delivery):
const posthogServer = new PostHog(POSTHOG_KEY, {
flushAt: 1, // Flush after 1 event
flushInterval: 0, // No interval batching
});
// Use captureImmediate() or capture() + await shutdown()
Reducing Costs:
posthog.init(POSTHOG_KEY, {
person_profiles: "identified_only", // Anonymous events 4x cheaper
autocapture: false, // Disable for high-traffic sites
});
<red_flags>
High Priority Issues:
distinct_id -- PII should not be the identifierposthog.reset() on logout -- users get mixed togetherawait shutdown() in serverless -- events are lostidentify() on every render -- performance degradationCommon Mistakes:
posthog directly instead of using usePostHog hook in Reactapi_host: "/ingest") -- events blocked by ad blockersperson_profiles: "identified_only" -- 4x higher costs on anonymous eventscapture() instead of captureImmediate() in serverless -- events may not completeGotchas & Edge Cases:
distinct_id is required for ALL server-side events (unlike client-side which auto-generates one)group() must include group ID with every event (not persisted like identify())cookieless_mode: "always" disables identify() entirely -- privacy trade-off</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST call posthog.identify() ONLY when a user signs up or logs in - never on every page load)
(You MUST include the user's database ID as distinct_id in ALL server-side events)
(You MUST call posthog.reset() when a user logs out to unlink future events)
(You MUST use the category:object_action naming convention for all custom events)
(You MUST NEVER include PII (email, name, phone) in event properties - use user IDs only)
Failure to follow these rules will cause analytics data quality issues, privacy violations, or lost events.
</critical_reminders>
npx claudepluginhub agents-inc/skills --plugin api-analytics-posthog-analyticsImplements PostHog product analytics: event capture, user identification, group analytics, and property management with posthog-js (browser) and posthog-node (server).
Implements Segment CDP patterns: Analytics.js tracking, server-side Node.js events, identity resolution, and typed event helpers for Next.js apps.
Adds PostHog product analytics events (capture calls) to track user behavior after implementing features or reviewing PRs. Also handles initial PostHog SDK setup.