clock-rotate-leftSessions

How indigo.ai groups messages into sessions across the Web Chat, WhatsApp, Voice, and the REST API — and how to keep user identity stable across them.

A session is the unit of conversation indigo.ai uses to group messages, persist short-term context, and compute analytics. Every interaction with one of your AI Agents — through the Web Chat widget, a messaging channel, or the REST API — happens inside a session.

Understanding how sessions are opened, closed, and stitched back to the same end user is essential when:

  • Embedding the Web Chat on your website and deciding whether to resume previous chats.

  • Connecting a CRM to indigo.ai and matching conversations to a known customer.

  • Building automations that fire non-conversational triggers and need to attribute messages to the right user.

  • Reading analytics, where some metrics are session-scoped (chats, CSAT, AI quality) and others are user-scoped (returning users).

Sessions vs. conversations

The platform distinguishes two related concepts:

Term
Scope
Bound to

Session (a "chat")

The current uninterrupted exchange.

One chat record.

Conversation

The full history of every session the same end user has ever had on this Workspace.

The persistent $user_ref.

Each new session creates a new chat record. All sessions of the same $user_ref belong to one conversation.

When a session ends

A session ends as soon as one of the following happens:

  • Inactivity timeout — no new messages for a configurable period (default 10 minutes). The next inbound message from the same user starts a new session.

  • CSAT submitted — once the user submits a CSAT score for the current chat, it is closed and any new message starts a fresh session.

  • Explicit reset — the user clicks "Start a new chat" in the Web Chat, or the conversation flow triggers an init event.

The inactivity timeout is set per Workspace and applies uniformly to every channel.

What resets between sessions

Behaviour
Resets at session boundary
Persists across sessions

Captured variables (slot values, in-flow state)

Chat-level analytics (CSAT, AI quality)

$conversation and $context content

✅ — both are scoped to the current session

$user_id and $user_ref (user identity)

User-profile variables

circle-exclamation

Picking between $conversation, $context, and $context_N

All three variables expose the current session to a Prompt Block, in different shapes:

  • $conversation — JSON list of the last 100 user turns of the current session, with their bot replies interleaved. Ordered chronologically. Use it when you want a structured short-term memory for an LLM.

  • $context — full text of the current session, with role-prefixed lines (User: ..., AI Chatbot: ...). Use it when you want a free-text rendering for prompt templating.

  • $context_1$context_5 — the last 1 to 5 user/agent pairs only. Useful when you need a tight context window or a lightweight short-memory.

See System Variables for the full list.

User identity: $user_id vs. $user_ref

Every session is tied to two identifiers, both of which are persistent across sessions for the same end user:

  • $user_ref — the external identifier provided by the integration (Web Chat cookie/local-storage value, WhatsApp phone number, Voice caller number, or a value you set explicitly). This is the identifier you control from outside the platform.

  • $user_id — the internal numeric identifier indigo.ai assigns the first time a $user_ref interacts with the Workspace. Used internally to link that user's sessions, messages, and profile variables.

Once a $user_ref exists, every subsequent session reuses the same $user_id. Both identifiers are stable over the lifetime of that user — they do not rotate per session.

Setting $user_ref from your site

For authenticated experiences, override the default Web Chat $user_ref (a randomly generated client-side value) with the user's identifier from your CRM. The platform supports two options:

Option 1 — uid query parameter on the widget script

Option 2 — local-storage value set before the widget loads

Both options collapse the user's chats from any device or browser into a single conversation. See Web Chat Integration: Dynamic Interaction and Data Exchange for the full integration recipe.

Sessions per channel

Each communication channel decides when a session starts, based on the protocol it speaks. After that, the same Workspace-level inactivity timeout applies everywhere.

Web Chat

  • A session is created the first time a visitor sends a message through the widget.

  • A $user_ref is stored in the visitor's browser (local storage), so reloading the page or navigating to another page on your site continues the same session as long as the inactivity timeout is not exceeded.

  • After the timeout, the next message starts a new session under the same $user_ref.

For configuration and customization options, see Configure & Install the Web Chat.

WhatsApp

  • The customer's WhatsApp ID (phone number in international format) is used as $user_ref. Every message from the same number lands in the same conversation.

  • Session boundaries follow the Workspace inactivity timeout — not the WhatsApp 24-hour customer service window. A customer who replies 30 minutes later starts a new session, even though Meta still considers the 24-hour business window open.

  • Outbound-initiated conversations (template messages) follow Meta's standard rules independently of the platform's session model.

See WhatsApp.

Voice

  • A session corresponds to a single phone call. It starts when the call connects and ends when one party hangs up (Hang up Block, Transfer Call Block, or hang-up from the user).

  • The caller's phone number (or the callee's, for outbound calls) is used as $user_ref, so calls from the same number on different days are stitched into one conversation. Each call is still a separate session inside that conversation.

See Voice.

Custom channels

If you integrate a custom channel via the Chat API, your integration is responsible for declaring the user_ref of every inbound message. As a rule of thumb:

  • Synchronous channels (live chat, voice): use a stable identifier (account ID, phone number) so that returning users keep their conversation.

  • Asynchronous channels (email, social DMs): use the channel-native sender ID and let the inactivity timeout handle session boundaries.

Sessions and the REST API

REST endpoints behave differently depending on whether they create messages or just read data:

  • Trigger endpoints (POST /rest/trigger/sync/:project_token, POST /rest/trigger/async/:project_token) — each call delivers a message attributed to the user_ref you pass in the request body. If a session for that user_ref is already active (within the inactivity timeout), the message is appended to it; otherwise, a new session starts. See Non-Conversational Triggers.

  • GraphQL queries and analytics endpoints — read-only; they do not affect sessions. See the GraphQL API overview and Analytics REST API.

Best practices

  • Set $user_ref from your CRM whenever the user is authenticated. Anonymous-only deployments lose the ability to recognize returning users across devices.

  • Don't rely on $conversation or $context for long-term memory — both reset at every new session. If you need facts about the user to survive a session boundary, persist them as user-profile variables and re-inject them in your prompts.

  • Tune the inactivity timeout to your use case: a stale session resumed days later confuses both the user and the agent. The default of 10 minutes is a sensible baseline; raise it for low-frequency support flows, lower it for transactional ones.

  • Use a stable user_ref on REST triggers when the trigger represents activity from a known customer. Pass a fresh value to start a clean session.

Last updated

Was this helpful?