Bring Your Own Turn Detection

Keep your existing turn detection and drive Flux turn endings yourself with eot_threshold and ForceEndTurn.

Streaming:Flux

Flux detects the end of a turn natively, and for most voice agents that is the right default. But if you have already invested in a turn detection stack — a VAD, an endpointing model, push-to-talk, or your own detector — you can keep it and adopt Flux for transcription without ripping out that logic. This guide shows the recipe for taking full ownership of turn endings.

The recipe

Two settings put you in control:

  1. Set eot_threshold to 1.0. This suppresses Flux’s natural EndOfTurn events — the model will not end a turn on its own confidence.
  2. Leave eager_eot_threshold unset. Eager end-of-turn is off by default; keep it off so no EagerEndOfTurn events fire.

Then send a ForceEndTurn message whenever your own detector decides the turn is over. Flux ends the turn and emits an EndOfTurn with "trigger": "manual".

1import json
2import websockets
3
4url = (
5 "wss://api.deepgram.com/v2/listen?model=flux-general-en"
6 "&eot_threshold=1.0" # suppress natural end-of-turn
7 "&eot_timeout_ms=30000" # safety-net backstop (see below)
8)
9headers = {"Authorization": "Token YOUR_DEEPGRAM_API_KEY"}
10
11async with websockets.connect(url, additional_headers=headers) as ws:
12 # When your turn detector fires:
13 await ws.send(json.dumps({"type": "ForceEndTurn"}))

How it works

  1. Send audio as usual. Flux transcribes continuously and emits StartOfTurn and Update events. With eot_threshold=1.0, it never emits EndOfTurn on its own.
  2. Your detector decides the turn is over. A push-to-talk release, a VAD silence event, a DTMF tone — whatever signal you rely on.
  3. Send ForceEndTurn. Flux ends the turn and emits EndOfTurn with the transcript decoded so far and "trigger": "manual".
  4. Dispatch the transcript. Treat the EndOfTurn transcript as final and hand it to your agent. turn_index increments and Flux is ready for the next turn.

What still ends a turn

With eot_threshold=1.0, three things can still end a turn:

  • ForceEndTurn — your explicit signal ("trigger": "manual").
  • eot_timeout_ms — a safety net. If this much silence passes, Flux force-ends the turn with "trigger": "timeout". Set it high enough that it only fires when your own detection has failed. The maximum is 60000 (60 seconds).
  • CloseStream — closes the connection without finalizing the active turn. No EndOfTurn is emitted for it; treat the most recent Update as the last transcript for that turn.

Keep eot_timeout_ms as a backstop, not a primary mechanism. If it fires often, your external detection is missing turn endings. Tune your detector rather than lowering the timeout.

Example

This loop wires an external detector to Flux. When your detector fires, it sends a ForceEndTurn; Flux replies with an EndOfTurn you treat as final.

1// Send audio frames to Flux as you receive them.
2function onAudioFrame(frame) {
3 ws.send(frame);
4}
5
6// Your existing turn detector fires -> force the turn to end.
7function onTurnDetected() {
8 ws.send(JSON.stringify({ type: "ForceEndTurn" }));
9}
10
11ws.onmessage = (event) => {
12 const data = JSON.parse(event.data);
13 if (data.type !== "TurnInfo") return;
14
15 if (data.event === "EndOfTurn") {
16 // trigger is "manual" for ForceEndTurn, "timeout" for the backstop.
17 console.log(`Turn ended (${data.trigger}):`, data.transcript);
18 dispatchToAgent(data.transcript);
19 }
20};

When to use this

  • You already have turn detection you trust and don’t want to migrate off it to adopt Flux.
  • Your turn-end signal is external and definitive — push-to-talk, DTMF, a UI action.
  • You are migrating from Nova-3 and want to keep your existing endpointing while gaining Flux transcript quality. See Migrating from Nova-3 to Flux.

If you don’t already have a turn detection stack, prefer Flux’s native detection — it is purpose-built for conversational turn-taking. See End-of-Turn Detection Parameters.