Capture user events, pageviews, and custom analytics with properties, groups, and feature flag context.
Capture an event and queue it for batch sending.
/**
* Capture an event manually
* @param props - The event properties
*/
capture(props: EventMessage): void;Usage Examples:
import { PostHog } from 'posthog-node';
const client = new PostHog('phc_your_api_key');
// Basic event capture
client.capture({
distinctId: 'user_123',
event: 'button_clicked',
properties: {
button_name: 'signup',
button_color: 'red'
}
});
// Event with timestamp
client.capture({
distinctId: 'user_123',
event: 'purchase_completed',
properties: {
amount: 99.99,
currency: 'USD',
product_id: 'prod_456'
},
timestamp: new Date()
});
// Event with groups
client.capture({
distinctId: 'user_123',
event: 'feature_used',
properties: {
feature_name: 'export_data'
},
groups: {
company: 'acme_corp',
organization: 'org_789'
}
});
// Event with feature flags
client.capture({
distinctId: 'user_123',
event: 'user_action',
sendFeatureFlags: true
});
// Event with custom UUID
client.capture({
distinctId: 'user_123',
event: 'custom_event',
uuid: 'custom-uuid-123'
});
// Disable GeoIP lookup
client.capture({
distinctId: 'user_123',
event: 'privacy_event',
disableGeoip: true
});Capture an event and send it immediately without queuing. Use for serverless environments or when you need guaranteed delivery before function termination.
/**
* Capture an event immediately (synchronously)
* @param props - The event properties
* @returns Promise that resolves when the event is captured
*/
captureImmediate(props: EventMessage): Promise<void>;Usage Examples:
// Basic immediate capture
await client.captureImmediate({
distinctId: 'user_123',
event: 'button_clicked',
properties: { button_name: 'signup' }
});
// In serverless function
export async function handler(event) {
await client.captureImmediate({
distinctId: event.userId,
event: 'function_invoked',
properties: {
function_name: 'my-function',
execution_time: Date.now()
}
});
// Ensure event is sent before function exits
return { statusCode: 200 };
}
// With feature flags
await client.captureImmediate({
distinctId: 'user_123',
event: 'user_action',
sendFeatureFlags: true
});
// With selective feature flag evaluation
await client.captureImmediate({
distinctId: 'user_123',
event: 'user_action',
sendFeatureFlags: {
onlyEvaluateLocally: true,
personProperties: { plan: 'premium' },
groupProperties: { organization: { tier: 'enterprise' } },
flagKeys: ['flag1', 'flag2']
}
});interface EventMessage {
/** Unique identifier for the user */
distinctId: string;
/** Name of the event (e.g., 'button_clicked', 'purchase_completed') */
event: string;
/** Custom properties for the event */
properties?: Record<string | number, any>;
/** Group associations (e.g., { company: 'acme_corp' }) */
groups?: Record<string, string | number>;
/** Whether to evaluate and send feature flags with the event */
sendFeatureFlags?: boolean | SendFeatureFlagsOptions;
/** Custom timestamp for the event (defaults to now) */
timestamp?: Date;
/** Custom UUID for the event (auto-generated if not provided) */
uuid?: string;
/** Disable GeoIP lookup for this event */
disableGeoip?: boolean;
}interface SendFeatureFlagsOptions {
/** Only use local evaluation, don't fall back to remote */
onlyEvaluateLocally?: boolean;
/** Person properties for flag evaluation */
personProperties?: Record<string, any>;
/** Group properties for flag evaluation */
groupProperties?: Record<string, Record<string, any>>;
/** Specific flag keys to evaluate */
flagKeys?: string[];
}// Track pageview
client.capture({
distinctId: 'user_123',
event: '$pageview',
properties: {
$current_url: 'https://example.com/pricing',
$referrer: 'https://google.com',
$pathname: '/pricing'
}
});// Product viewed
client.capture({
distinctId: 'user_123',
event: 'product_viewed',
properties: {
product_id: 'prod_456',
product_name: 'Premium Widget',
price: 99.99,
currency: 'USD',
category: 'widgets'
}
});
// Added to cart
client.capture({
distinctId: 'user_123',
event: 'product_added_to_cart',
properties: {
product_id: 'prod_456',
quantity: 2,
price: 99.99,
cart_total: 199.98
}
});
// Purchase completed
client.capture({
distinctId: 'user_123',
event: 'purchase_completed',
properties: {
order_id: 'order_789',
total: 199.98,
currency: 'USD',
items: [
{ product_id: 'prod_456', quantity: 2, price: 99.99 }
]
}
});// Feature used
client.capture({
distinctId: 'user_123',
event: 'feature_used',
properties: {
feature_name: 'export_data',
export_format: 'csv',
row_count: 1000
}
});
// API call made
client.capture({
distinctId: 'user_123',
event: 'api_call',
properties: {
endpoint: '/api/users',
method: 'GET',
status_code: 200,
response_time_ms: 150
}
});// Track company-level event
client.capture({
distinctId: 'user_123',
event: 'company_feature_used',
properties: {
feature: 'team_collaboration'
},
groups: {
company: 'acme_corp'
}
});
// Multi-level groups
client.capture({
distinctId: 'user_123',
event: 'resource_accessed',
properties: {
resource_type: 'document',
resource_id: 'doc_123'
},
groups: {
company: 'acme_corp',
team: 'engineering',
project: 'project_alpha'
}
});// Capture event with feature flags for experiments
client.capture({
distinctId: 'user_123',
event: 'experiment_viewed',
properties: {
experiment_name: 'checkout_flow_v2'
},
sendFeatureFlags: true
});
// Evaluate specific flags only
client.capture({
distinctId: 'user_123',
event: 'conversion',
properties: {
conversion_type: 'signup'
},
sendFeatureFlags: {
flagKeys: ['checkout_flow_v2', 'pricing_test']
}
});// API error
client.capture({
distinctId: 'user_123',
event: 'api_error',
properties: {
endpoint: '/api/users',
method: 'POST',
status_code: 500,
error_message: 'Internal server error'
}
});
// Performance metric
client.capture({
distinctId: 'user_123',
event: 'page_load_time',
properties: {
url: '/dashboard',
load_time_ms: 2500,
is_slow: true
}
});import express from 'express';
import { PostHog } from 'posthog-node';
const app = express();
const client = new PostHog('phc_your_api_key');
// Track request
app.use((req, res, next) => {
client.capture({
distinctId: req.user?.id || 'anonymous',
event: 'api_request',
properties: {
path: req.path,
method: req.method,
user_agent: req.headers['user-agent']
}
});
next();
});
// Shutdown on process exit
process.on('SIGTERM', async () => {
await client.shutdown();
process.exit(0);
});import { PostHog } from 'posthog-node';
const client = new PostHog('phc_your_api_key');
export async function handler(event, context) {
try {
// Track function invocation
await client.captureImmediate({
distinctId: event.userId || context.awsRequestId,
event: 'lambda_invoked',
properties: {
function_name: context.functionName,
request_id: context.awsRequestId
}
});
// Your business logic
const result = await processEvent(event);
// Track success
await client.captureImmediate({
distinctId: event.userId || context.awsRequestId,
event: 'lambda_success',
properties: {
function_name: context.functionName,
duration_ms: Date.now() - event.startTime
}
});
return { statusCode: 200, body: JSON.stringify(result) };
} catch (error) {
// Track error
await client.captureExceptionImmediate(error, event.userId);
return { statusCode: 500, body: 'Internal error' };
}
}Use descriptive, consistent event names in the format [object]_[action]:
// Good
client.capture({ distinctId: 'user_123', event: 'button_clicked' });
client.capture({ distinctId: 'user_123', event: 'form_submitted' });
client.capture({ distinctId: 'user_123', event: 'video_played' });
// Avoid
client.capture({ distinctId: 'user_123', event: 'click' });
client.capture({ distinctId: 'user_123', event: 'submit' });
client.capture({ distinctId: 'user_123', event: 'play' });Use snake_case for property names and avoid special characters:
// Good
client.capture({
distinctId: 'user_123',
event: 'purchase_completed',
properties: {
order_id: 'order_789',
total_amount: 99.99,
item_count: 3
}
});
// Avoid
client.capture({
distinctId: 'user_123',
event: 'purchase_completed',
properties: {
'Order ID': 'order_789',
'Total-Amount': 99.99,
'item.count': 3
}
});capture() for: Web servers, long-running processescaptureImmediate() for: Serverless functions, edge workers, critical events// Long-running server: use queued capture
app.post('/api/event', (req, res) => {
client.capture({
distinctId: req.user.id,
event: 'api_called'
});
res.json({ success: true });
});
// Serverless: use immediate capture
export async function handler(event) {
await client.captureImmediate({
distinctId: event.userId,
event: 'function_called'
});
return { statusCode: 200 };
}Don't mix capture() and captureImmediate() in the same application, as they use different queueing strategies.
// Bad: mixing methods
client.capture({ distinctId: 'user_123', event: 'event1' });
await client.captureImmediate({ distinctId: 'user_123', event: 'event2' });
// Good: choose one approach
client.capture({ distinctId: 'user_123', event: 'event1' });
client.capture({ distinctId: 'user_123', event: 'event2' });
await client.shutdown(); // Flush queue