or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

client-configuration.mderror-tracking.mdevent-tracking.mdexperimental.mdexpress-integration.mdfeature-flags.mdidentification.mdindex.mdsentry-integration.md
tile.json

identification.mddocs/

User and Group Identification

Identify users with properties, create aliases to link identities, and manage group analytics for organization-level tracking.

Capabilities

Identify User

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 User Immediately

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()
    }
  });
}

Create Alias

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 Alias Immediately

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'
});

Group Identify

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
});

Types

IdentifyMessage

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;
}

GroupIdentifyMessage

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;
}

Usage Patterns

User Onboarding Flow

// 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'
});

Progressive Profiling

// 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()
  }
});

User Property Updates

// 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
  }
});

B2B Group Analytics

// 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
});

Multi-level Groups

// 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 Merge Scenario

// 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()
  }
});

Best Practices

When to Use Identify

Use identify() when you want to:

  • Set or update user properties
  • Associate a user with their email, name, or other attributes
  • Track user lifecycle (signup, upgrade, etc.)
// Good: Set meaningful properties
client.identify({
  distinctId: 'user_123',
  properties: {
    email: 'user@example.com',
    plan: 'premium',
    signup_date: '2025-01-01'
  }
});

When to Use Alias

Use alias() when you need to:

  • Link an anonymous user to an identified user after signup
  • Merge two user identities
  • Connect different sessions from the same user
// Good: Link anonymous to identified user
client.alias({
  distinctId: 'user_123',      // New identified ID
  alias: 'anonymous_session_id' // Previous anonymous ID
});

When to Use Group Identify

Use groupIdentify() when you need to:

  • Track company or organization-level properties
  • Analyze usage by teams, departments, or other groups
  • Build B2B analytics dashboards
// Good: Track company properties
client.groupIdentify({
  groupType: 'company',
  groupKey: 'acme_corp',
  properties: {
    plan: 'enterprise',
    employee_count: 500
  }
});

Property Naming

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 vs $set_once

  • Use $set for properties that can change
  • Use $set_once for properties that should only be set once
client.identify({
  distinctId: 'user_123',
  properties: {
    $set: {
      last_login: new Date().toISOString(),
      plan: 'premium'
    },
    $set_once: {
      signup_date: '2025-01-01',
      first_referrer: 'google.com'
    }
  }
});

Group Type Limits

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'];