> ## Documentation Index
> Fetch the complete documentation index at: https://docs.base44.com/llms.txt
> Use this file to discover all available pages before exploring further.

# chat

***

## Overview

Chat module for following the AI chat of your users' apps in real time. Call
[`init()`](#init) to create a session and start following.

A session holds one socket and up to eight app subscriptions. For each app, you get a
snapshot of the app's chat, then every change as it happens:

* New and updated chat messages, with the AI's tool calls.
* The AI's status, from processing to ready.
* Preview reloads and navigation, the prompt queue, and generated images.

## Methods

### init()

> **init**(`options`): `ChatSession`

Creates a session without connecting it. A [session](#session-methods) is one socket plus the
app subscriptions that share it.

Pass a `getSession()` callback in the options. The client calls it to get a
[socket session](https://docs.base44.com/developers/references/apps-api/sections/socket-sessions.md), which your server
opens with [Create socket session](https://docs.base44.com/api-reference/create-socket-session.md). Each session is independent and gets its own socket session.

Call [`connect()`](#connect) on the returned session to open the socket.

#### Parameters

**options** `ChatInitOptions` *required*

Session options.

> **Properties**
>
> **getSession** `() =\> Promise\<SocketSession\>` *required*
>
> Returns a new socket session from your server.
>
> Return the `session_token`, `socket_url`, and `socket_path` of a
> [Create socket session](https://docs.base44.com/api-reference/create-socket-session.md) response as a
> [`SocketSession`](#socketsession), and keep its `session_id` on your server. Return a new
> session on every call. The client calls
> `getSession()` on the first connect(), and again only when
> the session expires or Base44 rejects its token. If a new session has a different `socket_url`
> or `socket_path`, the client moves to it and rejoins every active subscription.
>
> **onError** `(error: PlatformSocketError) =\> void` *required*
>
> Called on errors that affect the whole session, such as a failed connection or an ended session.
> Errors for one app go to that subscription's `onError()` instead. The
> [error codes](#errors)
> say what each error means.

#### Returns

[`ChatSession`](#session-methods)

The new session.

#### Example

```typescript Create and connect a session theme={null}
const chat = client.chat.init({
  async getSession() {
    const response = await fetch('/api/chat-socket-session', { method: 'POST' });
    return response.json();
  },
  onError(error) {
    console.error('Live updates error', error.code);
  },
});
await chat.connect();
```

## Session methods

A session is one socket plus the app subscriptions that share it, and it reconnects automatically
if the connection drops. Use the methods below to connect the socket, follow apps, and close the
session.

### connect()

> **connect**(): `Promise`\<`void`>

Connects the session's socket.

The first call gets a socket session from [`getSession()`](#init). If the session has expired
or Base44 rejects its token, the client calls `getSession()` once more for a new one.
Concurrent calls share one attempt.

The promise resolves once the socket connects, before any snapshot arrives. If the connection
drops, the session retries five times and rejoins every active subscription, each with a fresh
snapshot.

Call `connect()` again after a failure or a `session_replaced` error.

#### Returns

`Promise<void>`

A promise that resolves when the socket connects.

#### Throws

The promise rejects with a `PlatformSocketError` whose code is `connection_denied`, `connection_failed`, or `session_unavailable` when the session can't connect, or `client_closed` when the session is closed first.

#### Example

```typescript Connect and handle failure theme={null}
try {
  await chat.connect();
} catch (error) {
  console.error('Could not connect', error.code);
}
```

***

### subscribe()

> **subscribe**(`appId`, `options`): `PlatformSubscription`

Subscribes to an app's chat.

You can subscribe before or after connecting. A session has one subscription per app, up to
eight in total. A session can only follow apps your server gave the session access to, either
in [Create socket session](https://docs.base44.com/api-reference/create-socket-session.md) or later with
[Add app to session](https://docs.base44.com/api-reference/add-app-to-session.md). Subscribing to any other app fails
with `access_denied`. The subscription first receives a snapshot of the app, then each live
event.

Pass `onSnapshot()`, `onEvent()`, and `onError()` callbacks in the options to receive the app's
snapshot, live events, and errors.

Callbacks for an app run one at a time, in order. If a callback returns a promise, the session
waits for it before calling the next callback for that app. Each app has its own queue, so a
slow callback for one app doesn't delay the others. If more than 1,000 snapshots and events are
waiting for an app's callbacks, the subscription ends with `delivery_overflow`.

#### Parameters

> **Properties**
>
> **appId** `string` *required*
>
> ID of the app to follow, 24 lowercase hexadecimal characters.
>
> **options** `SubscriptionOptions` *required*
>
> Callbacks for the app's snapshots, events, and errors.
>
> > **Properties**
> >
> > **onSnapshot** `(snapshot: PlatformSnapshot) =\> void | Promise\<void\>` *required*
> >
> > Called with the app's current state, a [`PlatformSnapshot`](#platformsnapshot). Replace everything you hold for the app with the snapshot.
> >
> > The snapshot arrives when you subscribe, after every reconnect, and after the main conversation
> > is rewritten by an undo, restore, or sync. Live events follow it. A snapshot holds only the last
> > 50 messages, so load older history again if you show it.
> >
> > **onEvent** `(event: PlatformEvent) =\> void | Promise\<void\>` *required*
> >
> > Called with each live event, a [`PlatformEvent`](#platformevent). Events for an app arrive one at a time, in order. If the callback
> > throws or rejects, the subscription ends with `handler_failed`.
> >
> > New event types can be added at any time, so ignore the types you don't handle. An event newer
> > than this SDK arrives with `type: "unknown"`, and its event name is in `name`.
> > [Socket messages](https://docs.base44.com/developers/references/apps-api/sections/socket-messages.md) lists every event
> > and its payload.
> >
> > **onError** `(error: PlatformSocketError) =\> void` *required*
> >
> > Called on errors for this app. Every error ends the subscription except `snapshot_unavailable`.
> > The [error codes](#errors)
> > say what each error means.

#### Returns

`PlatformSubscription`

A subscription to an app's chat.

The subscription.

> **Properties**
>
> **appId** `string` *required*
>
> ID of the app.
>
> **active** `boolean` *required*
>
> Whether the subscription still receives updates. The value becomes `false` after an error or a call to unsubscribe().

#### Throws

* The method throws a `TypeError` when `appId` isn't a valid app ID or the app already has a subscription.
* The method throws a `PlatformSocketError` whose code is `subscription_limit` when the session already has eight subscriptions.

#### Example

```typescript Follow an app theme={null}
const subscription = chat.subscribe(appId, {
  onSnapshot(snapshot) {
    renderChat(snapshot.messages);
  },
  onEvent(event) {
    if (event.type === 'message.updated') upsertMessage(event.data.message);
  },
  onError(error) {
    console.error(`App ${error.appId}`, error.code);
  },
});
```

***

### close()

> **close**(): `void`

Closes the session.

Call `close()` when the page closes or you no longer need live updates. Closing ends every
subscription, stops reconnecting, and disconnects the socket. Calling `close()` again does
nothing. A closed session can't be reused, so call [`init()`](https://docs.base44.com/developers/references/platform-sdk/docs/interfaces/chat#init)
for a new one.

#### Returns

`void`

#### Example

```typescript Close a session theme={null}
chat.close();
```

## Type Definitions

### SocketSession

The three fields of a [Create socket session](https://docs.base44.com/api-reference/create-socket-session.md) response that
the browser needs. Keep the response's `session_id` on your server.

**session\_token** `string` *required*

Token that authenticates the socket. The client keeps it in memory and sends it only when the socket connects.

**socket\_url** `string` *required*

Origin of the platform socket, with no path, query, fragment, or credentials.

**socket\_path** `string` *required*

Absolute path the socket connects on, such as `/ws/socket.io/`.

### PlatformEvent

> **PlatformEvent** = `AppEvent`\<`"message.updated"`> | `AppEvent`\<`"message.removed"`> | `AppEvent`\<`"app.status_changed"`> | `AppEvent`\<`"preview.reload_requested"`> | `AppEvent`\<`"preview.navigation_requested"`> | `AppEvent`\<`"queue.updated"`> | `AppEvent`\<`"task.progressed"`> | `AppEvent`\<`"image.resolved"`> | `AppEvent`\<`"conversation.changed"`> | `AppEvent`\<`"files.changed"`> | `AppEvent`\<`"branch.deleted"`> | `AppEvent`\<`"repository.changed"`> | `AppEvent`\<`"pull_request.changed"`> | `UnknownEvent`

A live event for a subscribed app.

Check `type` to narrow `data` to that event's payload. The `data` of an event holds only the
fields that changed. Keep your value for any field the event leaves out, and clear a field the
event sets to `null`.
[Socket messages](https://docs.base44.com/developers/references/apps-api/sections/socket-messages.md) lists every event
and its payload.

An event added to the service after this version of the SDK arrives with `type: "unknown"`, its
event name in `name`, and an unchecked `data`, so check a field before using it. After you
upgrade, the event arrives under its own `type`.

#### Example

```typescript Narrow an event by type theme={null}
function onEvent(event: PlatformEvent) {
  if (event.type === "message.updated") {
    const { message } = event.data;
    console.log(`Message ${message.id} changed`);
  }
  // A hypothetical event this version of the SDK doesn't know yet
  if (event.type === "unknown" && event.name === "app.renamed" && typeof event.data.name === "string") {
    console.log(`App renamed to ${event.data.name}`);
  }
}
```

### PlatformSnapshot

An app's current state.

The snapshot arrives when you subscribe, after every reconnect, and after the main conversation
is rewritten. Replace everything you hold for the app with the snapshot. A snapshot holds only
the last 50 messages.

**status** `StatusObject | null` *required*

The app's build status, or `null` when none is recorded.

**messages** `Message[]` *required*

The last 50 messages visible to partners, oldest first.

**room** `string` *required*

Identifies the app the snapshot is for, in the form `/apps/{app_id}`.

**queue** `QueueState`

The main branch's prompt queue. Missing when the server sends none.

## Errors

### PlatformSocketError

The error the SDK reports when something goes wrong with live updates.

You don't create these errors. The SDK passes them to your `onError()` callbacks, rejects
`connect()` with them, and throws them from `subscribe()`. Check `code` to see what happened,
then look the code up below:

* Session error codes go to the `onError()` you pass to `init()`. The whole
  session is affected, and `appId` isn't set.
* App error codes go to the subscription's `onError()`. Only that app is
  affected, and `appId` says which one.

These errors never carry the session token, a callback's exception, or the server's exception
text.

#### Example

```typescript Handle session and app errors theme={null}
const chat = client.chat.init({
  async getSession() {
    const response = await fetch('/api/chat-socket-session', { method: 'POST' });
    return response.json();
  },
  // Session error codes: the whole session is affected
  onError(error) {
    if (error.code === 'session_revoked') showSignedOut();
  },
});

chat.subscribe(appId, {
  onSnapshot: renderChat,
  onEvent: applyEvent,
  // App error codes: only this app is affected, and error.appId says which
  onError(error) {
    if (error.code === 'access_revoked') hideLiveUpdates(error.appId);
  },
});
```

**code** `PlatformSocketErrorCode` *required*

What happened. One of the session error codes or app error codes.

> **Session error codes**
>
> Codes of errors that affect the whole session. They go to the `onError()` you pass to `init()`,
> and `connect()` rejects with them. A retryable error is one where the same call can succeed again
> without changing anything.
>
> **session\_unavailable**
>
> The `getSession()` callback threw, took longer than 20 seconds, or returned a session without a
> valid `session_token`, a `socket_url` that is an HTTP or HTTPS origin, or a `socket_path` that is
> an absolute path.
>
> Check the endpoint that opens sessions, then call `connect()` again. Retryable. If a field is
> invalid, fix it on your server first.
>
> **connection\_denied**
>
> Base44 refused the session even with a fresh token. Either the token is invalid, or live updates
> aren't turned on for the workspace.
>
> Check that your server opens a new session on every call. Not retryable.
>
> **connection\_failed**
>
> The socket couldn't connect after five retries, or the server closed the connection.
>
> Call `connect()` again, for example when the tab next gets focus. Retryable.
>
> **session\_revoked**
>
> Your server or an admin ended the session, or the workspace API key that opened the session lost
> access.
>
> Open a new session from your server if the page should still follow apps. Not retryable.
>
> **session\_replaced**
>
> Another socket connected with the same session token.
>
> Use one session per tab. Don't reconnect automatically. Call `connect()` only to take the
> session back on purpose. Not retryable.
>
> **protocol\_error**
>
> A message about the whole session didn't match the protocol.
>
> Update the SDK, then call `connect()` again. Not retryable.
>
> **client\_closed**
>
> You called `connect()` or `subscribe()` after `close()`.
>
> Create a new session with `init()`. Not retryable.

> **App error codes**
>
> Codes of errors for a single app. They go to the subscription's `onError()`, and `subscribe()`
> throws `subscription_limit`. Every one ends the subscription except `snapshot_unavailable`.
>
> **access\_denied**
>
> The session doesn't have access to the app, or the connection subscribed to apps too often.
>
> Add the app to the session from your server, then subscribe again. Not retryable.
>
> **access\_revoked**
>
> The session lost access to the app. Your server removed the app from the session, or the app
> left the workspace.
>
> Stop showing the app's live updates. Not retryable.
>
> **snapshot\_unavailable**
>
> The subscription is active, but its snapshot failed. Events keep arriving.
>
> Load the app's messages from the Apps API instead.
>
> **subscription\_limit**
>
> The session already has eight subscriptions.
>
> Unsubscribe from an app, or open another session. Not retryable.
>
> **delivery\_overflow**
>
> More than 1,000 snapshots and events were waiting for your callbacks.
>
> Make the callbacks faster, then subscribe again for a fresh snapshot. Retryable.
>
> **handler\_failed**
>
> Your `onSnapshot()` or `onEvent()` callback threw or rejected.
>
> Fix the callback, then subscribe again. Not retryable.
>
> **protocol\_error**
>
> An event for this app didn't match the protocol.
>
> Update the SDK, then subscribe again. Not retryable.

**appId** `string`

ID of the app the error is about. Set for app error codes, and not set for session error codes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.