From posthog-pack
Implements PostHog feature flags, A/B experiments, and cohorts using posthog-js (browser) and posthog-node (server) in TypeScript/JavaScript apps.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin posthog-packThis skill is limited to using the following tools:
Feature flag management, A/B experiment evaluation, and cohort analysis with PostHog. Covers boolean and multivariate flags, local evaluation for performance, experiment setup and statistical significance, and cohort creation via the API.
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.
Adds PostHog feature flags to gate new functionality for safe rollouts after feature implementation or PR reviews. Handles initial SDK setup if needed across multiple platforms.
Implements PostHog analytics for event tracking, user identification, feature flags, and dashboards in Next.js and React apps. Use when adding product analytics.
Share bugs, ideas, or general feedback.
Feature flag management, A/B experiment evaluation, and cohort analysis with PostHog. Covers boolean and multivariate flags, local evaluation for performance, experiment setup and statistical significance, and cohort creation via the API.
posthog-install-auth setupposthog-core-workflow-a (event capture)phx_...) for flag management APIimport posthog from 'posthog-js';
// Boolean flag
if (posthog.isFeatureEnabled('new-checkout-flow')) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}
// Multivariate flag (returns string variant name)
const variant = posthog.getFeatureFlag('pricing-page-experiment');
switch (variant) {
case 'control':
renderOriginalPricing();
break;
case 'annual-first':
renderAnnualFirstPricing();
break;
case 'social-proof':
renderSocialProofPricing();
break;
default:
renderOriginalPricing(); // Fallback if flag not loaded yet
}
// Get flag payload (JSON data attached to a flag variant)
const payload = posthog.getFeatureFlagPayload('banner-config');
// payload: { text: "Spring sale!", color: "#ff6b35", discount: 20 }
// React: Wait for flags to load before rendering
posthog.onFeatureFlags(() => {
// Flags are now loaded and ready
const enabled = posthog.isFeatureEnabled('new-feature');
setFeatureEnabled(enabled ?? false);
});
import { PostHog } from 'posthog-node';
const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
host: 'https://us.i.posthog.com',
// Personal API key enables local evaluation (no network call per flag check)
personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,
});
// Single flag evaluation
async function checkFlag(userId: string): Promise<boolean> {
const enabled = await posthog.isFeatureEnabled('new-api-version', userId);
return enabled ?? false;
}
// Multivariate flag
async function getVariant(userId: string): Promise<string> {
const variant = await posthog.getFeatureFlag('onboarding-experiment', userId, {
personProperties: { plan: 'pro', country: 'US' },
});
return (variant as string) || 'control';
}
// Get ALL flags for a user at once (one network call)
async function getUserFlags(userId: string) {
const flags = await posthog.getAllFlags(userId, {
personProperties: { plan: 'enterprise' },
groupProperties: { company: { name: 'Acme' } },
});
// flags: { 'new-checkout': true, 'pricing-experiment': 'variant-a', ... }
return flags;
}
// Get all flags with their payloads
async function getFlagsAndPayloads(userId: string) {
const result = await posthog.getAllFlagsAndPayloads(userId);
// result.featureFlags: { 'banner': true }
// result.featureFlagPayloads: { 'banner': { text: 'Sale!' } }
return result;
}
set -euo pipefail
# Create a boolean feature flag with percentage rollout
curl -X POST "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/feature_flags/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "new-dashboard-v2",
"name": "New Dashboard V2",
"active": true,
"filters": {
"groups": [{
"rollout_percentage": 25,
"properties": []
}]
}
}'
# Create a multivariate flag for A/B testing
curl -X POST "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/feature_flags/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "checkout-experiment",
"name": "Checkout Flow Experiment",
"active": true,
"filters": {
"multivariate": {
"variants": [
{"key": "control", "rollout_percentage": 50},
{"key": "streamlined", "rollout_percentage": 50}
]
},
"groups": [{"rollout_percentage": 100, "properties": []}]
}
}'
// Track experiment exposure and goal metrics
async function runExperiment(userId: string) {
const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!);
// PostHog automatically tracks $feature_flag_called when you evaluate
const variant = await posthog.getFeatureFlag('checkout-experiment', userId);
// Track the goal metric
posthog.capture({
distinctId: userId,
event: 'purchase_completed',
properties: {
variant,
order_value: 49.99,
// PostHog will attribute this to the experiment automatically
},
});
await posthog.flush();
return variant;
}
set -euo pipefail
# List experiments and their status
curl "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/experiments/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" | \
jq '.results[] | {id, name, start_date, end_date, feature_flag_key}'
# Get experiment results
curl "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/experiments/EXPERIMENT_ID/results/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" | \
jq '{
variants: [.result.variants[] | {key, count, conversion_rate: .absolute_exposure}],
significance: .result.significance_code,
probability: .result.probability
}'
set -euo pipefail
# Create a behavioral cohort (users who signed up in last 30 days)
curl -X POST "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/cohorts/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Recent Signups (30d)",
"is_calculating": true,
"filters": {
"properties": {
"type": "AND",
"values": [{
"type": "AND",
"values": [{
"key": "user_signed_up",
"type": "behavioral",
"value": "performed_event",
"time_value": 30,
"time_interval": "day"
}]
}]
}
}
}'
# List cohorts
curl "https://app.posthog.com/api/projects/$POSTHOG_PROJECT_ID/cohorts/" \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" | \
jq '.results[] | {id, name, count, is_calculating}'
| Error | Cause | Solution |
|---|---|---|
Flag always returns undefined | Flags not loaded yet | Use posthog.onFeatureFlags() callback |
| Flag returns default on server | No personalApiKey set | Add personal API key for local evaluation |
| Experiment not tracking | Goal event name mismatch | Verify event name matches experiment config |
Cohort stuck is_calculating | Large dataset | Wait for calculation; check PostHog status |
getAllFlags slow | No local evaluation | Set personalApiKey in PostHog constructor |
For common errors, see posthog-common-errors.