Skip to content

User Identity

Learn how to track anonymous users and link them to identified users for accurate analytics.

Overview

Kitbase tracks users using two identifiers:

IdentifierDescription
anonymous_idAuto-generated UUID for anonymous users
user_idYour user identifier (after login/signup)

Anonymous Tracking

The SDK automatically generates and persists an anonymous ID for tracking users before they log in:

typescript
// Track anonymous user (anonymous_id is automatically included)
await kitbase.track({
  channel: 'marketing',
  event: 'Landing Page Viewed',
  icon: '👀',
});

// Get the current anonymous ID
const anonymousId = kitbase.getAnonymousId();
// => "550e8400-e29b-41d4-a716-446655440000"

Storage

The anonymous ID is persisted in storage (localStorage by default) to maintain consistency across page reloads:

typescript
const kitbase = new Kitbase({
  token: '<YOUR_API_KEY>',
  storage: localStorage,                  // Default
  storageKey: 'kitbase_anonymous_id',     // Default
});

// Disable storage (anonymous ID regenerated each session)
const kitbase = new Kitbase({
  token: '<YOUR_API_KEY>',
  storage: null,
});

Identity Resolution

Link anonymous users to identified users using the identify() function. This enables accurate Monthly Active User (MAU) calculations.

The identify() Function

typescript
await kitbase.identify({
  userId: 'user-123',
  traits: {
    email: 'user@example.com',
    name: 'John Doe',
    plan: 'premium',
  },
});
ParameterTypeRequiredDescription
userIdstringYesUnique user identifier
traitsobjectNoUser properties (email, name, etc.)

How It Works

  1. Anonymous tracking: When a user first interacts with your app, the SDK generates an anonymous ID internally and attaches it to all events.

  2. Explicit identification: When the user logs in or signs up, you call identify() to link the anonymous ID to a user ID.

  3. Deduplication: Once linked, all previous anonymous events are attributed to the identified user, ensuring accurate user counts.

Example Flow

typescript
// Session 1: Track anonymous user
await kitbase.track({
  channel: 'engagement',
  event: 'Page View',
});
// → tracked with anonymous_id: "anon_abc123"

await kitbase.track({
  channel: 'engagement',
  event: 'Add to Cart',
});
// → tracked with anonymous_id: "anon_abc123"

// Session 2: User logs in - MUST call identify()
await kitbase.identify({
  userId: 'user-456',
  traits: { email: 'user@example.com' },
});
// → Links anon_abc123 to user-456

// Subsequent events use user_id
await kitbase.track({
  channel: 'purchases',
  event: 'Purchase',
  user_id: 'user-456',
});
// → All events now attributed to user-456

Identity Linking Requires identify()

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

User ID Management

typescript
// Get current user ID (set via identify)
const userId = kitbase.getUserId();
// => "user-123" or null

// Get anonymous ID
const anonymousId = kitbase.getAnonymousId();
// => "550e8400-e29b-41d4-a716-446655440000"

// Reset user data (clears user_id and generates new anonymous_id)
kitbase.reset();

Best Practices

When to Call identify()

Call identify() immediately after:

  • User login
  • User signup
  • User authentication via OAuth/SSO
typescript
// After successful login
async function handleLogin(credentials) {
  const user = await authService.login(credentials);

  // Identify the user immediately
  await kitbase.identify({
    userId: user.id,
    traits: {
      email: user.email,
      name: user.name,
      plan: user.subscription?.plan,
    },
  });

  // Track the login event
  await kitbase.track({
    channel: 'users',
    event: 'User Logged In',
    user_id: user.id,
    icon: '🔐',
  });
}

Consistent User IDs

Use the same user_id format across your application:

typescript
// Good: Consistent format
user_id: user.id           // Database ID
user_id: user.email        // Email (if unique)
user_id: user.uuid         // UUID

// Bad: Inconsistent formats
user_id: user.id           // "123" in one place
user_id: user.email        // "user@example.com" in another

Update Traits on Profile Changes

Call identify() again when user properties change:

typescript
async function handleProfileUpdate(updates) {
  await userService.update(updates);

  // Update traits
  await kitbase.identify({
    userId: currentUser.id,
    traits: {
      name: updates.name || currentUser.name,
      plan: updates.plan || currentUser.plan,
    },
  });
}

Multi-Device Users

When a user logs in on a new device:

  1. The new device has its own anonymous ID
  2. Calling identify() links both devices to the same user
  3. Events from both devices are attributed to the same user
typescript
// Device A: anonymous_id = "aaa-111"
// Device B: anonymous_id = "bbb-222"

// User logs in on Device A
await kitbase.identify({ userId: 'user-123' });
// → aaa-111 linked to user-123

// User logs in on Device B
await kitbase.identify({ userId: 'user-123' });
// → bbb-222 also linked to user-123

// Both devices' events 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.

Released under the MIT License.