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

# Sessions

> How Reactor sessions and connections work

## What is a session?

When you connect to a model, Reactor creates a **session** on a GPU running that model. The session
holds all the state for your interaction: the model's current generation context, any prompts you
have sent, and the media streams flowing between the model and your app.

A session is independent of the network connection. If your connection drops, the session keeps
running on the GPU. Reconnect and pick up where you left off without losing any model state.

A session is also independent of *which* client is connected. Multiple WebRTC connections can attach
to one session at the same time, and a session can outlive any single client. See
[Multiple connections per session](#multiple-connections-per-session).

***

## Connection lifecycle

Every connection goes through four states:

<Frame>
  <img src="https://mintcdn.com/reactortechnologiesinc/oCeFlbp0H3XO2l0l/diagrams/connection-lifecycle.svg?fit=max&auto=format&n=oCeFlbp0H3XO2l0l&q=85&s=3f00f9076a6550f4f071f30d07eea1e6" alt="Connection lifecycle: disconnected → connecting → waiting → ready" width="760" height="148" data-path="diagrams/connection-lifecycle.svg" />
</Frame>

| State          | Meaning                                                       |
| -------------- | ------------------------------------------------------------- |
| `disconnected` | No active connection                                          |
| `connecting`   | Negotiating with Reactor to create a session                  |
| `waiting`      | Session created, waiting for a GPU to be assigned             |
| `ready`        | Connected to the GPU. You can send commands and receive media |

The `waiting` state is normal. Reactor has accepted your request and is assigning a GPU,
which typically takes a few seconds. Once the status reaches `ready`, the WebRTC
connection to the GPU is established and media starts flowing.

***

## Multiple connections per session

A session is not tied to the client that created it. Several WebRTC connections can attach to one
session at the same time, which is how you build multiplayer or multi-viewer experiences on a single
model instance.

<Note>
  Sharing a session across clients is a JavaScript SDK feature, available in
  `@reactor-team/js-sdk` 2.12.0 and later.
</Note>

### Adopting an existing session

Pass a `sessionId` to `connect()` to attach to a session that already exists, for example one your
backend created. The SDK skips session creation (`POST /sessions`) and brings up its transport
against that session. The token you connect with must belong to the account that owns the session.

<CodeGroup>
  ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  // sessionId comes from your backend, or from another client's reactor.getSessionId()
  await reactor.connect(jwt, { sessionId });
  ```

  ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  <ReactorProvider
    modelName="your-model-name"
    jwtToken={token}
    connectOptions={{ sessionId, autoConnect: true }}
  >
    <ReactorView className="w-full aspect-video" />
  </ReactorProvider>
  ```
</CodeGroup>

A client reads its current session id with [`getSessionId()`](#session-id) and hands it to another
client to adopt. To adopt a specific WebRTC connection slot your backend pre-registered, also pass
[`connectionId`](/sdk-reference/reactor-class#connect).

### Who owns the session

The client that **created** a session owns its lifecycle. A client that adopted an existing session
(via `connect({ sessionId })`) tears down only its own connection when it disconnects, and leaves the
session running for its owner. This holds for explicit disconnects, page unloads, and errors.

### Tracks across connections

Each connection subscribes to the output tracks it wants on its own, controlled by
[`autoResumeTracks`](/sdk-reference/types#connectoptions). Input (`sendonly`) tracks have a single
publisher at a time: publishing an input that another connection already holds is rejected until that
connection unpublishes it. See [Tracks](/concepts/tracks).

***

## Disconnecting

When you disconnect, choose whether to keep the session alive.

### Non-recoverable (default)

The session is terminated and all state is released. Use this when the user is done.

This applies to the client that created the session. A client that adopted an existing session via
[`connect({ sessionId })`](#multiple-connections-per-session) closes its own connection but leaves
the session running for its owner.

### Recoverable

The session stays alive on the GPU for **30 seconds**. Reconnect within that window and the model
resumes exactly where it left off. Use this to survive brief network interruptions.

After 30 seconds without a reconnection, the session is automatically terminated. Billing continues
for the full reconnection window. For more information, see [Rate Limits](/resources/rate-limits).

<CodeGroup>
  ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  // Terminate the session
  await reactor.disconnect();

  // Keep the session alive
  await reactor.disconnect(true);
  await reactor.reconnect();
  ```

  ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import { useReactor } from "@reactor-team/js-sdk";

  function DisconnectControls() {
    const disconnect = useReactor((s) => s.disconnect);
    const reconnect = useReactor((s) => s.reconnect);

    return (
      <div>
        {/* Terminate the session */}
        <button onClick={() => disconnect()}>Leave</button>

        {/* Keep the session alive, then resume */}
        <button
          onClick={async () => {
            await disconnect(true);
            await reconnect();
          }}
        >
          Pause
        </button>
      </div>
    );
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  # Terminate the session
  await reactor.disconnect()

  # Keep the session alive
  await reactor.disconnect(recoverable=True)
  await reactor.reconnect()
  ```
</CodeGroup>

<Note>
  You are billed for the session's lifetime, from creation until termination, not for individual
  client connections. See [Pricing & Billing](/resources/billing) for rates, recoverable-disconnect
  behavior, and tips for minimizing cost.
</Note>

***

## Session ID

Each session has a unique ID that persists across reconnections. You can access it once connected:

<CodeGroup>
  ```typescript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  const sessionId = reactor.getSessionId();
  ```

  ```tsx React theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import { useReactor } from "@reactor-team/js-sdk";

  function SessionId() {
    const sessionId = useReactor((s) => s.sessionId);

    return <span>{sessionId}</span>;
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  session_id = reactor.get_session_id()
  ```
</CodeGroup>

Include the session ID in support requests or logs to help trace issues to a specific session. It is
also the value another client passes to
[`connect({ sessionId })`](#multiple-connections-per-session) to attach to the same session.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Commands & Messages" icon="arrow-right-left" href="/concepts/commands-and-messages">
    Send commands to the model and handle messages back.
  </Card>

  <Card title="Pricing & Billing" icon="credit-card" href="/resources/billing">
    How session time translates to cost.
  </Card>
</CardGroup>
