Skip to main content
When a user talks to your agent, you pass an end-user id - userId in the widget, or end_user_id (or its user_id alias) in session metadata. That id is the single most consequential thing you set, because: One id is one durable instance. Everything the agent accumulates for that id
  • conversation history and any memory it builds up - is keyed on it. Reach it again with the same id and the agent picks up where it left off. Reach it with a different id and the agent starts fresh, remembering nothing.
So the id is the memory, privacy, and persistence boundary all at once. Choosing what it maps to is a design decision.

The mental model: one template, many instances

You don’t deploy “Gmail” - you deploy a template, and every user gets their own inbox at their own address. An agent works the same way:
  • Map the id to a single value for your whole team → one shared instance the whole team talks to, with one shared memory. A shared agent. (To share one workspace while still attributing each person for usage and caps, name a stable instance instead - see Sessions & participants.)
  • Map the id to your user’s id → each user gets their own instance with its own private, accumulating memory. A personalized agent.
Same agent, same machinery. The only thing that changes is what you key on.

Three rules

1

Grain equals privacy - there is no sub-key

Everyone who shares an id shares one memory. If two people must not see each other’s conversations, give each their own id. You cannot get per-person privacy out of a coarse id - the agent has nothing finer to separate on. For a household or team that should share context, share the id deliberately.
2

Use a stable, durable key

The id must stay the same for as long as you want the memory to live. Derive it from something permanent (your internal user id), never from something that changes between visits - a session token, a rotating value, an email that can change. If the id drifts, the old instance is orphaned and the user silently starts over.
3

Treat it as a tenant boundary

The id is a security boundary, not a display label. Make it stable, opaque, and non-guessable, and keep your id spaces from colliding (a team id that happens to equal another user’s id would share their instance). For ids your own server can vouch for, use verified identity so the agent can safely act on per-user data.

Throwaway instances

Sometimes you want no memory at all - a public FAQ bot, or a shared kiosk where the next person must not see the last conversation. Pass the reserved id ephemeral:
karta("identify", { userId: "ephemeral" });
Each ephemeral session becomes its own isolated, single-use instance - nothing carries across sessions, and no two ephemeral users ever share state. It behaves like any other instance for the duration of the session; it just isn’t kept or reused afterward.
ephemeral is different from passing nothing. An anonymous visitor still gets a per-browser id so a reload resumes the same conversation; ephemeral guarantees a fresh, isolated instance every time.

Checking your ids are stable

If you intend instances to be reused but your key is unstable, returning users quietly lose their memory - and nothing errors. Your agent’s Overview surfaces an instance utility reading (how often instances are seen more than once) to help you catch that: if you expect reuse but it shows instances are almost always one-shot, your id is probably drifting between visits (rule 2).

Next

Widget identity

Anonymous, soft, and verified ids - and how to sign a verified id.

Sessions API

Passing end_user_id in session metadata directly.