# Multi-device sessions
Your users move between devices and the conversation follows them. AI Transport puts every device on the same session, so the second tab and the phone see the same conversation in realtime.
A multi-device session works because the session is backed by a shared Ably channel rather than a single client-to-server HTTP connection. Any device that joins the session sees every message: user prompts, agent responses, and control signals. Your users can open a second tab, switch to a phone, or share a session with a colleague.

Fan-out to multiple connected devices is automatic. There's no special configuration:
#### Javascript
```
// Client A (laptop): wrap with a ClientSessionProvider for chatId.
// Client B (phone): same channel name in its own ClientSessionProvider, different device.
// Inside Chat, read the session from context.
const { session } = useClientSession();
```
## How it works
Every client connected to the same Ably channel shares the same durable session. When any participant publishes (a user message, an agent response, a cancel signal), every other participant receives it through their own subscription.
The client transport distinguishes between own turns (started by this client) and observer turns (started by someone else). Both types are tracked, decoded, and added to the conversation tree. The UI updates for every client, regardless of who initiated the action.
## Distinguish own and observer runs
The client session separates runs initiated by the current client from those by other participants:
| Type | Origin | Handle |
| --- | --- | --- |
| Own run | This client sent the HTTP POST that created the run. | A `ClientRun` returned from `view.send`, with `runId` (populated after `started`), `inputCodecMessageId`, `cancel()`, and `toInvocation()`. |
| Observer run | Another client or agent created the run. | Lifecycle events and folded outputs through the tree; no per-client handle. |
Both types appear in the conversation tree and the UI. Folded outputs flow through the tree the same way regardless of origin; `RunInfo.clientId` on the view tells you which client started any given run.
## Track active runs across clients
On the client, the session's default view exposes `runs()`. It returns a snapshot of visible runs as projection-free `RunInfo`, consistent across every connected client:
### Javascript
```
const { session } = useClientSession();
const runs = session.view.runs();
const isAnyoneStreaming = runs.some((r) => r.status === 'active');
const isAgentWorking = runs.some((r) => r.status === 'active' && r.clientId === 'agent-1');
```
If client A starts a run, client B's view updates immediately as the `ai-run-start` lands on the channel.
## Sync with useChat
When using Vercel's `useChat`, the `useMessageSync` hook pushes messages from other clients into `useChat`'s state:
### Javascript
```
const { chatTransport } = useChatTransport();
const { messages, setMessages } = useChat({ transport: chatTransport });
useMessageSync({ setMessages });
```
Without `useMessageSync`, `useChat` only renders messages from its own sends.
## Handle late joiners
A client that connects after the conversation has started loads the full history from the session:
### Javascript
```
const { messages, hasOlder, loadOlder } = useView({ limit: 30 });
```
`useView` loads history on mount. If a response is currently streaming, the late joiner sees it in progress; the codec's lifecycle tracker synthesises missing events so the stream renders correctly.
## Identify the client
Each client has a `clientId` that identifies it across the session. On your server, set the client ID through Ably token authentication so it is verified and cannot be spoofed:
### Javascript
```
// In your token endpoint
const token = jwt.sign({
'x-ably-clientId': 'user-123',
// ...
}, keySecret);
```
The `clientId` is used throughout: turn ownership, cancel authorisation in the agent's `onCancel` hook, and active turn tracking. Filter `view.runs()` by `clientId === ably.auth.clientId` when you want to act on this client's own runs only. Issue the `clientId` from your auth endpoint, as described in [Set up authentication](https://ably.com/docs/ai-transport/getting-started/authentication.md).
## Edge cases and unhappy paths
- Two clients sharing the same `clientId` are indistinguishable to the transport. A cancel filter that keys on `clientId` (for example "cancel only my own runs") cancels runs from both. Use a unique `clientId` per device when ownership matters.
- A late joiner without channel history capability sees the live stream but not the conversation that came before. Capability scoping is part of [authentication](https://ably.com/docs/ai-transport/getting-started/authentication.md).
- A client that loses connectivity mid-stream resumes its own view on reconnect. Other clients' views are unaffected.
- Two devices sending messages at the same time create two separate [concurrent turns](https://ably.com/docs/ai-transport/features/concurrent-turns.md), multiplexed on the same session.
- A regenerate triggered on one device updates the conversation tree on every device. The visible branch on each device depends on its current view selection.
## FAQ
### Do I need to write any sync code?
No. The session subscription is the sync. For Vercel `useChat`, add `useMessageSync` to bridge observer messages into its state.
### How many clients connect to one session?
There is no fixed limit. Every client subscribes to the same session, so usage scales with the number of subscribers, up to the [connection and message rate limits](https://ably.com/docs/platform/pricing.md) in effect.
### Can two users have different branch selections on the same session?
Yes. Each view holds its own [branch selection](https://ably.com/docs/ai-transport/features/branching.md). The conversation tree is shared; the view is per-participant.
### What stops a stranger from joining my session?
Channel capabilities. Issue tokens that [scope](https://ably.com/docs/ai-transport/getting-started/authentication.md) `subscribe` and `publish` to the specific channel name for authenticated users.
### Does presence work across devices?
Yes. Each device enters presence with its own `clientId`, following the [agent presence patterns](https://ably.com/docs/ai-transport/features/agent-presence.md).
## Related features
- [Reconnection and recovery](https://ably.com/docs/ai-transport/features/reconnection-and-recovery.md): each device reconnects independently.
- [Cancellation](https://ably.com/docs/ai-transport/features/cancellation.md): cancel from any device.
- [History and replay](https://ably.com/docs/ai-transport/features/history.md): late joiners load the full conversation.
- [Database hydration](https://ably.com/docs/ai-transport/features/database-hydration.md): seed a device from your own store and reconcile it with the live session.
## Related Topics
- [Agent presence](https://ably.com/docs/ai-transport/features/agent-presence.md): Show agent status in your AI application with Ably Presence. Display streaming, thinking, idle, and offline states in realtime.
- [Branching, edit, and regenerate](https://ably.com/docs/ai-transport/features/branching.md): Edit user messages, regenerate AI responses, and navigate branches with Ably AI Transport. The full history is preserved in the conversation tree.
- [Cancellation](https://ably.com/docs/ai-transport/features/cancellation.md): Cancel AI responses mid-stream with Ably AI Transport. Scoped cancel signals, server-side authorization, and graceful abort handling.
- [Chain of thought](https://ably.com/docs/ai-transport/features/chain-of-thought.md): Stream reasoning and thinking content alongside responses with Ably AI Transport. Display chain-of-thought in realtime.
- [Concurrent turns](https://ably.com/docs/ai-transport/features/concurrent-turns.md): Run multiple AI turns simultaneously with Ably AI Transport. Independent streams, scoped cancellation, and multi-agent support.
- [Database hydration](https://ably.com/docs/ai-transport/features/database-hydration.md): Hydrate an AI conversation from your own database with AI Transport and reconcile it with the live Ably channel, with no gap and no duplicate.
- [Double texting](https://ably.com/docs/ai-transport/features/double-texting.md): Handle users sending multiple messages while the AI is streaming with Ably AI Transport. Queue or run messages concurrently.
- [Durable execution](https://ably.com/docs/ai-transport/features/durable-execution.md): Run AI Transport agents inside a durable workflow engine. Adopt an in-flight run from a fresh process, retry a failed step under a stable stepId, and let the retry supersede the failed attempt on the channel.
- [History and replay](https://ably.com/docs/ai-transport/features/history.md): Load conversation history from Ably channels with AI Transport. Paginated history, gapless continuity, and scroll-back patterns.
- [Human-in-the-loop](https://ably.com/docs/ai-transport/features/human-in-the-loop.md): Add human approval gates to AI agent workflows with Ably AI Transport. Approve tool executions and provide input across devices.
- [Interruption and steering](https://ably.com/docs/ai-transport/features/interruption-and-steering.md): Let users change direction mid-response in Ably AI Transport. Three patterns: steer the active run with a follow-up prompt, cancel and re-prompt, or send alongside as a concurrent run.
- [LiveObjects state](https://ably.com/docs/ai-transport/features/liveobjects.md): Give an AI agent live awareness of what the user is doing, and the user live awareness of what the agent is doing, with shared state on the AI Transport session channel via Ably LiveObjects.
- [Optimistic updates](https://ably.com/docs/ai-transport/features/optimistic-updates.md): User messages appear instantly in Ably AI Transport. Optimistic insertion with automatic reconciliation when the server confirms.
- [Push notifications](https://ably.com/docs/ai-transport/features/push-notifications.md): Notify users when AI agents complete background tasks with Ably Push Notifications. Reach users even when they're offline.
- [Reconnection and recovery](https://ably.com/docs/ai-transport/features/reconnection-and-recovery.md): AI Transport streams survive connection drops automatically. Clients reconnect and resume from where they left off with no lost tokens.
- [Token streaming](https://ably.com/docs/ai-transport/features/token-streaming.md): Stream AI-generated tokens to clients in realtime using AI Transport. Tokens are appended to a single durable message, and the full response is served to clients that join later.
- [Tool calling](https://ably.com/docs/ai-transport/features/tool-calling.md): Stream tool invocations and results through Ably AI Transport. Server-executed and client-executed tools with persistent state.
## Documentation Index
To discover additional Ably documentation:
1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages.
2. Identify relevant URLs from that index.
3. Fetch target pages as needed.
Avoid using assumed or outdated documentation paths.