posthog-local-dev-loop
Sets up a local development loop for PostHog, including mocking, debug modes, and test infrastructure.
Install
mkdir -p .claude/skills/posthog-local-dev-loop && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/6334" && unzip -o skill.zip -d .claude/skills/posthog-local-dev-loop && rm skill.zipInstalls to .claude/skills/posthog-local-dev-loop
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Configure PostHog local development with mocking, debug mode, and testing.Key capabilities
- →Configure PostHog debug mode for event inspection
- →Mock PostHog client for unit testing
- →Isolate development data from production
- →Enable instant flushing for local development
- →Implement integration tests with real dev projects
How it works
The skill establishes a development loop using environment-specific flushing configurations, debug logging, and mocked SDK clients for testing.
Inputs & outputs
When to use posthog-local-dev-loop
- →Create a mock PostHog client for unit tests
- →Isolate dev data from production
- →Configure hot-reloading for analytics code
- →Enable verbose debug logs for local troubleshooting
About this skill
PostHog Local Dev Loop
Overview
Set up a fast local development workflow for PostHog integrations. Covers debug mode for event inspection, mocking posthog-node for unit tests, and a dev/test PostHog project to avoid polluting production data.
Prerequisites
- Completed
posthog-install-authsetup - Node.js 20+ with npm/pnpm
- Vitest or Jest for testing
- Separate PostHog project for development (recommended)
Instructions
Step 1: Project Structure
my-posthog-app/
├── src/
│ ├── analytics/
│ │ ├── posthog.ts # Singleton client
│ │ ├── events.ts # Event taxonomy (typed constants)
│ │ └── flags.ts # Feature flag keys
│ └── index.ts
├── tests/
│ ├── analytics.test.ts # Unit tests with mocked PostHog
│ └── integration.test.ts # Integration tests (real PostHog dev project)
├── .env.local # Dev keys (git-ignored)
├── .env.example # Template: NEXT_PUBLIC_POSTHOG_KEY=phc_...
└── package.json
Step 2: PostHog Client with Dev Mode
// src/analytics/posthog.ts
import { PostHog } from 'posthog-node';
let client: PostHog | null = null;
export function getPostHog(): PostHog {
if (!client) {
client = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
host: process.env.POSTHOG_HOST || 'https://us.i.posthog.com',
flushAt: process.env.NODE_ENV === 'development' ? 1 : 20,
flushInterval: process.env.NODE_ENV === 'development' ? 0 : 10000,
// In dev, flush immediately so events appear instantly in dashboard
});
}
return client;
}
export async function shutdown() {
if (client) {
await client.shutdown();
client = null;
}
}
Step 3: Browser Debug Mode
// Enable PostHog debug mode in development
import posthog from 'posthog-js';
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: 'https://us.i.posthog.com',
loaded: (ph) => {
if (process.env.NODE_ENV === 'development') {
ph.debug();
// All events logged to browser console:
// [PostHog.js] Sending event: {"event":"$pageview","properties":{...}}
}
},
});
// Disable capture entirely in test environments
if (process.env.NODE_ENV === 'test') {
posthog.opt_out_capturing();
}
Step 4: Mock PostHog for Unit Tests
// tests/analytics.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock posthog-node
vi.mock('posthog-node', () => {
const mockCapture = vi.fn();
const mockIdentify = vi.fn();
const mockGetFeatureFlag = vi.fn().mockResolvedValue(true);
const mockShutdown = vi.fn().mockResolvedValue(undefined);
const mockFlush = vi.fn().mockResolvedValue(undefined);
return {
PostHog: vi.fn().mockImplementation(() => ({
capture: mockCapture,
identify: mockIdentify,
getFeatureFlag: mockGetFeatureFlag,
getAllFlags: vi.fn().mockResolvedValue({ 'new-feature': true }),
shutdown: mockShutdown,
flush: mockFlush,
})),
};
});
import { PostHog } from 'posthog-node';
describe('Analytics', () => {
let ph: InstanceType<typeof PostHog>;
beforeEach(() => {
vi.clearAllMocks();
ph = new PostHog('phc_test_key');
});
it('captures events with correct properties', () => {
ph.capture({
distinctId: 'user-1',
event: 'button_clicked',
properties: { button: 'signup' },
});
expect(ph.capture).toHaveBeenCalledWith({
distinctId: 'user-1',
event: 'button_clicked',
properties: { button: 'signup' },
});
});
it('evaluates feature flags', async () => {
const result = await ph.getFeatureFlag('new-feature', 'user-1');
expect(result).toBe(true);
});
});
Step 5: Integration Test with Real Dev Project
// tests/integration.test.ts
import { describe, it, expect, afterAll } from 'vitest';
import { PostHog } from 'posthog-node';
const POSTHOG_KEY = process.env.POSTHOG_TEST_KEY;
describe.skipIf(!POSTHOG_KEY)('PostHog Integration', () => {
const ph = new PostHog(POSTHOG_KEY!, {
host: 'https://us.i.posthog.com',
flushAt: 1,
flushInterval: 0,
});
afterAll(async () => {
await ph.shutdown();
});
it('should capture and flush an event', async () => {
ph.capture({
distinctId: `test-${Date.now()}`,
event: 'integration_test',
properties: { test: true },
});
// Flush returns successfully if network is reachable
await expect(ph.flush()).resolves.not.toThrow();
});
it('should evaluate feature flags', async () => {
const flags = await ph.getAllFlags(`test-${Date.now()}`);
expect(typeof flags).toBe('object');
});
});
Step 6: Package Scripts
{
"scripts": {
"dev": "tsx watch src/index.ts",
"test": "vitest run",
"test:watch": "vitest --watch",
"test:integration": "POSTHOG_TEST_KEY=$NEXT_PUBLIC_POSTHOG_KEY vitest run tests/integration"
}
}
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Events not in dev dashboard | Wrong project key | Verify .env.local has dev project phc_ key |
| Mock not intercepting | Wrong import path | Ensure vi.mock path matches actual import |
| Integration test timeout | PostHog unreachable | Check network, increase vitest timeout |
| Debug mode too noisy | ph.debug() in prod | Guard with NODE_ENV === 'development' |
Output
- Development PostHog client with instant flush
- Browser debug mode for event inspection
- Mocked posthog-node for unit tests
- Integration test suite for real PostHog connectivity
Resources
Next Steps
See posthog-sdk-patterns for production-ready code patterns.
When not to use it
- →When using production API keys in test environments
- →When failing to guard debug mode in production
Prerequisites
Limitations
- →Debug mode can be noisy if not environment-guarded
- →Integration tests require network connectivity
How it compares
It provides a structured testing and debugging environment rather than manual verification.
Compared to similar skills
posthog-local-dev-loop side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| posthog-local-dev-loop (this skill) | 1 | 27d | Review | Intermediate |
| develop-ai-functions-example | 5 | 6mo | Review | Intermediate |
| adk-engineer | 3 | 27d | Review | Advanced |
| posthog-hello-world | 0 | 27d | Caution | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
develop-ai-functions-example
vercel
Develop examples for AI SDK functions. Use when creating, running, or modifying examples under examples/ai-functions/src to validate provider support, demonstrate features, or create test fixtures.
adk-engineer
jeremylongshore
Execute software engineer specializing in creating production-ready ADK agents with best practices, code structure, testing, and deployment automation. Use when asked to "build ADK agent", "create agent code", or "engineer ADK application". Trigger with relevant phrases based on skill purpose.
posthog-hello-world
jeremylongshore
Create a minimal working PostHog example. Use when starting a new PostHog integration, testing your setup, or learning basic PostHog API patterns. Trigger with phrases like "posthog hello world", "posthog example", "posthog quick start", "simple posthog code".
langsmith-evaluator
dhar174
INVOKE THIS SKILL when building evaluation pipelines for LangSmith. Covers three core components: (1) Creating Evaluators - LLM-as-Judge, custom code; (2) Defining Run Functions - how to capture outputs and trajectories from your agent; (3) Running Evaluations - locally with evaluate() or auto-run v
mcp-builder
anthropics
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
dependency-upgrade
wshobson
Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.