LiveKit docs › Building Frontends › Agent state

---

# Agent state

> Track and respond to agent state changes in your frontend.

## Overview

Agents move through a lifecycle of states: connecting, listening, thinking, speaking, and eventually disconnecting or failing. Your frontend can read that state to show the right UI -- for example, when a user can talk, when an agent is busy, or if something has gone wrong. The agent publishes its state as the `lk.agent.state` participant attribute.

For most UI decisions you should use [state getters](#using-state-getters), which are booleans like `canListen` and `isFinished`, rather than raw state, so your UI stays correct as the SDK evolves.

## Agent states

State comes from two places. The agent SDK reports what the agent is doing (for example, listening or speaking), and the client reports connection and terminal outcomes. The following table defines each state.

| State | Description |
| `connecting` | The client is connecting to the room. The agent is not yet in the loop. |
| `pre-connect-buffering` | The app is connecting and may buffer user input before the connection is ready. Used for [instant connect](https://docs.livekit.io/agents/multimodality/audio.md#instant-connect). Can be disabled so the client goes straight to the active states. |
| `initializing` | The agent is connecting and setting up. |
| `idle` | The agent is connected but idle (waiting for user input). |
| `listening` | The agent is actively listening to the user. |
| `thinking` | The agent is processing input or performing actions. |
| `speaking` | The agent is producing audio output. |
| `disconnected` | The user disconnected cleanly. This is the normal success outcome after ending a session. |
| `failed` | The session entered an error state. Check the platform's failure API such as `failureReasons` for details. |

### Lifecycles

The following diagrams show the lifecycle of an agent with or without [instant connect](https://docs.livekit.io/agents/multimodality/audio.md#instant-connect) enabled. The flow can end in `failed` from any state, such as if the agent never connects or leaves the room unexpectedly during the conversation.

#### With instant connect

In this flow, the agent connects, buffers input, initializes, and then can listen, think, speak, and eventually disconnect.

```mermaid
flowchart LR
A[connecting] --> B[pre-connect-buffering]
B --> C[initializing]
C --> D[idle / listening / thinking / speaking]
D --> E[disconnected]
classDef stateConnecting fill:#1f1f1f,stroke:#404040,color:#d0d0d0
classDef stateBuffer fill:#0d2d3d,stroke:#1a4a5c,color:#7ec8e3
classDef stateInitializing fill:#252525,stroke:#454545,color:#d0d0d0
classDef stateActive fill:#0d2d3d,stroke:#1a4a5c,color:#7ec8e3
classDef stateDisconnected fill:#0d2618,stroke:#1a4028,color:#7dd89a
class A stateConnecting
class B stateBuffer
class C stateInitializing
class D stateActive
class E stateDisconnected
```

#### Without instant-connect

In this flow, the agent connects, initializes, and then can listen, think, speak, and eventually disconnect. It doesn't buffer input before the connection is ready.

```mermaid
flowchart LR
A[connecting] --> B[initializing]
B --> C[idle / listening / thinking / speaking]
C --> D[disconnected]
classDef stateConnecting fill:#1f1f1f,stroke:#404040,color:#d0d0d0
classDef stateInitializing fill:#252525,stroke:#454545,color:#d0d0d0
classDef stateActive fill:#0d2d3d,stroke:#1a4a5c,color:#7ec8e3
classDef stateDisconnected fill:#0d2618,stroke:#1a4028,color:#7dd89a
class A stateConnecting
class B stateInitializing
class C stateActive
class D stateDisconnected
```

### Disconnected vs failed

The `disconnected` state is the successful status of a call ending. It means the user connected, then disconnected, and everything shut down correctly.

The `failed` state is the error status of a call ending. It means the state machine hit an error, such as connection or agent errors. When state is `failed`, use the platform's failure property like `failureReasons` to surface or handle the issues.

## Using state getters

Use state getters for UI decisions to accommodate new states as they're added over time. State getters are booleans over raw state so your UI stays correct as the SDK evolves.

> ℹ️ **Info**
> 
> Only use raw states when you need to show a specific state in the UI, such as "Pre-connect buffering…" or "Connecting…" messages.

State getters and their associated descriptions and states can be found in the following table.

| Getter | Description | Associated states |
| `canListen` | The user can speak. Input is accepted (including while the agent is thinking or speaking). | `pre-connect-buffering`, `listening`, `thinking`, `speaking` |
| `isConnected` | The session is connected to the room. | `listening`, `thinking`, `speaking` |
| `isPending` | The agent is in a transitional phase (connecting or setting up). | `connecting`, `initializing`, `idle` |
| `isFinished` | The session has reached a terminal outcome. | `disconnected`, `failed` |

## Accessing agent state

The following examples show how to read state and getters for each platform.

**React**:

Use the `useAgent` hook to access the agent's state and getters:

```tsx
import { useAgent } from '@livekit/components-react';

function AgentStatus() {
  const agent = useAgent();
  return (
    <>
      {agent.canListen && (
        <div>
          <p>Agent ready!</p>
          <p>Agent is in state {agent.state}</p>

          {/* Show chat panel or other agent specific ui elements here */}
        </div>
      )}

      {agent.isFinished && (
        agent.failureReasons?.length > 0 ? (
          <p>Agent failed: {agent.failureReasons.join(', ')}</p>
        ) : (
          <p>Agent disconnected.</p>
        )
      )}
    </>
  );
}

```

---

**Swift**:

Access the agent from the session and use its state getters. The session's `agent` property exposes `canListen`, `isFinished`, `agentState`, and `error`:

```swift
@EnvironmentObject var session: Session

var body: some View {
    let agent = session.agent

    if agent.canListen {
        VStack {
            Text("Agent ready!")
            Text("Agent is in state \(String(describing: agent.agentState ?? .initializing))")
            // Show chat panel or other agent-specific UI here
        }
    }

    if agent.isFinished {
        if let error = agent.error {
            Text("Agent failed: \(error.localizedDescription)")
        } else {
            Text("Agent disconnected.")
        }
    }
}

```

---

**Android**:

Use the `rememberAgent` composable to access the agent's state and getters.

```kotlin
@Composable
fun AgentStatus() {
    val agent = rememberAgent()

    if (agent.canListen) {
        Column {
            Text("Agent ready!")
            Text("Agent is in state ${agent.agentState.name}")
            // Show chat panel or other agent-specific UI here
        }
    }

    if (agent.isFinished) {
        if (agent.failureReasons.isNotEmpty()) {
            Text("Agent failed: ${agent.failureReasons.joinToString(", ")}")
        } else {
            Text("Agent disconnected.")
        }
    }
}

```

## Custom state

The built-in agent states cover the agent's lifecycle, but your application may need to share additional state between the frontend and agent. For example, you might want to display which tool the agent is currently using, show a list of items the agent has found, or let the user toggle agent behavior from the UI.

For this kind of application-specific state, use LiveKit's state synchronization and RPC features. State synchronization keeps key-value data in sync across participants, while RPC lets you call methods on the agent or frontend from the other side.

- **[State synchronization](https://docs.livekit.io/transport/data/state.md)**: Share custom state between your frontend and agent.

- **[RPC](https://docs.livekit.io/transport/data/rpc.md)**: Define and call methods on your agent or your frontend from the other side.

---

This document was rendered at 2026-06-07T11:34:28.389Z.
For the latest version of this document, see [https://docs.livekit.io/frontends/build/agent-state.md](https://docs.livekit.io/frontends/build/agent-state.md).

To explore all LiveKit documentation, see [llms.txt](https://docs.livekit.io/llms.txt).