LiveKit docs › Understanding LiveKit › Rooms, participants, & tracks › Participant management

---

# Participant management

> List, remove, and mute from your backend server.

## Overview

A `Participant` is a user or process that is participating in a realtime session. They are represented by a unique developer-provided `identity` and a server-generated `sid`. A participant object also contains metadata about its state and [tracks](https://docs.livekit.io/intro/basics/rooms-participants-tracks/tracks.md) they've published.

> ❗ **Important**
> 
> A participant's identity is unique per room. If participants with the same identity join a room, only the most recent one to join can remain; the server automatically disconnects other participants using that identity.

There are two participant classes in the SDKs:

- `LocalParticipant`: An instance of `LocalParticipant` is created when a user connects to a room and represents the current user. It's the interface that lets the user publish tracks to the room.
- `RemoteParticipant`: An instance of `RemoteParticipant` is created for each remote user that joins the room. The local participant, by default, can subscribe to any tracks published by a remote participant.

A participant may also [exchange data](https://docs.livekit.io/transport/data.md) with one or many other participants.

### Linked participant

In an agent session, an agent can interact with one participant at a time. The _linked participant_ is the participant the agent is actively "listening" to. To learn more, see [Linked participant in agent sessions](https://docs.livekit.io/agents/logic/sessions.md#linked-participant).

### Hidden participants

A participant is hidden if their participant [permissions](https://docs.livekit.io/reference/server/server-apis.md#participantpermission) has `hidden` set to `true`. You can set this field in the participant's [access token](https://docs.livekit.io/frontends/authentication/tokens.md#video-grant). A hidden participant is not visible to other participants in the room.

### Participant fields

| Field | Type | Description |
| sid | string | A UID for this particular participant, generated by LiveKit server. |
| identity | string | Unique identity of the participant, as specified when connecting. |
| name | string | Optional display name. |
| state | ParticipantInfo.State | JOINING, JOINED, ACTIVE, or DISCONNECTED. |
| tracks | List<[TrackInfo](https://docs.livekit.io/reference/server/server-apis.md#trackinfo)> | Tracks published by the participant. |
| metadata | string | User-specified metadata for the participant. |
| joined_at | int64 | Timestamp when the participant joined the room. |
| kind | ParticipantInfo.Kind | [Type](#types-of-participants) of participant. |
| kind_details | ParticipantInfo.KindDetail | Additional details about participant type. Valid values include `CLOUD_AGENT`, `FORWARDED`, `CONNECTOR_WHATSAPP`, and `CONNECTOR_TWILIO`. |
| attributes | string | User-specified [attributes](https://docs.livekit.io/transport/data/state/participant-attributes.md) for the participant. |
| permission | [ParticipantPermission](https://docs.livekit.io/reference/server/server-apis.md#participantpermission) | Permissions granted to the participant. |

### Types of participants

In a realtime session, a participant could represent an end-user, as well as a server-side process. It's possible to distinguish between them with the `kind` field:

- `STANDARD`: A regular participant, typically an end-user in your application.
- `AGENT`: An agent spawned with the [Agents framework](https://docs.livekit.io/agents.md).
- `SIP`: A telephony user connected via [SIP](https://docs.livekit.io/telephony.md).
- `CONNECTOR`: A user connected via a [connector](https://docs.livekit.io/telephony/connectors.md) (for example, WhatsApp or Twilio).
- `EGRESS`: A server-side process that is recording the session using [LiveKit Egress](https://docs.livekit.io/transport/media/ingress-egress/egress.md).
- `INGRESS`: A server-side process that is ingesting media into the session using [LiveKit Ingress](https://docs.livekit.io/transport/media/ingress-egress/ingress.md).

## Initialize RoomServiceClient

Participant management is done through the room service. Create a `RoomServiceClient`:

**Go**:

```go
import (
  lksdk "github.com/livekit/server-sdk-go"
  livekit "github.com/livekit/protocol/livekit"
)

// ...

host := "https://my.livekit.host"
roomClient := lksdk.NewRoomServiceClient(host, "api-key", "secret-key")

```

---

**Python**:

```shell
uv add livekit-api

```

```python
from livekit.api import LiveKitAPI

# Will read LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET from environment variables
async with api.LiveKitAPI() as lkapi:
  # ... use your client with `lkapi.room` ...

```

---

**Node.js**:

```js
import { Room, RoomServiceClient } from 'livekit-server-sdk';

const livekitHost = 'https://my.livekit.host';
const roomService = new RoomServiceClient(livekitHost, 'api-key', 'secret-key');

```

Use the `RoomServiceClient` to manage participants in a room with the APIs in the following sections. To learn more about grants and the required privileges for each API, see [Authentication](https://docs.livekit.io/frontends/authentication.md).

## List participants

You can list all the participants in a room using the `ListParticipants` API.

### Required privileges

You must have the `roomList` grant to list participants.

### Examples

**Go**:

```go
res, err := roomClient.ListParticipants(context.Background(), &livekit.ListParticipantsRequest{
  Room: roomName,
})

```

---

**Python**:

```python
from livekit.api import ListParticipantsRequest

res = await lkapi.room.list_participants(ListParticipantsRequest(
  room=room_name
))

```

---

**Node.js**:

```js
const res = await roomService.listParticipants(roomName);

```

---

**LiveKit CLI**:

```shell
lk room participants list <ROOM_NAME>

```

## Get participant details

Get detailed information about a participant in a room using the `GetParticipant` API.

### Required privileges

You must have the [`roomAdmin`](https://docs.livekit.io/frontends/authentication/tokens.md#video-grant) grant to get detailed participant information.

### Parameters

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to get. |

### Examples

**Go**:

```go
res, err := roomClient.GetParticipant(context.Background(), &livekit.RoomParticipantIdentity{
  Room:     roomName,
  Identity: identity,
})

```

---

**Python**:

```python
from livekit.api import RoomParticipantIdentity

res = await lkapi.room.get_participant(RoomParticipantIdentity(
  room=room_name,
  identity=identity,
))

```

---

**Node.js**:

```js
const res = await roomService.getParticipant(roomName, identity);

```

---

**LiveKit CLI**:

```shell
lk room participants get --room <ROOM_NAME> <PARTICIPANT_ID>

```

## Update participant

You can modify a participant's permissions and metadata using the `UpdateParticipant` API.

### Required privileges

You must have the `roomAdmin` grant to update a participant.

### Parameters

At least one of `permission` or `metadata` must be set, along with the required `room` and `identity` fields.

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to update. |
| `permission` | [ParticipantPermission](https://docs.livekit.io/reference/server/server-apis.md#participantpermission) |  | Permissions to update for the participant. Required if `metadata` is _not_ set. |
| `metadata` | string |  | Metadata to update for the participant. Required if `permission` is _not_ set. |
| `name` | string |  | Display name to update for the participant. |
| `attributes` | map[string]string |  | Attributes to update for the participant. |

### Updating participant permissions

You can update a participant's permissions using the `Permission` field in the `UpdateParticipantRequest`. When there's a change in permissions, connected clients are notified through a `ParticipantPermissionChanged` event.

This is useful, for example, to promote an audience member to a speaker role within a room by granting them the `CanPublish` privilege.

On LiveKit Cloud, updating permissions also revokes the participant's current token. A new token is automatically issued to the participant. To learn more, see [Token revocation](https://docs.livekit.io/frontends/authentication/tokens.md#token-revocation).

> ℹ️ **Revoking permissions unpublishes tracks**
> 
> When you revoke the `CanPublish` permission from a participant, all tracks they've published are automatically unpublished.

**Go**:

```go
// Promotes an audience member to a speaker
res, err := c.UpdateParticipant(context.Background(), &livekit.UpdateParticipantRequest{
  Room: roomName,
  Identity: identity,
  Permission: &livekit.ParticipantPermission{
    CanSubscribe: true,
    CanPublish: true,
    CanPublishData: true,
  },
})

// ...and later revokes their publishing permissions as speaker
res, err := c.UpdateParticipant(context.Background(), &livekit.UpdateParticipantRequest{
  Room: roomName,
  Identity: identity,
  Permission: &livekit.ParticipantPermission{
    CanSubscribe: true,
    CanPublish: false,
    CanPublishData: true,
  },
})

```

---

**Python**:

```python
from livekit.api import UpdateParticipantRequest, ParticipantPermission

# Promotes an audience member to a speaker
await lkapi.room.update_participant(UpdateParticipantRequest(
  room=room_name,
  identity=identity,
  permission=ParticipantPermission(
    can_subscribe=True,
    can_publish=True,
    can_publish_data=True,
  ),
))

# ...and later move them back to audience
await lkapi.room.update_participant(UpdateParticipantRequest(
  room=room_name,
  identity=identity,
  permission=ParticipantPermission(
    can_subscribe=True,
    can_publish=False,
    can_publish_data=True,
  ),
))

```

---

**Node.js**:

```js
// Promotes an audience member to a speaker
await roomService.updateParticipant(roomName, identity, undefined, {
  canPublish: true,
  canSubscribe: true,
  canPublishData: true,
});

// ...and later move them back to audience
await roomService.updateParticipant(roomName, identity, undefined, {
  canPublish: false,
  canSubscribe: true,
  canPublishData: true,
});

```

---

**LiveKit CLI**:

```shell
lk room participants update \
  --permissions '{"can_publish":true,"can_subscribe":true,"can_publish_data":true}' \
  --room <ROOM_NAME> \
  <PARTICIPANT_ID>

```

### Updating participant metadata

You can modify a participant's metadata using the `Metadata` field in the `UpdateParticipantRequest`. When metadata is changed, connected clients receive a `ParticipantMetadataChanged` event.

**Go**:

```go
data, err := json.Marshal(values)
_, err = c.UpdateParticipant(context.Background(), &livekit.UpdateParticipantRequest{
  Room: roomName,
  Identity: identity,
  Metadata: string(data),
})

```

---

**Python**:

```python
from livekit.api import UpdateParticipantRequest

await lkapi.room.update_participant(UpdateParticipantRequest(
  room=room_name,
  identity=identity,
  metadata=json.dumps({"some": "values"}),
))

```

---

**Node.js**:

```js
const data = JSON.stringify({
  some: 'values',
});

await roomService.updateParticipant(roomName, identity, data);

```

---

**LiveKit CLI**:

```shell
lk room participants update \
  --metadata '{"some":"values"}' \
  --room <ROOM_NAME> \
  <PARTICIPANT_ID>

```

## Move participant

> ℹ️ **LiveKit Cloud feature**
> 
> This feature is only available in LiveKit Cloud.

You can move a participant from one room to a different room using the `MoveParticipant` API. Moving a participant removes them from the source room and adds them to the destination room. For example, this API can be used to move a participant from a call room to another room in an [agent-assisted call transfer](https://docs.livekit.io/telephony/features/transfers/warm.md) workflow.

### Required privileges

You must have the `roomAdmin` grant to move a participant.

### Parameters

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to move. |
| `destination_room` | string | ✓ | Room to move participant into. |

### Examples

**Go**:

```go
res, err := roomClient.MoveParticipant(context.Background(), &livekit.MoveParticipantRequest{
  Room: roomName,
  Identity: identity,
  DestinationRoom: destinationRoom,
})

```

---

**Python**:

```python
from livekit.api import MoveParticipantRequest

await lkapi.room.move_participant(MoveParticipantRequest(
  room="<CURRENT_ROOM_NAME>",
  identity="<PARTICIPANT_ID>",
  destination_room="<NEW_ROOM_NAME>",
))

```

---

**Node.js**:

```js
await roomService.moveParticipant(roomName, identity, destinationRoom);

```

---

**LiveKit CLI**:

```shell
lk room participants move --room <CURRENT_ROOM_NAME> \
  --identity <PARTICIPANT_ID> \
  --destination-room <NEW_ROOM_NAME>

```

## Forward participant

> ℹ️ **LiveKit Cloud feature**
> 
> This feature is only available in LiveKit Cloud.

You can forward a participant to one or more rooms using the `ForwardParticipant` API. Forwarding allows you to share a participant's tracks with other rooms. For example, if you have a single ingress feed that you want to simultaneously share to multiple rooms.

A forwarded participant's tracks are shared to destination rooms until the participant leaves the room or is removed from a destination room using `RemoveParticipant`.

### Required privileges

You must have the `roomAdmin` and `destinationRoom` grants to forward a participant to the room specified for the `destinationRoom` in the grant.

### Parameters

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to forward. |
| `destination_room` | string | ✓ | Room to forward participant's tracks to. |

### Examples

**Go**:

```go
res, err := roomClient.ForwardParticipant(context.Background(), &livekit.ForwardParticipantRequest{
  Room: roomName,
  Identity: identity,
  DestinationRoom: destinationRoom,
})

```

---

**Python**:

```python
from livekit.api import ForwardParticipantRequest

await lkapi.room.forward_participant(ForwardParticipantRequest(
  room="<CURRENT_ROOM_NAME>",
  identity="<PARTICIPANT_ID>",
  destination_room="<NEW_ROOM_NAME>",
))

```

---

**Node.js**:

```js
await roomService.fowardParticipant(roomName, identity, destinationRoom);

```

---

**LiveKit CLI**:

```shell
lk room participants forward --room <CURRENT_ROOM_NAME> \
  --identity <PARTICIPANT_ID> \
  --destination-room <NEW_ROOM_NAME>

```

## Remove participant

The `RemoveParticipant` API forcibly disconnects the participant from the room. On LiveKit Cloud, this also immediately revokes their access token. To learn more, see [Token revocation](https://docs.livekit.io/frontends/authentication/tokens.md#token-revocation).

If you need to allow a removed participant to rejoin later, generate a new access token for them.

### Required privileges

You must have the `roomAdmin` grant to remove a participant.

### Parameters

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to remove. |

### Examples

**Go**:

```go
res, err := roomClient.RemoveParticipant(context.Background(), &livekit.RoomParticipantIdentity{
  Room:     roomName,
  Identity: identity,
})

```

---

**Python**:

```python
from livekit.api import RoomParticipantIdentity

await lkapi.room.remove_participant(RoomParticipantIdentity(
  room=room_name,
  identity=identity,
))

```

---

**Node.js**:

```js
await roomService.removeParticipant(roomName, identity);

```

---

**LiveKit CLI**:

```shell
lk room participants remove <PARTICIPANT_ID>

```

## Mute or unmute participant

To mute or unmute a specific participant track, you must first get the `TrackSid` using the `GetParticipant` [API](#getparticipant). You can then call the `MutePublishedTrack` API with the track SID.

### Required privileges

You must have the `roomAdmin` grant to mute or unmute a participant's published track.

### Parameters

| Name | Type | Required | Description |
| `room` | string | ✓ | Room participant is currently in. |
| `identity` | string | ✓ | Identity of the participant to mute. |
| `track_sid` | string | ✓ | SID of the track to mute. |
| `muted` | bool | ✓ | Whether to mute the track:- `true` to mute
- `false` to unmute |

### Examples

**Go**:

```go
res, err := roomClient.MutePublishedTrack(context.Background(), &livekit.MuteRoomTrackRequest{
  Room:     roomName,
  Identity: identity,
  TrackSid: "track_sid",
  Muted:    true,
})

```

---

**Python**:

```python
from livekit.api import MuteRoomTrackRequest

await lkapi.room.mute_published_track(MuteRoomTrackRequest(
  room=room_name,
  identity=identity,
  track_sid="track_sid",
  muted=True,
))

```

---

**Node.js**:

```js
await roomService.mutePublishedTrack(roomName, identity, 'track_sid', true);

```

---

**LiveKit CLI**:

```shell
lk room mute-track \
  --room <ROOM_NAME> \
  --identity <PARTICIPANT_ID> \
  <TRACK_SID>

```

You can also unmute the track by setting `muted` to `false`.

> ℹ️ **Turned off by default**
> 
> Being remotely unmuted can catch users by surprise, so it's turned off by default.
> 
> To allow remote unmute, select the **Admins can remotely unmute tracks** option in your [project settings](https://cloud.livekit.io/projects/p_/settings/project).
> 
> If you're self-hosting, configure `room.enable_remote_unmute: true` in your config YAML.

---

This document was rendered at 2026-06-07T11:37:08.311Z.
For the latest version of this document, see [https://docs.livekit.io/intro/basics/rooms-participants-tracks/participants.md](https://docs.livekit.io/intro/basics/rooms-participants-tracks/participants.md).

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