Users
Kitbase tracks two types of users: anonymous users who have not been identified, and identified users who have been linked to a known user ID via the identify() method.
User Types
| Type | Identifier | How It Works |
|---|---|---|
| Anonymous | anonymous_id (auto-generated UUID) | Created automatically on first visit. Each device gets its own anonymous ID. |
| Identified | user_id (your identifier) | Linked to a known user via identify(). Associates all activity with a single identity. |
Anonymous Tracking
When a user first visits your site, the SDK automatically generates a UUID and stores it in localStorage. This anonymous ID is attached to every event the user triggers.
// Anonymous ID is generated and included automatically
await kitbase.track({
channel: 'engagement',
event: 'Landing Page Viewed',
});
// Retrieve the current anonymous ID
const anonymousId = kitbase.getAnonymousId();
// => "550e8400-e29b-41d4-a716-446655440000"Key points about anonymous tracking:
- The UUID is generated on the user's first visit.
- It is stored in localStorage, so it persists across page loads and browser restarts.
- All events are attributed to this
anonymous_iduntil the user is identified. - Each device gets its own
anonymous_id. A user on two devices will appear as two anonymous users untilidentify()is called on both.
Disabling Storage
If you do not want to persist the anonymous ID across page loads, disable storage:
const kitbase = init({
sdkKey: '<YOUR_API_KEY>',
storage: null, // Anonymous ID regenerated each session
});User Identification
Call identify() after a user logs in or signs up to link their anonymous activity to a known user ID.
await kitbase.identify({
userId: 'user-123',
traits: {
email: 'jane@example.com',
name: 'Jane Doe',
plan: 'premium',
},
});When identify() is called:
- The SDK sends the current
anonymous_idand the provideduserIdto the server. - The server creates a link between the two identifiers.
- All past events associated with that
anonymous_idare backfilled with theuser_id. - All subsequent events automatically include the
user_id.
Multi-Device Identification
When the same user logs in on multiple devices, each device has its own anonymous_id. Calling identify() on each device links all anonymous IDs to the same user_id, unifying the user's activity across devices.
// 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
// Both devices' events are now attributed to user-123User Analytics Dashboard
The Users page in the dashboard gives you a complete view of your user base.
User List
Browse all users with the following controls:
| Control | Description |
|---|---|
| Type filter | Show all users, only identified users, or only anonymous users |
| Search | Search by user ID or anonymous ID |
| Country filter | Filter by geographic location |
| Browser filter | Filter by browser name |
| Date range | Filter by when users were first or last seen |
User Detail View
Click on any user to see their full profile:
| Section | Description |
|---|---|
| User type | Whether the user is identified or anonymous |
| Session count | Total number of sessions recorded for this user |
| Event count | Total number of events triggered by this user |
| First seen | Timestamp of the user's earliest event |
| Last seen | Timestamp of the user's most recent event |
| User properties | Traits set via identify() (email, name, plan, etc.) |
| Activity heatmap | A calendar heatmap showing events per day over recent months |
| Event history | A chronological list of all events with timestamps and details |
User Properties (Traits)
Traits are key-value pairs that describe the user. They are set through the identify() method and are visible in the user detail view.
await kitbase.identify({
userId: 'user-123',
traits: {
email: 'jane@example.com',
name: 'Jane Doe',
company: 'Acme Corp',
plan: 'premium',
created_at: '2025-01-15T10:00:00Z',
},
});Traits can be updated at any time by calling identify() again with the same userId and new or changed values:
// User upgrades their plan
await kitbase.identify({
userId: 'user-123',
traits: {
plan: 'enterprise',
},
});The new traits are merged with existing ones. You do not need to resend all traits on every call.
Identity Resolution
Identity resolution is the process of connecting anonymous and identified user records into a single profile.
How It Works
- Before
identify()-- The user is tracked under theiranonymous_id. All events are attributed to this anonymous identifier. - When
identify()is called -- The server creates a mapping fromanonymous_idtouser_id. - Backfill -- All past events that were recorded with the
anonymous_idare retroactively associated with theuser_id. - Response -- The server response indicates whether this was a new link or a previously established one.
This ensures accurate Monthly Active User (MAU) counts. A user who browses anonymously and later creates an account is counted as one user, not two.
TIP
Identity resolution prevents double-counting. Without it, a user who visits your site anonymously and then signs up would appear as two separate users in your analytics.
Best Practices
Use Database IDs as user_id
Use your application's internal database ID or UUID as the userId, not personally identifiable information like email addresses. This avoids leaking PII into analytics and keeps the identifier stable even if the user changes their email.
// Recommended
await kitbase.identify({ userId: user.databaseId });
// Avoid
await kitbase.identify({ userId: user.email });Call identify() Early
Call identify() as soon as the user is authenticated. This ensures that events triggered immediately after login are correctly attributed.
async function handleLogin(credentials) {
const user = await authService.login(credentials);
// Identify immediately after authentication
await kitbase.identify({
userId: user.id,
traits: {
email: user.email,
name: user.name,
plan: user.subscription?.plan,
},
});
}Update Traits on Profile Changes
When user properties change (e.g., plan upgrade, name change), call identify() again to keep traits current.
async function handlePlanUpgrade(newPlan) {
await kitbase.identify({
userId: currentUser.id,
traits: { plan: newPlan },
});
}Call reset() on Logout
When a user logs out, call reset() to clear the user ID and generate a new anonymous ID. This prevents the next user on the same device from being attributed to the previous user's identity.
function handleLogout() {
kitbase.reset();
// Clears user_id, generates a new anonymous_id, starts a new session
}Be Consistent with user_id Format
Use the same format for userId across all platforms and services. If you use a database integer ID on the web, use the same ID in your mobile app and backend. Inconsistent formats lead to fragmented user profiles.
// Consistent: always use the database ID
userId: String(user.id) // "12345" everywhere
// Inconsistent: different formats in different places
userId: user.id // "12345" on web
userId: user.email // "jane@example.com" on mobile