# Calling State and Lifecycle

The `call` object instance manages everything related to a particular call instance, such as:

- creating and joining a call
- performing actions (mute, unmute, send reaction, etc...)
- manage event subscriptions (`call.on('call.session_started', callback)`, etc...)
- and many more

Every `call` instance should be created through the `client.call(type, id)` helper.

Our `StreamVideoClient` is responsible for maintaining a WebSocket connection to our servers and also takes care about the API calls that are proxied from the `call` instance.

As we learned in [Joining and Creating Calls](https://getstream.io/video/docs/javascript/guides/joining-and-creating-calls/) guide, a call instance is managed like this:

```ts
import { Call, StreamVideoClient } from "@stream-io/video-client";

let client: StreamVideoClient; // ...

const call: Call = client.call(type, id);

// load existing call information from our servers
await call.get();

// Creates the call on our servers in case it doesn't exist. Otherwise,
// loads the call information from our servers.
await call.getOrCreate();

// join the call
await call.join();

// leave the call and dispose all allocated resources
await call.leave();
```

Every `call` instance has a local state, exposed to integrators through:

- `call.state.callingState` - a getter that returns the current value
- `call.state.callingState$` - an observable that an integrator can subscribe to and be notified everytime the value changes

The call instance is a stateful resource that, once acquired with `client.call()`, must be disposed of with `call.leave()`. Failure to dispose of the call properly can result in memory leaks and unexpected behavior.

## Calling State

Every `call` instance has its own local state managed by the SDK.

These values are exposed through the `CallingState` enum:

```ts
import { CallingState } from "@stream-io/video-client";

// read the current value, or subscribe to `call.state.callingState$` for updates
const callingState = call.state.callingState;

switch (callingState) {
  case CallingState.JOINED:
    // ...
    break;
  default:
    const exhaustiveCheck: never = callingState;
    throw new Error(`Unknown calling state: ${exhaustiveCheck}`);
}
```

<Admonition type="note">

As `CallingState` is an enum that can be extended at any time by us, it would be good to make sure you
use it exhaustively. This way, if you use TypeScript, you can get a compile time error and be notified that
there are few more states that you should handle.

</Admonition>

### Calling States

| State                              | Description                                                                                                                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CallingState.UNKNOWN`             | The state is unknown. This value is set when Calling State isn't initialized properly.                                                                                           |
| `CallingState.IDLE`                | A call instance is created on the client side but a WebRTC session isn't established yet.                                                                                        |
| `CallingState.RINGING`             | This is an incoming (ring) call. You are the callee.                                                                                                                             |
| `CallingState.JOINING`             | The call join flow is executing (typically right after `call.join()`). Our systems are preparing to accept the new call participant.                                             |
| `CallingState.JOINED`              | The join flow has finished successfully and the current participant is part of the call. The participant can receive and publish audio and video.                                |
| `CallingState.LEFT`                | The call has been left (`call.leave()`) and all allocated resources are released. Please create a new `call` instance if you want to re-join.                                    |
| `CallingState.RECONNECTING`        | A network connection has been lost (due to various factors) and the `call` instance attempts to re-establish a connection and resume the call.                                   |
| `CallingState.RECONNECTING_FAILED` | The SDK failed to recover the connection after a couple of consecutive attempts. You need to inform the user that he needs to go online and manually attempt to rejoin the call. |
| `CallingState.MIGRATING`           | The SFU node that is hosting the current participant is shutting down or tries to rebalance the load. This `call` instance is being migrated to another SFU node.                |
| `CallingState.OFFLINE`             | No network connection can be detected. Once the connection restores, the SDK will automatically attempt to recover the connection (signalled with `RECONNECTING` state).         |

### Calling State transitions: regular path

State transitions when joining a call as caller or callee:

<Mermaid>

```text
stateDiagram-v2
  direction LR
  [*] --> IDLE
  IDLE --> RINGING: call.join({ ring })
  RINGING --> JOINING
  IDLE --> JOINING: call.join()
  JOINING --> JOINED
  JOINED --> LEFT: call.leave()
  LEFT --> [*]
```

</Mermaid>

### Calling State transitions: reconnects and migration

State transitions after network interruptions or during SFU node shutdown/rebalancing:

<Mermaid>

```text
stateDiagram-v2
  direction LR
  [*] --> JOINING
  JOINING --> JOINED: successful join

  JOINED --> RECONNECTING: network glitch/switch
  RECONNECTING --> JOINING: attempt to reconnect
  RECONNECTING --> RECONNECTING_FAILED

  JOINED --> LEFT: call.leave()
  LEFT --> [*]

  JOINED --> MIGRATING: initiate server migration
  MIGRATING --> JOINING: attempt to migrate

  JOINED --> OFFLINE: went offline
  OFFLINE --> RECONNECTING
```

</Mermaid>

### Example handling

To understand these values better, here is a hypothetical example of how these values can be mapped:

```typescript
import { CallingState } from "@stream-io/video-client";

// read the current value, or subscribe to `call.state.callingState$` for updates
const callingState = call.state.callingState;

switch (callingState) {
  case CallingState.UNKNOWN:
  case CallingState.IDLE:
    return renderLobbyScreen();

  case CallingState.RINGING:
    return renderIncomingCallScreen();

  case CallingState.JOINING:
    return renderLoadingScreen();

  case CallingState.JOINED:
    return renderActiveCallScreen();

  case CallingState.LEFT:
    return renderHaveANiceDayScreen();

  case CallingState.RECONNECTING:
  case CallingState.MIGRATING:
    return renderRestoringConnectionScreen();

  case CallingState.RECONNECTING_FAILED:
    return renderGeneralConnectionProblemScreen();

  case CallingState.OFFLINE:
    return renderNoConnectionScreen();

  default:
    const exhaustiveCheck: never = callingState;
    throw new Error(`Unknown calling state: ${exhaustiveCheck}`);
}
```


---

This page was last updated at 2026-08-11T08:51:42.933Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/javascript/guides/calling-state-and-lifecycle/](https://getstream.io/video/docs/javascript/guides/calling-state-and-lifecycle/).