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

# Participant events

> Events for participant state changes — joining, leaving, updates, waiting room, and active speaker.

These events fire when participants join or leave the call, when participant state changes, and when waiting room or active speaker status updates.

***

## participant-joined

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a new remote participant joins the call.

<Note>
  This event may fire for a remote participant before the local [`joined-meeting`](/reference/daily-js/events/lifecycle-events#joined-meeting) event fires.
</Note>

<ResponseField name="action" type="string">
  Always `"participant-joined"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="DailyParticipant">
  The participant who joined. See [`DailyParticipant`](/reference/daily-js/types/daily-participant) for the full shape.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "participant-joined",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "session_id": "6f0ce557-e6e4-409f-bae9-fe5663ba4ae7",
    "user_name": "A. User Name",
    "user_id": "user_123",
    "joined_at": "2023-06-01T18:37:59.946Z",
    "local": false,
    "owner": false,
    "networkQualityState": "unknown",
    "permissions": {
      "hasPresence": true,
      "canSend": true,
      "canReceive": { "base": true },
      "canAdmin": false
    },
    "will_eject_at": "1970-01-01T00:00:00.000Z",
    "tracks": {
      "audio": { "subscribed": false, "state": "sendable" },
      "video": { "subscribed": false, "state": "sendable" },
      "screenVideo": { "subscribed": false, "state": "off", "off": { "byUser": true } },
      "screenAudio": { "subscribed": false, "state": "off", "off": { "byUser": true } }
    },
    "record": false
  }
}
```

```javascript theme={null}
call.on('participant-joined', ({ participant }) => {
  console.log(`${participant.user_name || participant.session_id} joined`);
  addParticipantTile(participant);
});
```

***

## participant-updated

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a local or remote participant's state changes — for example when their audio or video track state changes, their permissions are updated, or their network quality changes.

<ResponseField name="action" type="string">
  Always `"participant-updated"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="DailyParticipant">
  The updated participant. See [`DailyParticipant`](/reference/daily-js/types/daily-participant) for the full shape.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "participant-updated",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "session_id": "6f0ce557-e6e4-409f-bae9-fe5663ba4ae7",
    "..."
  }
}
```

```javascript theme={null}
call.on('participant-updated', ({ participant }) => {
  updateParticipantTile(participant);
});
```

***

## participant-left

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a remote participant leaves the call. The `participant` object reflects the participant's state just before they disconnected.

<Note>
  A participant [losing presence](/reference/daily-js/instance-methods/update-participant#param-update-permissions) is treated as leaving and triggers this event. In that case, the optional `reason` field will be `'hidden'`.
</Note>

<ResponseField name="action" type="string">
  Always `"participant-left"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="DailyParticipant">
  The participant who left, captured just before they disconnected. See [`DailyParticipant`](/reference/daily-js/types/daily-participant) for the full shape.
</ResponseField>

<ResponseField name="reason" type="string">
  Optional. Present when the participant became hidden rather than truly leaving. Value is `'hidden'`.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "participant-left",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "session_id": "6f0ce557-e6e4-409f-bae9-fe5663ba4ae7",
    "..."
  },
  "reason": "hidden"
}
```

```javascript theme={null}
call.on('participant-left', ({ participant }) => {
  removeParticipantTile(participant.session_id);
});
```

***

## participant-counts-updated

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when the count of present or hidden participants in the call changes. See [`participantCounts()`](/reference/daily-js/instance-methods/participant-counts) for details.

<ResponseField name="action" type="string">
  Always `"participant-counts-updated"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participantCounts" type="object">
  Contains `present` (number of visible participants) and `hidden` (number of hidden participants).
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "participant-counts-updated",
  "callClientId": "17225364729060.9442072768918943",
  "participantCounts": {
    "present": 4,
    "hidden": 1
  }
}
```

```javascript theme={null}
call.on('participant-counts-updated', ({ participantCounts }) => {
  document.getElementById('participant-count').textContent = participantCounts.present;
});
```

***

## waiting-participant-added

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a participant enters the waiting room and is added to the [`waitingParticipants()`](/reference/daily-js/instance-methods/waiting-participants) set.

<ResponseField name="action" type="string">
  Always `"waiting-participant-added"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="object">
  Contains `id`, `name`, and `awaitingAccess` (with a `level` field indicating the requested access level).
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "waiting-participant-added",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "id": "a64d30f4-5216-4481-a2ef-515d6dd7dfc6",
    "name": "Jane Smith",
    "awaitingAccess": { "level": "full" }
  }
}
```

***

## waiting-participant-updated

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a participant in the waiting room updates their details — currently this only occurs when their `name` changes.

<ResponseField name="action" type="string">
  Always `"waiting-participant-updated"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="object">
  Contains `id`, `name`, and `awaitingAccess`.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "waiting-participant-updated",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "id": "a64d30f4-5216-4481-a2ef-515d6dd7dfc6",
    "name": "Jane Smith (updated)",
    "awaitingAccess": { "level": "full" }
  }
}
```

***

## waiting-participant-removed

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when a participant is removed from the [`waitingParticipants()`](/reference/daily-js/instance-methods/waiting-participants) set — either they were granted access, denied, or left on their own.

<ResponseField name="action" type="string">
  Always `"waiting-participant-removed"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="participant" type="object">
  Contains `id`, `name`, and `awaitingAccess`.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "waiting-participant-removed",
  "callClientId": "17225364729060.9442072768918943",
  "participant": {
    "id": "a64d30f4-5216-4481-a2ef-515d6dd7dfc6",
    "name": "Jane Smith",
    "awaitingAccess": { "level": "full" }
  }
}
```

***

## active-speaker-change

<Badge color="green">{"✓"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

Fires when the active speaker — the participant whose audio input is currently loudest — changes. Use this to highlight the speaking participant in a custom UI.

<ResponseField name="action" type="string">
  Always `"active-speaker-change"`.
</ResponseField>

<ResponseField name="callClientId" type="string">
  The ID of the call client instance that emitted this event.
</ResponseField>

<ResponseField name="activeSpeaker" type="object">
  Contains `peerId`, which is the `session_id` of the participant currently speaking.
</ResponseField>

```json theme={null}
// Example event object
{
  "action": "active-speaker-change",
  "callClientId": "17225364729060.9442072768918943",
  "activeSpeaker": {
    "peerId": "049ebba2-523b-4e6c-9a9f-1f8bb956670d"
  }
}
```

```javascript theme={null}
call.on('active-speaker-change', ({ activeSpeaker }) => {
  highlightSpeaker(activeSpeaker.peerId);
});
```

***

## See also

<CardGroup>
  <Card title="Types" icon="t" iconType="solid">
    * [DailyParticipant](/reference/daily-js/types/daily-participant)
  </Card>

  <Card title="Methods" icon="code" iconType="solid">
    * [participants()](/reference/daily-js/instance-methods/participants)
    * [participantCounts()](/reference/daily-js/instance-methods/participant-counts)
    * [updateParticipant()](/reference/daily-js/instance-methods/update-participant)
    * [waitingParticipants()](/reference/daily-js/instance-methods/waiting-participants)
  </Card>

  <Card title="Events" icon="bolt" iconType="solid">
    * [Lifecycle events](/reference/daily-js/events/lifecycle-events)
  </Card>

  <Card title="Guides" icon="book-open" iconType="solid">
    * [Participants](/docs/daily-js/concepts/participants)
    * [Waiting room](/docs/daily-js/guides/waiting-room)
  </Card>
</CardGroup>
