| name | posthog-integration |
| description | PostHog API / Integration for NodeJS/Typescript. Use when: implementing PostHog telemetry, adding analytics events, configuring PostHog adapters, writing telemetry tests, integrating feature flags, uploading sourcemaps, or debugging PostHog capture issues. |
| argument-hint | What PostHog telemetry task do you need help with? |
PostHog Integration โ NodeJS/TypeScript
When to Use
- Adding new telemetry events to
TelemetryService
- Implementing or modifying
IPostHogAdapter (Node or Web)
- Writing tests for PostHog adapters or telemetry service
- Integrating PostHog with lifecycle hooks (
PostHogHook)
- Configuring feature flags via PostHog
- Uploading sourcemaps for error symbolication
- Debugging event capture, flush, or shutdown issues
Architecture Overview
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ extension.ts (entry) โ
โ TelemetryService.initialize(context) โ
โ PostHogHook(telemetryService).initialize() โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโผโโโโโโโโโโโ โโโโโโโโโผโโโโโโโโโโโโโโโโโ
โ TelemetryService โ โ Observability Layer โ
โ (typed capture โ โ HookSystem โ
โ methods) โ โ PostHogHook โ
โโโโโโโโโโโโฌโโโโโโโโโโโ โโโโโโโโโฌโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โ IPostHogAdapter (interface) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ posthogAdapter.ts โ posthogAdapter.web.ts โ
โ (posthog-node) โ (posthog-js) โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โ PostHog Cloud โ
โ us.i.posthog.com โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key Files
| File | Purpose |
|---|
src/telemetry/types.ts | IPostHogAdapter, PostHogConfig, TelemetryEvent, TelemetryPrimitive |
src/telemetry/posthogAdapter.ts | Node.js adapter wrapping posthog-node |
src/telemetry/posthogAdapter.web.ts | Web adapter wrapping posthog-js |
src/telemetry/telemetryService.ts | Central facade โ typed capture methods, event enrichment |
src/observability/posthogHook.ts | Bridge: HookSystem โ TelemetryService |
scripts/upload-posthog-sourcemaps.mjs | Sourcemap upload for error symbolication |
Procedure: Adding a New Telemetry Event
1. Define the Event
Add a typed capture method to TelemetryService:
captureMyNewEvent(properties: {
caller: string;
model?: string;
durationMs?: number;
}): void {
this.capture('my_new_event', {
...properties,
});
}
2. Call from Production Code
Invoke from the appropriate location (provider, command, hook handler):
import { TelemetryService } from '../telemetry/telemetryService';
telemetryService.captureMyNewEvent({
caller: 'chat',
model: 'gpt-4',
durationMs: elapsed,
});
3. Write the Test First (TDD)
it('should capture my_new_event with correct properties', () => {
const adapter = sinon.createStubInstance(PostHogAdapter);
const service = new TelemetryService(adapter as unknown as IPostHogAdapter);
service.captureMyNewEvent({ caller: 'chat', model: 'gpt-4', durationMs: 150 });
sinon.assert.calledOnce(adapter.capture);
const [eventName, props] = adapter.capture.firstCall.args;
expect(eventName).to.equal('my_new_event');
expect(props).to.include({ caller: 'chat', model: 'gpt-4', durationMs: 150 });
expect(props).to.have.property('distinctId');
expect(props).to.have.property('extension_version');
});
4. Run Tests
npm run test:coverage
Procedure: Implementing an Adapter
Adapters implement IPostHogAdapter:
export interface IPostHogAdapter {
initialize(config: PostHogConfig): void;
capture(event: TelemetryEvent): void;
captureException(error: Error, options?: TelemetryCaptureExceptionOptions): void;
identify(distinctId: string, properties?: TelemetryPersonProperties): void;
isFeatureEnabled(flag: string, distinctId: string): Promise<boolean>;
flush(): Promise<void>;
shutdown(): Promise<void>;
setEnabled(enabled: boolean): void;
}
Node adapter (posthogAdapter.ts): Uses posthog-node PostHog class.
Web adapter (posthogAdapter.web.ts): Uses posthog-js with persistence: "memory".
Both guard all calls behind an enabled flag and return no-ops when disabled.
Procedure: Integrating with HookSystem
Use PostHogHook to capture events from the request lifecycle:
To add a new hook-captured event:
- Register handler on the appropriate
HookPoint in PostHogHook.initialize()
- Extract relevant data from
HookContext
- Call
telemetryService.captureXxx(...) with extracted properties
Configuration
API Key & Host: Hardcoded in TelemetryService (static readonly).
Telemetry opt-in: Respects vscode.env.isTelemetryEnabled. Adapter toggles via setEnabled() on onDidChangeTelemetryEnabled.
User identification: vscode.env.sessionId (preferred) or vscode.env.machineId as distinctId.
Sourcemap upload (env vars):
POSTHOG_HOST
POSTHOG_PROJECT_API_KEY
POSTHOG_PERSONAL_API_KEY
POSTHOG_RELEASE
npm run posthog:sourcemaps
Testing Patterns
Framework: Mocha + Sinon + VS Code test runner
| What | How |
|---|
| Adapter tests | Sinon sandbox, stub PostHog.prototype.captureException |
| Service tests | sinon.createStubInstance(PostHogAdapter), verify event shape |
| Hook tests | HookSystem.clear() in setup, stub StructuredLogger |
| Disabled path | Verify no-ops when enabled = false |
| Pre-initialize | Verify no-ops before initialize() called |
Coverage targets: Statements/Branches/Functions 90%+, Lines 85%+
Common Pitfalls
- Forgetting enrichment: Every event automatically gets
distinctId, extension_version, vscode_version, ui_kind, os โ don't duplicate these in properties.
- Web adapter
isFeatureEnabled is synchronous: Node adapter returns Promise<boolean>, web adapter returns boolean directly. Handle both cases in consumers.
- Missing
setEnabled toggle: Always test the disabled path; telemetry must be a no-op when vscode.env.isTelemetryEnabled is false.
- Sourcemap upload requires production build: Run
npm run build:posthog-sourcemaps before uploading.