
Setting up session tracking
To use the Sessions view, pass asessionId when initializing your trace context. The session ID should be stable for the duration of a conversation — typically a UUID you generate when the conversation starts.
- TypeScript
- Python
sessionId are linked together in the Sessions view, regardless of which trace they belong to.
The sessions list
The Sessions page shows a paginated table of all sessions in your project:
Sort by Cost to find your most expensive sessions. Sort by Turns to find conversations with the highest round-trip count — a candidate for prompt optimization.
Filtering sessions
Use the filter bar to narrow the list by:- Date range — see sessions from a specific period
- User ID — view all sessions for a specific user
- Status — filter to sessions with errors
- Minimum turns — find longer conversations
The sessions list is time-bounded: it defaults to the last 7 days even before you touch any filter, so a project with a long history doesn’t run an unbounded scan on every page load. Use the date-range picker in the filter bar to widen the window (for example, the last 24 hours or 30 days) or pick an explicit start and end date. A session with no activity inside the selected window won’t appear in the list — widen the range before assuming a session doesn’t exist.
Session detail
Click any session row to open its detail view. The detail view shows:Conversation timeline
A sequential list of every LLM call in the session, in chronological order. Each entry shows the model, latency, token count, and cost for that call. Click any entry to open the full trace flame graph.Session metrics
- Total cost — cumulative spend across all calls
- Total tokens — combined input and output tokens
- Average latency per turn — mean response time across all calls
- Error count — number of calls that ended in an error state
User attribution
If the session was associated with auserId, the user’s full session history is available from a link at the top of the detail view. This lets you see all sessions for a user in one place — useful for investigating a user complaint or analysing high-value customers.
Conversation-level eval score
If any session-scope evaluator has judged this conversation, a badge reading Conversation: Pass/Fail · N evaluators appears on the session detail page. This is a distinct signal from the per-trace evaluator scores shown on individual calls in the conversation timeline — one score judges a single LLM call, the other judges the whole conversation. See Session-level evaluation below for how to configure it.Session-level evaluation
Every evaluator described on the Evaluations page normally scores one trace at a time. A session-scope evaluator instead judges an entire conversation — every trace sharing asessionId, folded into one ordered transcript — so you can catch quality problems that only show up across multiple turns (the assistant contradicting itself, losing context, or drifting off-topic over a long back-and-forth) rather than in any single call.
What it is
A session-scope evaluator runs the same LLM-as-judge pipeline as a regular evaluator, but the “trace” it’s handed is the full transcript of the conversation instead of one prompt/completion pair. The resulting score is written with the conversation’ssessionId attached and no traceId/spanId — it’s a property of the conversation, not of any one call in it. Because a conversation can span multiple models across turns, a session-level score also has no single “model” or “provider” attached to it.
Configuring a session-scope evaluator
Session scope is a property of the evaluator template, set alongside its other configuration (rubric, score type, threshold):scope: "session" instead of the default "trace". The Create Custom Template dialog on the Evaluations page doesn’t yet expose a scope toggle, so set it via the API when creating or updating a template:
A session-scope evaluator is excluded from the normal per-trace auto-evaluation path entirely — it never scores an individual trace, only whole sessions once they’re detected as complete (see below).
How “session complete” is detected
There’s no explicit “close this session” call in the SDK — a conversation can always receive one more turn. Instead, Zespan detects a session as complete by quiescence: a session is considered done once it has gone 30 minutes (default) with no new activity. This is configurable via theSESSION_QUIET_MINUTES environment variable.
A background scan checks for newly-quiet sessions on a 10-minute cron tick, and only looks at projects that have at least one enabled session-scope evaluator — most projects have none, so this stays cheap. Once a session is found quiet, it’s queued for session-level evaluation; the judge then runs against the full transcript and the resulting scores appear on the session detail page shortly after.
Cost attribution by session
In addition to per-model cost breakdown, the Sessions view helps answer questions like:- “Which types of conversations cost the most?”
- “Are there sessions where users are burning through tokens disproportionately?”
- “What is my average cost per conversation?”
Plan requirements
Session tracking is available on all plans. The Sessions page is populated automatically as long as your SDK passessessionId in its trace context. No additional configuration is required.
Data retention for session data follows your plan’s retention window — 14 days on Free, 30 days on Solo, 90 days on Pro, 180 days on Team, 1 year on Scale. Sessions and traces older than the window are excluded from every response, so widening a date-range filter past your retention window returns nothing extra.
