Skip to main content
Until you say otherwise, events are anonymous and carry only a generated session ID. Once you know who the user is, call identify() and every event after that carries their user ID and traits. The session’s earlier anonymous events are linked to that user at query time too, so a funnel counts the whole journey as one person. The identity is saved in localStorage and restored by init(), which means a returning visitor is still identified until you call reset() on logout.

Identifying a user

  • userId: a string that uniquely identifies the user in your system. Use a stable, non-PII identifier like a database ID or UUID.
  • traits: an optional Record<string, unknown> of attributes that describe the user. Traits are sent with every event after this call.
Each call replaces the identity wholesale. Traits are never merged: calling identify('user_42', {}) wipes previously set traits, so pass the complete trait set every time. Traits are deep-cloned at call time, so mutating the object afterwards has no effect.
Traits are included in every event payload, not just at the moment you call identify(). Avoid putting sensitive PII (passwords, card numbers, government IDs) in traits.

The identity object shape

The identity is stored internally as an Identity type and embedded in each request payload:
Before identify() is called, userId is null and traits is an empty object {}. After calling identify(), both fields reflect the values you provided.

When to call identify()

Call identify() as soon as the user’s identity becomes known to your app:
1

After login

The user just authenticated. You now have a stable user ID to associate with future events.
2

After signup

A new account was just created. Identifying immediately links the first events (onboarding steps, feature tours) to the new user.
3

On page load when the session is already authenticated

init() restores the saved identity, so a returning visitor is already identified. Re-identifying after you check your auth session is still worth it. It keeps traits fresh and covers users whose browser storage was cleared.

Sessions

Identity and session are separate. The session ID is a UUID generated for you and kept in sessionStorage under @wendung/sdk/session/v1, so it survives reloads in the same tab. Every event carries it; you never manage it yourself. A session ends, and a new ID starts, after 30 minutes without activity, after 24 hours in total, when you call reset(), or when identify() names a different user than the current one (an account switch without a logout). The first identify() in an anonymous session keeps the session. That is what makes the earlier anonymous events attributable to the user.

Resetting identity on logout

Call reset() when the user logs out. It does five things:
  1. Flushes any pending events. They are delivered with the identity they were tracked under, never dropped.
  2. Clears the userId (sets it back to null)
  3. Clears all traits (resets to {})
  4. Removes the persisted identity from localStorage
  5. Generates a new session ID
After reset(), any new events you track are anonymous until you call identify() again. They carry the new session ID but no user.
They are sent with userId: null and linked at query time to the first user identified in that session. Funnels, user stats, and journeys count the anonymous prefix and the identified tail as one person, with nothing for you to stitch. Events in sessions where nobody ever identifies stay anonymous.
Yes. Each call replaces the current userId and traits entirely. Re-identifying the same user (for example after a plan upgrade) keeps the session; identifying a different user starts a new session so the two users’ events stay separate. Include all traits on every call.