[ Web Proxy ]
URL:
Viewing: https://docs.kitbase.dev/identify-users [Back]  [Original]

Identify Users | Kitbase
Skip to content
Main Navigation HomeQuick StartWeb AnalyticsSDKsDashboardChangelog
Menu
Return to top
Sidebar Navigation

Getting Started

AI Visibility

Site Audit

Keyword Research

Workflows

On this page
    Copy page

    Identify Users

    Link anonymous visitors to known users so every event, from first page view to final purchase, is attributed to a single person.

    Overview

    Kitbase tracks users with two identifiers:

    IdentifierDescription
    anonymous_idAuto-generated UUID assigned to every visitor before they log in
    user_idYour unique user identifier, set when you call identify()

    Before identification, all events are linked to the auto-generated anonymous ID. After identify() is called, the SDK sends a request to POST /sdk/v1/identify (authenticated with your SDK key), and subsequent events are attributed to the real user. The server also backfills past anonymous events so nothing is lost.

    How It Works

    1. User visits site      anonymous_id generated (UUID, stored in localStorage)
    2. User browses          events tracked with anonymous_id only
    3. User logs in          identify(userId, traits) called
    4. SDK sends request     server links anonymous_id to user_id
    5. Server backfills      previous anonymous events now attributed to user
    6. Subsequent events     include both anonymous_id and user_id

    Basic Usage

    Call identify() immediately after the user authenticates:

    typescript
    // After user logs in
    await kitbase.identify({
      userId: 'user_123',
      traits: {
        email: 'jane@example.com',
        name: 'Jane Doe',
        plan: 'premium',
        company: 'Acme Inc'
      }
    });

    Identity Linking Requires identify()

    Kitbase does not automatically link anonymous users to identified users. You must explicitly call identify() after authentication.

    Identify Options

    typescript
    interface IdentifyOptions {
      userId: string;                       // Required: your unique user identifier
      traits?: Record<string, unknown>;     // Optional: user properties
    }
    ParameterTypeRequiredDescription
    userIdstringYesYour unique user identifier (database ID recommended)
    traitsRecord<string, unknown>NoArbitrary key-value pairs describing the user

    Traits can include any key-value pairs. Common examples:

    TraitExample
    email"jane@example.com"
    name"Jane Doe"
    plan"premium"
    company"Acme Inc"
    role"admin"
    created_at"2025-03-15T10:00:00Z"

    When to Call identify()

    Call identify() immediately after any of these events:

    • After login (email/password, OAuth, magic link)
    • After signup (new account creation)
    • After OAuth callback (Google, GitHub, etc.)
    • On app load when the user is already authenticated (check your auth state)
    typescript
    // After OAuth login
    async function handleOAuthCallback(user) {
      await kitbase.identify({
        userId: user.id,
        traits: {
          email: user.email,
          name: user.name,
          provider: 'google'
        }
      });
    }
    
    // On app load if already authenticated
    if (currentUser) {
      await kitbase.identify({
        userId: currentUser.id,
        traits: {
          email: currentUser.email,
          plan: currentUser.plan
        }
      });
    }

    Call identify() as early as possible

    The sooner you identify a user after authentication, the fewer events remain anonymous. Place your identify() call at the earliest point in your auth flow.

    Anonymous ID Management

    Retrieve the current identifiers at any time:

    typescript
    kitbase.getAnonymousId();  // Returns current anonymous UUID
    kitbase.getUserId();       // Returns user_id if identified, null otherwise

    Storage Options

    The anonymous ID is persisted across page reloads. You can configure how and where it is stored:

    typescript
    // Default: localStorage
    const kitbase = init({
      sdkKey: '<YOUR_SDK_KEY>',
      storage: localStorage
    });
    
    // Custom storage (must implement getItem / setItem / removeItem)
    const kitbase = init({
      sdkKey: '<YOUR_SDK_KEY>',
      storage: myCustomStorage
    });
    
    // No persistence (new anonymous ID generated each session)
    const kitbase = init({
      sdkKey: '<YOUR_SDK_KEY>',
      storage: null
    });

    Reset Identity

    Clear the current user and start a fresh anonymous session:

    typescript
    kitbase.reset();
    // Clears user_id, generates a new anonymous_id, starts a new session

    Use reset() when:

    • The user logs out
    • The user switches accounts
    typescript
    async function handleLogout() {
      await authService.logout();
      kitbase.reset(); // Start tracking as a new anonymous user
    }

    Multi-Device Support

    When the same person uses your app on multiple devices:

    • Each device generates its own anonymous_id
    • Calling identify() with the same userId on each device links all activity to one user
    • Events from every device are attributed to the same user profile
    typescript
    // Device A: anonymous_id = "aaa-111"
    await kitbase.identify({ userId: 'user_123' });
    // -> aaa-111 linked to user_123
    
    // Device B: anonymous_id = "bbb-222"
    await kitbase.identify({ userId: 'user_123' });
    // -> bbb-222 also linked to user_123
    
    // All events from both devices are now attributed to user_123

    MAU Accuracy

    Identity resolution prevents double-counting users who browse anonymously before signing in. A user who visits your site anonymously and later creates an account counts as one MAU, not two.

    Server-Side Behavior

    When identify() is called, the following happens on the server:

    1. The SDK sends POST /sdk/v1/identify with { userId, anonymousId, traits }
    2. The server creates a link between the anonymous_id and the user_id
    3. The server backfills user_id on all past events matching that anonymous_id in ClickHouse
    4. The server responds with:
    json
    {
      "success": true,
      "userId": "user_123",
      "previouslyLinked": false
    }
    FieldTypeDescription
    successbooleanWhether the identification succeeded
    userIdstringThe identified user ID
    previouslyLinkedbooleantrue if this anonymous ID was already linked to this user

    REST API (Direct)

    You can call the identify endpoint directly without the SDK:

    bash
    curl -X POST https://ingest.kitbase.dev/sdk/v1/identify \
      -H "x-sdk-key: YOUR_SDK_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "user_id": "user_123",
        "anonymous_id": "550e8400-e29b-41d4-a716-446655440000",
        "traits": {
          "email": "jane@example.com",
          "name": "Jane Doe"
        }
      }'

    Best Practices

    Use consistent user IDs

    Always use the same identifier format for a given user. Database IDs or UUIDs work well:

    typescript
    // Good: consistent database ID
    await kitbase.identify({ userId: user.id });
    
    // Bad: mixing formats across your app
    await kitbase.identify({ userId: user.email });   // email in one place
    await kitbase.identify({ userId: String(user.id) }); // numeric ID elsewhere

    Avoid PII as user IDs

    Do not use personally identifiable information (email addresses, phone numbers) as the userId. Use opaque database IDs instead, and pass PII as traits:

    typescript
    // Good
    await kitbase.identify({
      userId: 'usr_8f3a2b',
      traits: { email: 'jane@example.com' }
    });
    
    // Bad
    await kitbase.identify({
      userId: 'jane@example.com'
    });

    Update traits when the profile changes

    Call identify() again whenever user properties change (plan upgrade, name update, etc.) to keep traits current:

    typescript
    async function handlePlanUpgrade(newPlan: string) {
      await billingService.upgrade(newPlan);
    
      await kitbase.identify({
        userId: currentUser.id,
        traits: {
          plan: newPlan,
          upgraded_at: new Date().toISOString()
        }
      });
    }

    Call reset() on logout

    Always call reset() when a user logs out to prevent the next user on a shared device from inheriting the previous identity:

    typescript
    async function handleLogout() {
      await authService.logout();
      kitbase.reset();
    }

    Identify as early as possible

    Place your identify() call at the earliest point after authentication. The longer you wait, the more events are tracked without a user_id.

    Next steps

    Pager

    Released under the MIT License.


    Web Proxy Viewer  |  New URL  |  Original Page