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

# Events

> Events emitted by the AvaturnHead instance.

Subscribe with [`on(event, callback)`](/web-sdk/reference/methods#on-event-callback-off-event-callback) and unsubscribe with `off(event, callback)`.

The SDK forwards events from two sources:

* **Avatar / engine events** sent by the Avaturn backend over the underlying transport (avatar speech, transcripts, errors).
* **Client lifecycle events** emitted locally by the SDK (`init`, `idle`, microphone state).

## Avatar speech

### `avatar_started_speaking`

Fired when the avatar starts speaking.

```typescript theme={null}
{ type: "avatar_started_speaking", phrase_id: string }
```

### `avatar_ended_speaking`

Fired when the avatar finishes the current utterance.

```typescript theme={null}
{ type: "avatar_ended_speaking" }
```

### `avatar_started_speaking_phrase`

Fired when the avatar starts a specific queued phrase. Use this when you need to track individual phrases (e.g. for captioning).

```typescript theme={null}
{ type: "avatar_started_speaking_phrase", phrase_id: string }
```

### `avatar_ended_speaking_phrase`

Fired when the avatar finishes a phrase.

```typescript theme={null}
{ type: "avatar_ended_speaking_phrase", phrase_id: string }
```

## Transcripts

Emitted by the [OpenAI Realtime engine](/howtos/openai_realtime_api). Not emitted by the [Cartesia engine](/howtos/cartesia).

<Note>
  **User-input transcripts require configuration.** Set `audio.input.transcription.model` in the OpenAI session config (e.g. `"whisper-1"`); without it the input transcript event never fires. Assistant transcripts flow by default.
</Note>

### `ce_events.realtime.input_transcript`

User speech transcription.

```typescript theme={null}
{
  type: "ce_events.realtime.input_transcript",
  transcript: string,
  timestamp: number // unix seconds
}
```

### `ce_events.realtime.response_transcript`

Avatar (assistant) speech transcription.

```typescript theme={null}
{
  type: "ce_events.realtime.response_transcript",
  transcript: string,
  timestamp: number // unix seconds
}
```

## Client lifecycle

Emitted by the SDK locally.

### `init`

Fired when the avatar video track is ready. The promise returned by [`init()`](/web-sdk/reference/methods#init) resolves on this event.

### `idle`

Fired after 5 minutes without a backend message or [`task()`](/web-sdk/reference/methods#task-text) call. If [`keepAlive`](/web-sdk/reference/properties#keepalive) is `false`, the SDK also tears down its local state right after the event fires.

<Note>
  The `idle` event bypasses the [`event`](#event) catch-all. Subscribe to `idle` directly if you need to react to it.
</Note>

## Errors

### `error`

Fired when the backend reports a lifecycle failure. Payload structure:

```typescript theme={null}
{
  type: "error",
  error: {
    type: "session_lifecycle_error",
    code: "internal_error" | "limits_exceeded" | "openai-realtime-version-mismatch",
    message: string,
    session_id: string
  }
}
```

* `openai-realtime-version-mismatch` — your OpenAI session config mixes beta and GA-only features. Use GA-only ([beta-to-GA migration](https://platform.openai.com/docs/guides/realtime#beta-to-ga-migration)).
* `limits_exceeded` — workspace quota reached.
* `internal_error` — generic server-side failure; check `message` for details.

## Microphone

### `local_audio_change`

Fired when the user's microphone mute state changes. Callback receives a `boolean` directly (`true` = unmuted, `false` = muted).

```typescript theme={null}
avatar.on("local_audio_change", (active: boolean) => {
  // ...
});
```

### `local_mic_state_change`

Fired when the microphone permission or device state changes. Callback receives a state string from Daily's [`DailyTrackState['state']`](https://docs.daily.co/reference/daily-js/types/daily-track-state) union (e.g. `"blocked"`, `"off"`, `"sendable"`, `"loading"`, `"interrupted"`, `"playable"`, `"receivable"`).

```typescript theme={null}
avatar.on("local_mic_state_change", (state) => {
  // ...
});
```

## Catch-all

### `event`

Fires alongside every other event **except** [`idle`](#idle). Useful for logging or debugging.

```typescript theme={null}
avatar.on("event", ({ event, value }) => {
  console.log(event, value);
});
```

## Example

```typescript theme={null}
function onPhraseEnd({ phrase_id }: { phrase_id: string }) {
  console.log("phrase done:", phrase_id);
}

avatar.on("avatar_ended_speaking_phrase", onPhraseEnd);
// later
avatar.off("avatar_ended_speaking_phrase", onPhraseEnd);
```
