# The session lifecycle

> boot, identify, update, shutdown, and destroy — the full lifecycle of a chat session.

Product: Clad Widget SDK
Source: https://docs.useclad.ai/widget/session-lifecycle

---

A Support Chat session moves through a predictable set of phases. After the
script loads, it goes from **`not_initialized`** to **`loading`** and then
**`ready`**. Calling [`boot()`](#bootoptions) transitions it through
**`booting`** into either an **`anonymous`** or an **`authenticated`** session,
depending on whether you supplied a user.

Calling [`shutdown()`](#shutdownoptions) ends the session (**`shutdown`**), and
[`destroy()`](#destroy) tears the widget down entirely (**`destroyed`**).

```
not_initialized → loading → ready → booting → anonymous | authenticated
        → shutdown → destroyed
```

You can read the current phase at any time via `chat.state` — it reflects the
**session / identity** lifecycle above.

> **Live connection status is reported separately, as an event — not via
> `chat.state`.** Transient realtime drops and recoveries surface through the
> [`connection:state`](#events) event (`connecting` / `connected` /
> `reconnecting` / `disconnected`), and are handled for you automatically.
> Subscribe to that event if you want to reflect online/offline status in your
> own UI; `chat.state` itself does not change for connection blips.

### `boot(options?)`

Creates or resumes a session. With no `user`, the session is **anonymous**.
With a `user`, you should supply a `tokenProvider` (see
[Identity verification](#identity-verification-jwt)).

Anonymous visitors appear to your support team under a stable, friendly
pseudonym (e.g. **"Amber Falcon"**) instead of a generic "Website visitor"
label, so agents can tell concurrent chats apart. When the visitor later
identifies (or submits an email through a ticket form), their real name and
email replace the pseudonym on the same contact.

```ts
await chat.boot({
  user: {
    id: currentUser.id,
    email: currentUser.email,
    name: currentUser.name,
  },
  company: {
    id: currentOrg.id,
    name: currentOrg.name,
    plan: currentOrg.plan,
  },
  tokenProvider: () =>
    fetch("/api/support-chat-token").then((r) => r.text()),
});
```

- Idempotent for the same identity.
- Calling `boot()` with a **different** identified user throws — call
  [`shutdown()`](#shutdownoptions) first, or use [`identify()`](#identifyoptions).

### `identify(options)`

Upgrades an anonymous session to an authenticated user (and merges anonymous
history when possible). See [Anonymous → authenticated upgrade](#anonymous--authenticated-upgrade).

### `update(options)`

Refreshes the **ephemeral page context** attached to future conversations and
messages (it behaves like [`setContext`](#context-tags--custom-fields)). Safe to
call on SPA route changes.

```ts
await chat.update({
  context: { currentPage: "billing", accountHealth: "red" },
});
```

> **Note:** `update()` currently applies only `context`. To change the
> **signed‑in user**, call [`identify()`](#identifyoptions) with a fresh token —
> passing `user` / `company` to `update()` does **not** propagate trait changes
> today.

### `shutdown(options?)`

Call on **logout**. Clears user‑specific state and closes the realtime
connection. Pass `{ clearStorage: true }` to also remove anonymous/session
identifiers — important on shared computers so a previous user's conversations
don't linger.

```ts
await chat.shutdown({ clearStorage: true });
```

### `destroy()`

Removes the iframe, listeners, and timers. Persistent storage is left intact
unless you previously called `shutdown({ clearStorage: true })`.

```ts
await chat.destroy();
```
