# 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.

```typescript { .api }
/**
 * Identify a user and set their properties
 * @param data - The identify data containing distinctId and properties
 */
identify(data: IdentifyMessage): void;
```

**Usage Examples:**

```typescript
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.

```typescript { .api }
/**
 * 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:**

```typescript
// 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.

```typescript { .api }
/**
 * 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:**

```typescript
// 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.

```typescript { .api }
/**
 * 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:**

```typescript
// 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).

```typescript { .api }
/**
 * Create or update a group and its properties
 * @param data - The group identify data
 */
groupIdentify(data: GroupIdentifyMessage): void;
```

**Usage Examples:**

```typescript
// 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

```typescript { .api }
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

```typescript { .api }
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

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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.)

```typescript
// 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

```typescript
// 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

```typescript
// Good: Track company properties
client.groupIdentify({
  groupType: 'company',
  groupKey: 'acme_corp',
  properties: {
    plan: 'enterprise',
    employee_count: 500
  }
});
```

### Property Naming

Use consistent, descriptive property names:

```typescript
// 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

```typescript
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:

```typescript
// Good: Well-planned hierarchy
const groupTypes = ['company', 'department', 'team', 'project', 'workspace'];

// Avoid: Too many or unclear types
const groupTypes = ['org', 'organization', 'company', 'business', 'enterprise'];
```
