Skip to content

Identifying users

Kilden separates events (immutable) from persons (mutable). Every event carries a distinct_id; identity resolution maps distinct ids to persons so that pre-signup and post-signup activity belong to the same human.

On first visit the SDK generates an anonymous id — anon_ + UUID v7 — persists it, and stamps it on every event. A person is created for it on the first event. No call needed.

When you know who the user is, call identify with your stable user id (a database id works better than an email — emails change):

kilden.identify('user_4821', { email: '[email protected]', plan: 'pro' });

This emits a $identify event that carries both ids (the user id as distinct_id, the anonymous id as $anon_distinct_id). The pipeline then does one of two things:

  • Your user id is new (the common case, ~90%): it’s added as another distinct id of the anonymous visitor’s person. All the pre-signup history is already attributed — nothing moves.
  • Your user id already has a person (login on a second device): the two persons merge.

Call identify on every page where the user is logged in, not just at login — it’s idempotent, and it’s what keeps new devices and cleared browsers linked.

  • The older person wins (its created_at); the newer person’s distinct ids are re-pointed to it.
  • Traits: the winner keeps its values on conflict; the loser only fills gaps. A later $set overwrites either way.
  • Past events keep working in queries: person merges are resolved at query time, so historical events attributed to the losing person count toward the winner.
kilden.setPersonProperties(
{ plan: 'enterprise' }, // $set — overwrites
{ signup_source: 'organic' }, // $set_once — only if absent
);

Traits live on the person and can change; events are frozen at capture time. If you need a value to be trustworthy (billing plan, revenue), send it server-side with a secret key or as signed traits — anything a browser sends can be forged by the browser’s owner.

kilden.reset();

Rotates the anonymous id, clears the identity token and super properties. Skip this and the next person to log in on that browser gets linked to the previous user’s anonymous trail.

  • Two known ids never merge automatically. If an identified user somehow gets identified as a different known id, Kilden refuses the merge (it’s almost always an instrumentation bug), logs it, and attributes the event to the user id’s person. The web SDK deliberately has no alias()identify covers the browser flow completely; $alias exists in the pipeline for server SDKs, where linking two known ids is legitimate.
  • Distinct-id cap per person (100 by default) prevents runaway id accumulation (“person bloat”); past the cap, events still attribute but new mappings aren’t created.
  • With identity verification in enforce mode, an unverified identify from a browser cannot create or modify identity mappings at all.