# User Identification

User identification allows you to associate events with specific users, set person properties, create aliases between distinct IDs, and manage user state.

## Capabilities

### Identify User

Identifies a user with a distinct ID and optionally sets person properties.

```typescript { .api }
/**
 * Identifies a user with a distinct ID and sets person properties
 * @param new_distinct_id - Unique identifier for the user (optional)
 * @param userPropertiesToSet - Properties to set on the person profile
 * @param userPropertiesToSetOnce - Properties to set only if not already set
 */
function identify(
    new_distinct_id?: string,
    userPropertiesToSet?: Properties,
    userPropertiesToSetOnce?: Properties
): void;
```

**Usage Examples:**

```typescript
// Identify with just a user ID
posthog.identify('user-123');

// Identify with user ID and properties
posthog.identify('user-123', {
    email: 'user@example.com',
    name: 'John Doe',
    plan: 'premium'
});

// Set properties only once (useful for immutable attributes)
posthog.identify('user-123',
    { last_login: new Date().toISOString() },
    { first_seen: new Date().toISOString() }
);

// Update properties without changing distinct ID
posthog.identify(undefined, {
    subscription_status: 'active'
});
```

### Set Person Properties

Sets person properties without changing the distinct ID.

```typescript { .api }
/**
 * Sets person properties for the current user
 * @param userPropertiesToSet - Properties to set on the person profile
 * @param userPropertiesToSetOnce - Properties to set only if not already set
 */
function setPersonProperties(
    userPropertiesToSet?: Properties,
    userPropertiesToSetOnce?: Properties
): void;
```

**Usage Example:**

```typescript
// Update user properties
posthog.setPersonProperties({
    subscription_tier: 'pro',
    last_active: new Date().toISOString()
});

// Set properties once (won't overwrite if already exists)
posthog.setPersonProperties(
    { current_plan: 'enterprise' },
    { signup_date: '2024-01-15' }
);
```

### Create Person Profile

Explicitly creates a person profile for the current user.

```typescript { .api }
/**
 * Explicitly creates a person profile for the current user
 * Useful when person_profiles config is set to 'identified_only' or 'never'
 */
function createPersonProfile(): void;
```

**Usage Example:**

```typescript
// Force creation of person profile
posthog.createPersonProfile();
```

### Reset User State

Resets the user state, creating a new anonymous user.

```typescript { .api }
/**
 * Resets the user state, creating a new anonymous user
 * @param reset_device_id - If true, also resets the device ID (default: false)
 */
function reset(reset_device_id?: boolean): void;
```

**Usage Examples:**

```typescript
// Reset user (keep device ID)
posthog.reset();

// Reset user and device ID (complete reset)
posthog.reset(true);

// Common use case: user logout
function logout() {
    posthog.reset();
    // Clear session, redirect, etc.
}
```

### Create Alias

Creates an alias linking two distinct IDs, allowing you to merge user profiles.

```typescript { .api }
/**
 * Creates an alias linking two distinct IDs
 * @param alias - The new distinct ID to link
 * @param original - The original distinct ID (optional, defaults to current distinct ID)
 * @returns CaptureResult if successful
 */
function alias(alias: string, original?: string): CaptureResult | void | number;
```

**Usage Examples:**

```typescript
// Link anonymous user to identified user
const anonymousId = posthog.get_distinct_id();
posthog.alias('user-123'); // Links current ID to 'user-123'

// Explicit alias between two IDs
posthog.alias('user-123', 'anonymous-abc-def');

// Common pattern: after signup
function onSignup(userId) {
    posthog.alias(userId);
    posthog.identify(userId, {
        email: user.email,
        name: user.name
    });
}
```

### Get Distinct ID

Gets the current distinct ID for the user.

```typescript { .api }
/**
 * Gets the current distinct ID for the user
 * @returns The current distinct ID
 */
function get_distinct_id(): string;
```

**Usage Example:**

```typescript
const distinctId = posthog.get_distinct_id();
console.log('Current user ID:', distinctId);

// Use in API calls
fetch('/api/user-data', {
    headers: {
        'X-User-ID': posthog.get_distinct_id()
    }
});
```

### Get Groups

Gets all current group memberships for the user.

```typescript { .api }
/**
 * Gets all current group memberships
 * @returns Object mapping group types to group keys
 */
function getGroups(): Record<string, any>;
```

**Usage Example:**

```typescript
const groups = posthog.getGroups();
console.log('User groups:', groups);
// Example output: { company: 'acme-inc', team: 'engineering' }
```

## Deprecated Methods

### people.set()

**Deprecated**: Use `setPersonProperties()` instead.

```typescript { .api }
/**
 * @deprecated Use setPersonProperties() instead
 * Sets person properties
 * @param prop - Property name or properties object
 * @param to - Property value (if prop is a string)
 * @param callback - Optional callback for request completion
 */
function people.set(
    prop: string | Properties,
    to?: string,
    callback?: RequestCallback
): void;
```

**Migration Example:**

```typescript
// Old way (deprecated)
posthog.people.set('email', 'user@example.com');
posthog.people.set({ name: 'John', age: 30 });

// New way
posthog.setPersonProperties({ email: 'user@example.com' });
posthog.setPersonProperties({ name: 'John', age: 30 });
```

### people.set_once()

**Deprecated**: Use `setPersonProperties()` with second parameter instead.

```typescript { .api }
/**
 * @deprecated Use setPersonProperties(undefined, props) instead
 * Sets person properties once if not already set
 * @param prop - Property name or properties object
 * @param to - Property value (if prop is a string)
 * @param callback - Optional callback for request completion
 */
function people.set_once(
    prop: string | Properties,
    to?: string,
    callback?: RequestCallback
): void;
```

**Migration Example:**

```typescript
// Old way (deprecated)
posthog.people.set_once('signup_date', '2024-01-15');
posthog.people.set_once({ initial_referrer: 'google' });

// New way
posthog.setPersonProperties(undefined, { signup_date: '2024-01-15' });
posthog.setPersonProperties(undefined, { initial_referrer: 'google' });
```

## Types

### Properties

```typescript { .api }
/**
 * Object containing user or event properties
 */
type Properties = Record<string, Property | Property[]>;
```

### Property

```typescript { .api }
/**
 * A single property value
 */
type Property = string | number | boolean | null | undefined;
```

### RequestCallback

```typescript { .api }
/**
 * Callback for request completion
 */
type RequestCallback = (response: RequestResponse) => void;
```

### RequestResponse

```typescript { .api }
/**
 * Response from a PostHog request
 */
interface RequestResponse {
    /**
     * HTTP status code
     */
    statusCode: number;

    /**
     * HTTP status text
     */
    statusText?: string;

    /**
     * Response body
     */
    body?: string;
}
```

## Best Practices

### Identification Timing

When to call `identify()`:

```typescript
// After user logs in
async function login(email, password) {
    const user = await authenticateUser(email, password);
    posthog.identify(user.id, {
        email: user.email,
        name: user.name,
        plan: user.plan
    });
}

// After user signs up
async function signup(userData) {
    const user = await createUser(userData);
    // Create alias from anonymous ID to user ID
    posthog.alias(user.id);
    // Identify with user properties
    posthog.identify(user.id, {
        email: user.email,
        name: user.name
    });
}

// On app initialization (for already logged-in users)
async function initializeApp() {
    const user = await getCurrentUser();
    if (user) {
        posthog.identify(user.id, {
            email: user.email,
            plan: user.plan
        });
    }
}
```

### Reset on Logout

Always reset user state when users log out:

```typescript
function logout() {
    // Reset PostHog state
    posthog.reset();

    // Clear local storage/session
    localStorage.clear();

    // Redirect to login
    window.location.href = '/login';
}
```

### Anonymous vs Identified Users

Handle both anonymous and identified users appropriately:

```typescript
// Check if user is identified
function isUserIdentified() {
    const distinctId = posthog.get_distinct_id();
    // Anonymous IDs are UUIDs, identified IDs are typically not
    return !distinctId.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
}

// Use different logic based on user state
if (isUserIdentified()) {
    // Show personalized content
} else {
    // Show generic content
}
```

### Person Profile Configuration

Control when person profiles are created using the `person_profiles` config:

```typescript
// Only create profiles for identified users (recommended)
posthog.init('token', {
    person_profiles: 'identified_only' // Default
});

// Always create profiles (more data, higher costs)
posthog.init('token', {
    person_profiles: 'always'
});

// Never create profiles (anonymous-only tracking)
posthog.init('token', {
    person_profiles: 'never'
});

// Force profile creation when needed
if (shouldCreateProfile()) {
    posthog.createPersonProfile();
}
```

### Aliasing Best Practices

Use aliases carefully to merge user identities:

```typescript
// ✅ Good: Alias before identify
function onSignup(userId) {
    posthog.alias(userId); // Link anonymous ID to user ID
    posthog.identify(userId, { email: user.email });
}

// ❌ Bad: Identify without alias (creates separate profiles)
function onSignup(userId) {
    posthog.identify(userId, { email: user.email });
    // Anonymous events won't be linked to this user
}

// ✅ Good: Merge external IDs
function linkExternalAccount(externalId) {
    const currentId = posthog.get_distinct_id();
    posthog.alias(externalId, currentId);
}
```

### Property Naming Conventions

Use consistent naming for person properties:

```typescript
// ✅ Good: Snake case, descriptive names
posthog.identify('user-123', {
    email: 'user@example.com',
    first_name: 'John',
    last_name: 'Doe',
    subscription_tier: 'premium',
    account_created_at: '2024-01-15',
    total_purchases: 5
});

// ❌ Bad: Inconsistent naming
posthog.identify('user-123', {
    Email: 'user@example.com',
    firstName: 'John',
    LastName: 'Doe',
    'subscription-tier': 'premium'
});
```

## Common Patterns

### User Lifecycle Management

```typescript
// App initialization
async function initApp() {
    const currentUser = await checkAuth();

    if (currentUser) {
        // Identify logged-in user
        posthog.identify(currentUser.id, {
            email: currentUser.email,
            plan: currentUser.plan
        });
    }
    // Otherwise, user remains anonymous
}

// Signup flow
async function handleSignup(formData) {
    const newUser = await createAccount(formData);

    // Create alias to link anonymous activity
    posthog.alias(newUser.id);

    // Identify with initial properties
    posthog.identify(newUser.id, {
        email: newUser.email,
        name: newUser.name
    }, {
        signup_date: new Date().toISOString(),
        initial_referrer: document.referrer
    });
}

// Login flow
async function handleLogin(credentials) {
    const user = await authenticate(credentials);

    // Identify returning user
    posthog.identify(user.id, {
        email: user.email,
        last_login: new Date().toISOString()
    });
}

// Logout flow
function handleLogout() {
    posthog.reset();
    clearSession();
    redirectToLogin();
}
```

### Progressive User Properties

Update user properties as you learn more:

```typescript
// On signup: basic info
posthog.identify(userId, {
    email: user.email,
    name: user.name
});

// After onboarding: preferences
posthog.setPersonProperties({
    preferred_language: 'en',
    notification_settings: 'daily'
});

// After first purchase: lifecycle stage
posthog.setPersonProperties({
    customer_stage: 'active',
    first_purchase_date: new Date().toISOString()
});

// Properties set once (never updated)
posthog.setPersonProperties(undefined, {
    signup_referrer: document.referrer,
    initial_utm_source: utmSource
});
```
