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

# Turn Detection

export const ModelBadges = ({models}) => {
  return <div className="flex flex-wrap gap-2 -mt-3 mb-3 not-prose">
      {models.map(model => <span key={model} className="inline-flex items-center rounded-full bg-green-500/15 px-2.5 py-0.5 text-xs font-mono text-green-700 dark:text-green-400 ring-1 ring-inset ring-green-500/30">
          {model}
        </span>)}
    </div>;
};

<ModelBadges models={["universal-3-5-pro"]} />

Detect when a speaker has finished their turn.

Streaming transcription is delivered in **turns**. A turn is one continuous unit of speech belonging to a single speaker. Deciding when a turn has ended, called **endpointing**, determines how an interactive voice application feels. End turns too early and you cut speakers off mid-thought or split a complex entity like a phone number into multiple parts. End turns too late and your voice agent feels unresponsive.

## How turn detection works

Universal-3.5 Pro Streaming does not endpoint on silence alone. When a speaker pauses, the model evaluates both acoustic and contextual cues, meaning how the speech sounded and what has been said so far, to judge whether the speaker is finished or just pausing mid-thought.

Two silence thresholds control this behavior.

| Parameter          | What it does                                                                                                                                                              | Default                                                                  |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `min_turn_silence` | Silence in milliseconds before the model runs an end-of-turn check. If the turn reads as complete, the turn ends. Otherwise a partial is emitted and the turn stays open. | Set by `mode` (`min_latency: 128`, `balanced: 224`, `max_accuracy: 800`) |
| `max_turn_silence` | Maximum silence in milliseconds before the turn is forced to end, regardless of content. This is the fallback for turns that never read as complete.                      | `1536`                                                                   |

Lower values end turns faster. Higher values tolerate longer pauses without fragmenting the turn. Both parameters can be set on the connection and [updated mid-stream](#capturing-entities-like-phone-numbers), and their defaults come from the [`mode` preset](/streaming/getting-started/optimizing-accuracy-and-latency) you select.

<Note>
  **Speaker labels change the defaults**

  When `speaker_labels` is enabled, the server applies diarization-tuned defaults instead (`min_turn_silence: 640`, `max_turn_silence: 768`, continuous partials disabled) so turns break cleanly at speaker changes.
</Note>

## The lifecycle of a turn

Each turn produces a predictable message sequence of one `SpeechStarted` message, one or more partial `Turn` messages, and a final `Turn` message.

Every `Turn` message re-transcribes the full turn audio, so each message supersedes the previous one. Always replace what you have rendered rather than appending. This also means transcripts get more accurate as the turn progresses, since each pass gives the model more audio and more context to work with. For maximum accuracy, use the final transcript marked `end_of_turn: true`. Use partials where responsiveness matters more than accuracy.

### SpeechStarted

The server sends `SpeechStarted` once per turn, immediately before the turn's first `Turn` message. It carries the turn's start `timestamp` in milliseconds from the start of the audio stream, and the `confidence` of a new turn starting.

```json theme={null}
{
  "type": "SpeechStarted",
  "timestamp": 1216,
  "confidence": 0.98
}
```

`SpeechStarted` is only emitted once the model produces an actual transcript, so background noise alone does not trigger it. That makes it a reliable barge-in signal for voice agents. When it arrives, stop your agent's TTS playback and start listening.

### Partials

While the speaker talks, the session emits `Turn` messages with `end_of_turn: false`.

```json theme={null}
{
  "type": "Turn",
  "turn_order": 0,
  "end_of_turn": false,
  "turn_is_formatted": false,
  "transcript": "my number is five five five",
  "end_of_turn_confidence": 0.0
}
```

Partials are emitted at three points.

* **Early partials** are emitted shortly after speech begins, timed by the `interruption_delay` parameter.
* **Pause partials** are emitted when a pause triggers an end-of-turn check but the turn reads as incomplete.
* **Continuous partials** are emitted roughly every 3 seconds during uninterrupted speech (`continuous_partials`, enabled by default), so long utterances keep updating even without pauses.

Partials are suited to live captions, barge-in handling, and speculative LLM prefetching, where you want text immediately and can tolerate it being revised.

### Finals

When the turn ends, the session emits a `Turn` message with `end_of_turn: true`. The final is fully formatted, with punctuation, casing, and numbers and entities rendered in written form.

```json theme={null}
{
  "type": "Turn",
  "turn_order": 0,
  "end_of_turn": true,
  "turn_is_formatted": true,
  "transcript": "My number is 555-0134.",
  "end_of_turn_confidence": 1.0
}
```

The final is the most accurate transcript of the turn. Send it to your LLM, store it, and act on it whenever accuracy matters.

## Tuning interruption sensitivity

`SpeechStarted` and early partials are what trigger interruptions in a voice agent, and two parameters control how eagerly they fire.

| Parameter            | What it does                                                                                   | Default                                                                |
| -------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `vad_threshold`      | Confidence between `0` and `1` required to classify an audio frame as speech.                  | `0.2`                                                                  |
| `interruption_delay` | How long in milliseconds after speech begins the first partial is emitted, from `0` to `1000`. | Set by `mode` (`min_latency: 0`, `balanced: 500`, `max_accuracy: 500`) |

If quiet or distant speech is being missed, lower `vad_threshold` so softer audio counts as speech. If background noise or the agent's own TTS audio is triggering false interruptions, raise `vad_threshold` so the session requires stronger evidence of speech, increase `interruption_delay` so it waits longer before emitting the first partial, or enable [Voice Focus](/streaming/voice-focus) to suppress background audio before it reaches the model.

Like the silence thresholds, both can be set on the connection and updated mid-stream.

## Capturing entities like phone numbers

Speakers naturally pause between the groups of a phone number, credit card, or address, and each of those pauses can read as a completed thought, splitting one entity across several turns. When your application knows an entity is coming (for example, your voice agent just asked for a callback number), raise `min_turn_silence` mid-stream so those pauses don't end the turn. Afterward, set your `mode` again to restore the preset's defaults. Changes take effect immediately, without reconnecting.

<Tabs>
  <Tab language="python" title="Python" default>
    ```python theme={null}
    # Before capturing the entity
    websocket.send('{"type": "UpdateConfiguration", "min_turn_silence": 1000}')

    # After the response, re-apply your mode to restore its defaults
    websocket.send('{"type": "UpdateConfiguration", "mode": "balanced"}')
    ```
  </Tab>

  <Tab language="python-sdk" title="Python SDK">
    ```python theme={null}
    # Before capturing the entity
    client.update_configuration(min_turn_silence=1000)

    # After the response, re-apply your mode to restore its defaults
    client.update_configuration(mode="balanced")
    ```
  </Tab>

  <Tab language="javascript" title="Javascript">
    ```javascript theme={null}
    // Before capturing the entity
    websocket.send('{"type": "UpdateConfiguration", "min_turn_silence": 1000}');

    // After the response, re-apply your mode to restore its defaults
    websocket.send('{"type": "UpdateConfiguration", "mode": "balanced"}');
    ```
  </Tab>

  <Tab language="javascript-sdk" title="JavaScript SDK">
    ```javascript theme={null}
    // Before capturing the entity
    transcriber.updateConfiguration({ minTurnSilence: 1000 });

    // After the response, re-apply your mode to restore its defaults
    transcriber.updateConfiguration({ mode: "balanced" });
    ```
  </Tab>
</Tabs>

If turns are still force-ended during very long pauses, raise `max_turn_silence` the same way. See [Updating configuration mid-stream](/streaming/updating-configuration-mid-stream) for the full list of mid-stream parameters.

## Bring your own turn detection

If you run your own VAD or turn detection model, send a `ForceEndpoint` message to end the current turn immediately. The server responds with the turn's final `Turn` message right away, without waiting for silence.

<Tabs>
  <Tab language="python" title="Python" default>
    ```python theme={null}
    websocket.send('{"type": "ForceEndpoint"}')
    ```
  </Tab>

  <Tab language="python-sdk" title="Python SDK">
    ```python theme={null}
    client.force_endpoint()
    ```
  </Tab>

  <Tab language="javascript" title="Javascript">
    ```javascript theme={null}
    websocket.send('{"type": "ForceEndpoint"}');
    ```
  </Tab>

  <Tab language="javascript-sdk" title="JavaScript SDK">
    ```javascript theme={null}
    transcriber.forceEndpoint();
    ```
  </Tab>
</Tabs>

## Going further

* [Optimizing accuracy and latency](/streaming/getting-started/optimizing-accuracy-and-latency) covers the `mode` presets that set turn detection defaults, plus advanced tuning parameters, including turn detection on the Universal Streaming models.
* [Message sequence](/streaming/message-sequence) documents the complete WebSocket message contract, including turn ordering guarantees.
* [Updating configuration mid-stream](/streaming/updating-configuration-mid-stream) lists everything you can change during a live session.
