A session is one conversation between your app and a user. A user is one person across all their conversations. The dashboard builds both by grouping trajectories that share aDocumentation Index
Fetch the complete documentation index at: https://docs.bentolabs.ai/llms.txt
Use this file to discover all available pages before exploring further.
convo_id or a user_id. There is no separate Session or User object: you pass strings, the grouping happens server-side.
Conversations
Pass the sameconvo_id to every bento.begin or bento.track_ai call that belongs in one conversation.
convo_id becomes the OTel attribute gen_ai.conversation.id and lands in the traces.session_id column on our side. The attribute name and the column name don’t match for historical reasons. Use the kwarg.Choosing a convo_id
Stable
Survives between requests in the same conversation.
Unique
Two different conversations never share an ID.
Opaque
UUID, slug, or hash. No PII.
| Your app has | Use as convo_id |
|---|---|
| A chat thread row | The thread’s primary key (stringified) |
| A web session | The session UUID |
| A Slack/Discord channel | channel_id:thread_ts |
| Nothing yet | Generate one with uuid4() at conversation start, store it client-side |
Users
user_id is a pass-through string. We do not store profile data: no email, no name, no traits.
gen_ai.user.id (OTel) and traces.user_id (column). You can filter the trace list by user_id, count distinct users, and pivot any metric by user.
Choosing a user_id
- Use your internal stable user ID (users-table primary key, auth provider
subclaim, etc.) - One ID per real human, across devices
- Treat it like a foreign key. No PII.
How the dashboard groups
| You set | The dashboard shows |
|---|---|
Same convo_id on N spans | One session with N turns |
Same user_id across sessions | All those sessions under one user view |
Same convo_id, different user_id | One session. The latest user_id wins for display. Avoid this. |
Different convo_id, same user_id | N independent sessions under one user |
Grouping happens at query time, not ingest time. There’s no migration to “create a session”. Existing trajectories start grouping the moment you start passing the right ID.
Setting IDs on a trajectory
A trajectory carriesconvo_id and user_id on its own span. Child spans don’t inherit them; pass the IDs to each track_ai call too so per-span filters work.
Verbose, but unambiguous. Inheritance from parent to child is on the roadmap.
What sessions are not
Not a billing or quota concept
Not a billing or quota concept
Sessions are a dashboard grouping. You’re billed on span volume.
Not bounded in time
Not bounded in time
A session has no TTL. Keep passing the same
convo_id for a year and the dashboard will show one very long session. Rotate IDs when a conversation logically ends.Not user-scoped automatically
Not user-scoped automatically
Two different
user_ids sharing a convo_id look like one session with mixed users. Rotate convo_id whenever the user changes.