Conversations and analytics
This chapter explains what LiteBot stores about every chat or voice session, how to read it back through the dashboard and the HTTP API, and how long it is kept. Read it when you need a transcript, want to see why a bot answered the way it did, or want cost and usage figures for a period. The cost arithmetic itself is in Cost and performance.
LiteBot writes five kinds of record to MongoDB:
| Collection | One document per | Written by |
|---|---|---|
conversations |
Session | Conversation manager (chat) and the voice handler |
request_traces |
Chat turn, or whole voice call | Chat engine and voice handler, when tracing is on |
request_analytics |
LLM call | Analytics manager, in batches |
session_analytics |
Session | Analytics manager, every 30 s while active and at session end |
leads, support_tickets |
Lead or ticket | The bundled lead and ticket tools |
All of these except leads and support_tickets carry a tenantId, taken from the bot's tenant when the row is written. Tenant users only ever see rows of their own tenant; the global admin sees all.
The conversations collection
A session starts on the first message for a new session id and gets an id of the form sess_<random> unless the caller supplies one. The document _id is the session id.
| Field | Meaning |
|---|---|
sessionId |
Same as _id. |
botId |
Bot currently serving the session. Changes if the intent router switches bots. |
tenantId |
Tenant of the bot at creation. |
userId |
Caller identity sent with the request (for a WhatsApp or phone channel this is often the phone number). null when none was sent. |
messages[] |
The transcript. See below. |
context |
Session variables: values passed in the chat request's context, values tools save, and flags such as call_ended on voice calls. |
metadata |
Free-form metadata passed when the session was created. |
status |
active or ended. |
createdAt, lastActivity |
Start time and time of the last message. |
endedAt |
When the session was closed. |
endedBy |
idle-sweep when the session was closed by the idle sweep rather than by a hang-up or DELETE. |
botSwitches[] |
{ timestamp, from, to } for every bot switch. |
Each entry in messages[] holds role (user, assistant, and so on), content, timestamp and an id. Assistant messages also hold toolCalls (what the model asked for) and toolResults (what each tool returned, with toolName, success and the result). toolResults is the most reliable record of what a tool did, because it is kept for as long as the conversation is.
Memory per session is capped at MAX_SESSION_MESSAGES (default 200); older messages are dropped from the stored transcript once the cap is reached. Only the last LLM_HISTORY_MAX_MESSAGES (default 40) are sent to the model.
How a session ends
- A hang-up tool,
DELETE /api/chat/session/:id, or the end of a voice call setsstatus: endedandendedAt. - Sessions idle longer than
SESSION_IDLE_TIMEOUT_MS(default 30 minutes) are closed by a sweep that runs everySESSION_CLEANUP_INTERVAL_MS(default 15 minutes). The sweep also closes staleactiverows in MongoDB left behind by a restart, settingendedAtto the row's ownlastActivityandendedBy: idle-sweep.
See Session-end hooks for what runs when a session ends.
Reading conversations
All /api/conversations routes need a JWT or API key with the conversations read permission (Users, roles and tenants).
| Method and path | What it returns |
|---|---|
GET /api/conversations |
Paged list. Query: page, limit (1–100, default 20), botId, userId, status, startDate, endDate, search (matches session id, user id or bot id), sortBy, sortOrder. |
GET /api/conversations/stats/summary |
Summary counts for the same filters. |
GET /api/conversations/:sessionId |
One conversation with messages, context and an analytics block from session_analytics. |
GET /api/conversations/:sessionId/traces |
Execution traces for the session. See Request traces. |
GET /api/conversations/export/:sessionId?format=json |
Download. json (default) is the full document including toolResults; csv is timestamp, role and content only. |
DELETE /api/conversations/:sessionId |
Deletes the conversation and its session_analytics and request_analytics rows. |
POST /api/conversations/bulk-delete |
Same for up to 100 ids: {"sessionIds": ["..."]}. |
curl -s http://127.0.0.1:3345/api/conversations/sess_abc123 \
-H "Authorization: Bearer <token>"
The single-conversation view returns each message's role, content, timestamp and toolCalls, but not toolResults. Use the JSON export when you need tool results.
Deletes do not remove request_traces rows; those expire on their own (Retention).
Request traces
A trace is the step-by-step record of how a reply was produced. Tracing is on unless ENABLE_REQUEST_TRACING=false.
- Chat: one
request_tracesdocument per turn. - Voice: one document per call, written when the call ends, with steps for every turn.
Each document holds sessionId, botId, tenantId, userId, createdAt and a trace array. Step types:
step |
Fields |
|---|---|
llm_call |
iteration, provider, model, inputTokens, outputTokens, duration (ms), toolCallsRequested. Voice turns show provider gemini-live. |
tool_execution |
toolName, parameters, result (first 500 characters, or the error), duration, success, iteration. |
llm_followup |
Each extra model round-trip after tools ran: iteration, duration, tokenUsage, hasMoreToolCalls. |
flow_transition |
Node moves in a visual-flow bot (Visual flows). |
A turn with several llm_followup steps took several model round-trips; that is the first place to look for slow or costly turns.
Traces exist only for sessions handled after tracing was added to your build (chat first, voice later). For older sessions, read toolResults from the conversation instead.
Session and request analytics
request_analytics
One row per LLM call. Rows are queued and written with one insert every ANALYTICS_BATCH_INTERVAL_MS (default 2000) or when ANALYTICS_BATCH_SIZE (default 50) rows are waiting, and at session end.
| Field | Meaning |
|---|---|
sessionId, botId, tenantId |
Owner. |
provider, model |
Provider and model that actually served the call (after any failover). |
usage |
Token counts from the provider: promptTokens, completionTokens, totalTokens, and cachedTokens where reported. |
cost, costData |
Cost in USD and its breakdown (Cost and performance). |
responseTime |
Milliseconds for this call. Missing or 0 when it could not be timed (some voice turns). |
toolCalls |
Tool calls requested in this call. |
success, error |
Outcome. A failed turn records success: false and the error text. |
timestamp, createdAt |
When it happened and when it was written. |
session_analytics
One row per session, replaced in place while the session runs (at most every 30 seconds) and at session end.
| Field | Meaning |
|---|---|
sessionId, botId, tenantId, userId |
Owner. |
channel |
voice for Gemini Live calls. Absent on chat sessions; reports count a missing channel as chat. |
startTime, endTime, duration |
Duration is in seconds. |
messageCount, toolCallCount, errors, successRate |
Turn counts and outcome. |
totalCost, totalTokens, totalInputTokens, totalOutputTokens |
Session totals. Cost is USD. |
averageResponseTime |
Mean of the timed LLM calls, in ms. |
averageCostPerMessage, averageTokensPerMessage |
Totals divided by messageCount. |
provider, model |
Provider and model of the last call. |
Analytics API
All /api/analytics routes need authentication and are scoped to your tenant. Ranges are ?days=N (default 7) or ?startDate=<ISO>&endDate=<ISO>. Where a route takes tz, it buckets days and hours in that IANA zone (default ANALYTICS_TZ, Asia/Kolkata).
| Path | Source | What it gives |
|---|---|---|
/api/analytics/report |
session_analytics |
Totals, voice and chat split, per-bot rows sorted by cost, and a daily series. Takes tz. Cached 60 s. |
/api/analytics/evidence?botId= |
Several | Evidence bundle download. See below. |
/api/analytics/performance |
session_analytics |
System response times with p50, p95 and p99 of per-session averages. |
/api/analytics/performance/:botId |
session_analytics |
The same for one bot. |
/api/analytics/response-timeline |
request_analytics |
Average, maximum and p95 latency per hour (ranges of 2 days or less) or per day. p95 needs MongoDB 7 or later; older servers return null. Takes tz. |
/api/analytics/tool-performance |
request_traces |
Per-tool call count, duration and failures. limit (default 12, max 50), botId. Says whether tracing is on. |
/api/analytics/slowest-operations |
session_analytics |
The slowest bots, split into estimated components (see the note below). limit (default 10, max 100). |
/api/analytics/dashboard |
Fan-out | The datasets the dashboard Analytics page loads, in one call. |
The bot routes add GET /api/bots/analytics/summary, /api/bots/analytics/:botId/detailed, /api/bots/analytics/trending, /api/bots/analytics/health and /api/bots/analytics/realtime (live in-memory sessions); GET /api/chat/stats and GET /api/chat/analytics give totals with provider and model breakdowns.
The LLM, database, tools and formatting split shown by the performance routes is an estimate (70/10/15/5 per cent of the average), not a measurement. For measured timings use traces or the metrics block of a chat reply (Cost and performance).
Evidence bundle
GET /api/analytics/evidence?botId=<id>&days=7 streams a zip named evidence-<botId>-<from>-to-<to>.zip:
| File | Contents |
|---|---|
README.md |
What each file holds and suggested analysis questions. |
bot.json |
The bot's current configuration: prompt, model, tools, rules. |
conversations.jsonl |
One conversation per line, selected by createdAt. |
session_analytics.jsonl |
One session summary per line, selected by startTime. |
request_traces.jsonl |
One trace document per line. |
summary.json |
Period, counts, cost, token, message and tool-call totals, and truncated. |
Each file holds at most 2,000 documents, oldest first; summary.json says whether that cap was hit, so shorten the range if it was. Values under keys ending in token, password, secret, credential, authorization or api_key are replaced with [REDACTED], including inside stringified tool results.
curl -s -o evidence.zip -H "Authorization: Bearer <token>" \
"http://127.0.0.1:3345/api/analytics/evidence?botId=<bot-id>&days=7"
Dashboard pages
- Conversations lists sessions with the filters above. Opening one shows the transcript and a trace viewer that draws each
request_tracesstep. - Analytics has the tabs Sessions, Performance, Usage, Insights, Advanced and Reports, with a range of 24 hours, 7, 30 or 90 days.
- Reports (inside Analytics) shows the
/api/analytics/reportfigures and has an Evidence button per bot that downloads the bundle.
See Dashboard.
Leads and support tickets
There are no /api/leads or /api/tickets routes. These collections are filled by tools:
| Tool | Collection | What it writes |
|---|---|---|
createLead |
leads |
The parameters given, plus source (default chat), score: 0, status: new, sessionId, botId, timestamps. |
qualifyLead |
leads |
Updates score and status of an existing lead. |
createTicket |
support_tickets |
ticketNumber (TKT-...), title, description, category, priority, status: open, customer name and email, sessionId, botId. |
updateTicketStatus |
support_tickets |
New status and resolution. |
leads has a unique sparse index on email, so a second lead with the same email fails. These rows carry no tenantId. Read them with your own MongoDB tooling, or write your own tool that sends them to your CRM (Tools). GET /health/ready reports not ready until both collections exist; LiteBot creates them with their indexes at start-up.
Retention
| Data | Kept |
|---|---|
conversations |
Until you delete them. No expiry. |
session_analytics, request_analytics |
Until you delete them, or delete the conversation through the API. |
request_traces |
30 days, through a TTL index on createdAt. LiteBot creates that index the first time anyone opens a trace (GET /api/conversations/:sessionId/traces); until then traces are not expired. |
leads, support_tickets |
Until you delete them. |
To enforce a retention period on the other collections, add your own TTL index in MongoDB or run a scheduled delete. Conversations contain whatever callers said, so treat them as personal data (Security).
Where to go next
- What each figure costs and how to make replies faster: Cost and performance
- Tracing, batching and timezone settings: Environment reference, part 2
- Every endpoint in one place: HTTP API