Identify users with properties, create aliases to link identities, and manage group analytics for organization-level tracking.
Associate a user with their properties. Properties can be set directly or using $set and $set_once operators.
/**
* Identify a user and set their properties
* @param data - The identify data containing distinctId and properties
*/
identify(data: IdentifyMessage): void;Usage Examples:
import { PostHog } from 'posthog-node';
const client = new PostHog('phc_your_api_key');
// Basic identify with properties
client.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
name: 'John Doe',
plan: 'premium'
}
});
// Using $set and $set_once
client.identify({
distinctId: 'user_123',
properties: {
$set: {
email: 'user@example.com',
plan: 'premium'
},
$set_once: {
first_login: '2025-01-01T00:00:00Z',
signup_source: 'organic'
}
}
});
// Update user properties
client.identify({
distinctId: 'user_123',
properties: {
last_seen: new Date().toISOString(),
session_count: 15
}
});
// Disable GeoIP lookup
client.identify({
distinctId: 'user_123',
properties: {
name: 'John Doe'
},
disableGeoip: true
});Identify a user and send immediately without queuing. Use for serverless environments.
/**
* Identify a user and set their properties immediately (synchronously)
* @param data - The identify data containing distinctId and properties
* @returns Promise that resolves when the identify is processed
*/
identifyImmediate(data: IdentifyMessage): Promise<void>;Usage Examples:
// Immediate identify in serverless function
await client.identifyImmediate({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
name: 'John Doe'
}
});
// Update profile on login
async function handleLogin(userId, email) {
await client.identifyImmediate({
distinctId: userId,
properties: {
email: email,
last_login: new Date().toISOString()
}
});
}Link two distinct IDs together, typically used to connect an anonymous user with an identified user after signup or login.
/**
* Create an alias to link two distinct IDs together
* @param data - The alias data containing distinctId and alias
*/
alias(data: { distinctId: string; alias: string; disableGeoip?: boolean }): void;Usage Examples:
// Link anonymous user to identified user after signup
client.alias({
distinctId: 'user_123', // The new identified user ID
alias: 'anonymous_456' // The previous anonymous ID
});
// In signup flow
async function handleSignup(anonymousId, newUserId) {
// Create alias to link identities
client.alias({
distinctId: newUserId,
alias: anonymousId
});
// Identify the new user
client.identify({
distinctId: newUserId,
properties: {
signup_date: new Date().toISOString()
}
});
}
// Disable GeoIP lookup
client.alias({
distinctId: 'user_123',
alias: 'anonymous_456',
disableGeoip: true
});Create an alias and send immediately without queuing.
/**
* Create an alias to link two distinct IDs together immediately (synchronously)
* @param data - The alias data containing distinctId and alias
* @returns Promise that resolves when the alias is processed
*/
aliasImmediate(data: { distinctId: string; alias: string; disableGeoip?: boolean }): Promise<void>;Usage Examples:
// Immediate alias in serverless function
await client.aliasImmediate({
distinctId: 'user_123',
alias: 'anonymous_456'
});Create or update properties for a group (e.g., company, organization, team).
/**
* Create or update a group and its properties
* @param data - The group identify data
*/
groupIdentify(data: GroupIdentifyMessage): void;Usage Examples:
// Create a company group
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
name: 'Acme Corporation',
industry: 'Technology',
employee_count: 500,
plan: 'enterprise'
}
});
// Update organization properties
client.groupIdentify({
groupType: 'organization',
groupKey: 'org_456',
properties: {
region: 'US-West',
tier: 'premium'
}
});
// Associate with a specific user
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
updated_at: new Date().toISOString()
},
distinctId: 'user_123'
});
// Team group
client.groupIdentify({
groupType: 'team',
groupKey: 'team_engineering',
properties: {
name: 'Engineering',
size: 25,
department: 'Product'
}
});
// Disable GeoIP lookup
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
name: 'Acme Corporation'
},
disableGeoip: true
});interface IdentifyMessage {
/** Unique identifier for the user */
distinctId: string;
/** User properties to set ($set) or set once ($set_once) */
properties?: Record<string | number, any>;
/** Disable GeoIP lookup for this identify call */
disableGeoip?: boolean;
}interface GroupIdentifyMessage {
/** Type of group (e.g., 'company', 'organization', 'team') - limited to 5 per project */
groupType: string;
/** Unique identifier for the group */
groupKey: string;
/** Group properties to set */
properties?: Record<string | number, any>;
/** Optional distinctId to associate message with a specific user */
distinctId?: string;
/** Disable GeoIP lookup for this group identify call */
disableGeoip?: boolean;
}// Step 1: Anonymous user visits site
client.capture({
distinctId: 'anonymous_789',
event: 'page_viewed',
properties: {
page: 'landing'
}
});
// Step 2: User signs up
const newUserId = 'user_123';
// Link anonymous and identified IDs
client.alias({
distinctId: newUserId,
alias: 'anonymous_789'
});
// Set user properties
client.identify({
distinctId: newUserId,
properties: {
email: 'user@example.com',
signup_date: new Date().toISOString(),
signup_source: 'organic'
}
});
// Track signup event
client.capture({
distinctId: newUserId,
event: 'user_signed_up'
});// Initial signup - minimal info
client.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
$set_once: {
signup_date: new Date().toISOString()
}
}
});
// Later: user completes profile
client.identify({
distinctId: 'user_123',
properties: {
name: 'John Doe',
company: 'Acme Corp',
role: 'Engineer'
}
});
// Later: user upgrades plan
client.identify({
distinctId: 'user_123',
properties: {
plan: 'premium',
upgraded_at: new Date().toISOString()
}
});// Update properties on each login
app.post('/api/login', async (req, res) => {
const user = await authenticateUser(req);
client.identify({
distinctId: user.id,
properties: {
last_login: new Date().toISOString(),
login_count: user.loginCount + 1,
last_ip: req.ip
}
});
res.json({ success: true });
});
// Update properties on activity
client.identify({
distinctId: 'user_123',
properties: {
last_seen: new Date().toISOString(),
page_views: 42
}
});// Create company group
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
name: 'Acme Corporation',
industry: 'Technology',
employee_count: 500,
plan: 'enterprise',
mrr: 5000
}
});
// Track company-level event
client.capture({
distinctId: 'user_123',
event: 'document_created',
properties: {
document_type: 'proposal'
},
groups: {
company: 'acme_corp'
}
});
// Update company when it upgrades
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
plan: 'enterprise_plus',
upgraded_at: new Date().toISOString(),
mrr: 10000
},
distinctId: 'user_123' // Who triggered the upgrade
});// Company
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
name: 'Acme Corporation'
}
});
// Department within company
client.groupIdentify({
groupType: 'department',
groupKey: 'engineering',
properties: {
name: 'Engineering',
head_count: 50
}
});
// Team within department
client.groupIdentify({
groupType: 'team',
groupKey: 'team_backend',
properties: {
name: 'Backend Team',
members: 10
}
});
// Track event across all levels
client.capture({
distinctId: 'user_123',
event: 'code_deployed',
properties: {
service: 'api'
},
groups: {
company: 'acme_corp',
department: 'engineering',
team: 'team_backend'
}
});// User has two accounts that need merging
const primaryId = 'user_primary';
const secondaryId = 'user_secondary';
// Create alias to link accounts
client.alias({
distinctId: primaryId,
alias: secondaryId
});
// Update primary account with merged properties
client.identify({
distinctId: primaryId,
properties: {
accounts_merged: true,
merge_date: new Date().toISOString()
}
});Use identify() when you want to:
// Good: Set meaningful properties
client.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
plan: 'premium',
signup_date: '2025-01-01'
}
});Use alias() when you need to:
// Good: Link anonymous to identified user
client.alias({
distinctId: 'user_123', // New identified ID
alias: 'anonymous_session_id' // Previous anonymous ID
});Use groupIdentify() when you need to:
// Good: Track company properties
client.groupIdentify({
groupType: 'company',
groupKey: 'acme_corp',
properties: {
plan: 'enterprise',
employee_count: 500
}
});Use consistent, descriptive property names:
// Good
client.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
plan_type: 'premium',
signup_date: '2025-01-01',
is_active: true
}
});
// Avoid
client.identify({
distinctId: 'user_123',
properties: {
'E-mail': 'user@example.com',
'Plan': 'premium',
'date': '2025-01-01',
'active': true
}
});$set for properties that can change$set_once for properties that should only be set onceclient.identify({
distinctId: 'user_123',
properties: {
$set: {
last_login: new Date().toISOString(),
plan: 'premium'
},
$set_once: {
signup_date: '2025-01-01',
first_referrer: 'google.com'
}
}
});PostHog allows up to 5 group types per project. Plan your group hierarchy carefully:
// Good: Well-planned hierarchy
const groupTypes = ['company', 'department', 'team', 'project', 'workspace'];
// Avoid: Too many or unclear types
const groupTypes = ['org', 'organization', 'company', 'business', 'enterprise'];