# Sessions

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                          | —                                          | ✅                        |

{% hint style="warning" %}
Both `$conversation` and `$context` are **scoped to the current session**. Neither variable carries memory from previous sessions of the same user. If you need long-term memory across sessions, persist the relevant facts to user-profile variables explicitly and re-inject them into prompts.
{% endhint %}

### 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](/getting-started/workspace/variables/system-variables.md) 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**

```html
<script defer src="https://platform.indigo.ai/widget.js?token=YOUR_TOKEN&v=3&uid=crm-12345"></script>
```

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

```html
<script>
  window.localStorage.setItem('indigo-ai-widget-uid', 'crm-12345');
</script>
<script defer src="https://platform.indigo.ai/widget.js?token=YOUR_TOKEN&v=3"></script>
```

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](/tech-deep-dives/web-chat-integration-and-customization-on-your-website/web-chat-integration-dynamic-interaction-and-data-exchange-with-your-website.md) 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](/build-your-ai-agents/configure-and-install-the-web-chat.md).

### 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](/getting-started/communication-channels/whatsapp.md).

### 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](/getting-started/communication-channels/voice.md).

### Custom channels

If you integrate a custom channel via the [Chat API](/tech-deep-dives/integrating-custom-channels-with-the-chat-api.md), 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](/integrating-with-our-platform-api/non-conversational-triggers.md).
* **GraphQL queries and analytics endpoints** — read-only; they do not affect sessions. See the [GraphQL API overview](/integrating-with-our-platform-api.md) and [Analytics REST API](/integrating-with-our-platform-api/analytics-api.md).

## 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.

## Related pages

* [System Variables](/getting-started/workspace/variables/system-variables.md) — full reference for `$user_id`, `$user_ref`, `$conversation`, `$context`.
* [Configure & Install the Web Chat](/build-your-ai-agents/configure-and-install-the-web-chat.md) — Web Chat session persistence settings.
* [Non-Conversational Triggers](/integrating-with-our-platform-api/non-conversational-triggers.md) — how to start sessions programmatically from external systems.
* [Web Chat Integration: Dynamic Interaction and Data Exchange](/tech-deep-dives/web-chat-integration-and-customization-on-your-website/web-chat-integration-dynamic-interaction-and-data-exchange-with-your-website.md) — passing `user_ref` and other context from your site.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://guide.indigo.ai/integrating-with-our-platform-api/sessions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
