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

# User Turn Strategies

> Configure how user turns are detected and managed in conversations

## Overview

User turn strategies provide fine-grained control over how user speaking turns are detected in conversations. They determine when a user's turn starts (user begins speaking) and when it stops (user finishes speaking and expects a response).

By default, Pipecat uses a combination of VAD (Voice Activity Detection) and AI-powered turn detection:

* **Start**: VAD detection or transcription received
* **Stop**: AI-powered turn detection using `LocalSmartTurnAnalyzerV3`

You can customize this behavior by providing your own strategies for more sophisticated turn detection, such as requiring a minimum number of words before triggering a turn, or using AI-powered turn detection models.

## How It Works

1. **Turn Start Detection**: When any start strategy triggers, the user aggregator:
   * Marks the start of a user turn
   * Optionally emits `UserStartedSpeakingFrame`
   * Optionally emits an interruption frame (if the bot is speaking)

2. **During User Turn**: The aggregator collects transcriptions and audio frames.

3. **Turn Stop Detection**: When a stop strategy triggers, the user aggregator:
   * Marks the end of the user turn
   * Emits `UserStoppedSpeakingFrame`
   * Pushes the aggregated user message to the LLM context

4. **Timeout Handling**: If no stop strategy triggers within `user_turn_stop_timeout` seconds (default: 5.0), the turn is automatically ended. This timeout is configurable via `LLMUserAggregatorParams` (see [Configuration](#configuration) below). When the timeout fires, the [`on_user_turn_stop_timeout`](/api-reference/server/utilities/turn-management/turn-events#on_user_turn_stop_timeout) event is emitted.

## Configuration

User turn strategies are configured via `LLMUserAggregatorParams` when creating an `LLMContextAggregatorPair`:

```python theme={null}
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
    LLMContextAggregatorPair,
    LLMUserAggregatorParams,
)
from pipecat.turns.user_turn_strategies import UserTurnStrategies

context = LLMContext(messages)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=UserTurnStrategies(
            start=[...],  # List of start strategies
            stop=[...],   # List of stop strategies
        ),
    ),
)
```

### Additional Parameters

In addition to `user_turn_strategies`, `LLMUserAggregatorParams` accepts these turn-related parameters:

<ParamField path="user_turn_stop_timeout" type="float" default="5.0">
  Safety-net timeout in seconds. If a user turn starts but no stop strategy
  triggers within this duration, the turn is automatically ended and the
  [`on_user_turn_stop_timeout`](/api-reference/server/utilities/turn-management/turn-events#on_user_turn_stop_timeout)
  event is emitted.
</ParamField>

```python theme={null}
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_stop_timeout=4.0,  # Decrease timeout to 4 seconds
    ),
)
```

## Start Strategies

Start strategies determine when a user's turn begins. Multiple strategies can be provided, and the first one to trigger will signal the start of a user turn.

### Base Parameters

All start strategies inherit these parameters:

<ParamField path="enable_interruptions" type="bool" default="True">
  If True, the user aggregator will emit an interruption frame when the user
  turn starts, allowing the user to interrupt the bot.
</ParamField>

<ParamField path="enable_user_speaking_frames" type="bool" default="True">
  If True, the user aggregator will emit frames indicating when the user starts
  speaking. Disable this if another component (e.g., an STT service) already
  generates these frames.
</ParamField>

### VADUserTurnStartStrategy

Triggers a user turn start based on Voice Activity Detection. This is the most responsive strategy, detecting speech as soon as the VAD indicates the user has started speaking.

```python theme={null}
from pipecat.turns.user_start import VADUserTurnStartStrategy

strategy = VADUserTurnStartStrategy()
```

### TranscriptionUserTurnStartStrategy

Triggers a user turn start when a transcription is received. This serves as a fallback for scenarios where VAD-based detection fails (e.g., when the user speaks very softly) but the STT service still produces transcriptions.

<ParamField path="use_interim" type="bool" default="True">
  Whether to trigger on interim (partial) transcription frames for earlier
  detection.
</ParamField>

```python theme={null}
from pipecat.turns.user_start import TranscriptionUserTurnStartStrategy

strategy = TranscriptionUserTurnStartStrategy(use_interim=True)
```

### MinWordsUserTurnStartStrategy

Requires the user to speak a minimum number of words before triggering a turn start. This is useful for preventing brief utterances like "okay" or "yeah" from triggering responses.

<ParamField path="min_words" type="int" required>
  Minimum number of spoken words required to trigger the start of a user turn.
</ParamField>

<ParamField path="use_interim" type="bool" default="True">
  Whether to consider interim transcription frames for earlier detection.
</ParamField>

```python theme={null}
from pipecat.turns.user_start import MinWordsUserTurnStartStrategy

# Require at least 3 words to start a turn
strategy = MinWordsUserTurnStartStrategy(min_words=3)
```

<Note>
  When the bot is not speaking, this strategy will trigger after just 1 word.
  The `min_words` threshold only applies when the bot is actively speaking,
  preventing short affirmations from interrupting the bot.
</Note>

### WakePhraseUserTurnStartStrategy

Requires a wake phrase to be detected before allowing interaction. This strategy blocks subsequent strategies until a wake phrase is detected in a transcription, then allows interaction for a configurable timeout period.

<ParamField path="phrases" type="List[str]" required>
  List of wake phrases to detect (e.g., `["hey pipecat", "ok pipecat"]`).
</ParamField>

<ParamField path="timeout" type="float" default="10.0">
  Inactivity timeout in seconds before returning to IDLE state. In timeout mode,
  the timer resets on activity. In single activation mode, acts as a keepalive
  window after wake phrase detection.
</ParamField>

<ParamField path="single_activation" type="bool" default="False">
  If True, the wake phrase is required before every turn. The strategy returns
  to IDLE after each turn completes.
</ParamField>

```python theme={null}
from pipecat.turns.user_start import WakePhraseUserTurnStartStrategy

# Timeout mode: wake phrase unlocks interaction for 10 seconds
strategy = WakePhraseUserTurnStartStrategy(
    phrases=["hey pipecat", "ok pipecat"],
    timeout=10.0,
)

# Single activation: wake phrase required before every turn
strategy = WakePhraseUserTurnStartStrategy(
    phrases=["hey pipecat"],
    single_activation=True,
)
```

**Event Handlers**

The strategy provides event handlers for wake phrase detection:

| Event                     | Signature                                  | Description                                                    |
| ------------------------- | ------------------------------------------ | -------------------------------------------------------------- |
| `on_wake_phrase_detected` | `async def handler(strategy, phrase: str)` | Called when a wake phrase is matched                           |
| `on_wake_phrase_timeout`  | `async def handler(strategy)`              | Called when the inactivity timeout expires (timeout mode only) |

```python theme={null}
@strategy.event_handler("on_wake_phrase_detected")
async def on_wake_phrase_detected(strategy, phrase):
    print(f"Wake phrase detected: {phrase}")

@strategy.event_handler("on_wake_phrase_timeout")
async def on_wake_phrase_timeout(strategy):
    print("Wake phrase timeout, returning to IDLE")
```

<Note>
  This strategy should be placed **first** in the start strategies list to
  properly gate all subsequent strategies. Use
  `default_user_turn_start_strategies()` to extend the defaults with wake phrase
  detection.
</Note>

### KrispVivaIPUserTurnStartStrategy

Uses Krisp's Interruption Prediction (IP) model to distinguish genuine user interruptions from backchannels (e.g., "uh-huh", "yeah"). When VAD detects user speech, this strategy feeds audio frames into the Krisp VIVA IP model, which outputs a probability indicating whether the speech is a genuine interruption. A user turn is triggered only when this probability exceeds the configured threshold.

This strategy is designed to work alongside other start strategies (e.g., `TranscriptionUserTurnStartStrategy` as a fallback).

<ParamField path="model_path" type="Optional[str]" default="None">
  Path to the Krisp VIVA IP model file (.kef extension). If None, uses the
  `KRISP_VIVA_IP_MODEL_PATH` environment variable.
</ParamField>

<ParamField path="threshold" type="float" default="0.5">
  IP probability threshold (0.0 to 1.0). When the model's output exceeds this
  value, the speech is classified as a genuine interruption.
</ParamField>

<ParamField path="frame_duration_ms" type="int" default="20">
  Frame duration in milliseconds for IP processing. Supported values: 10, 15,
  20, 30, 32.
</ParamField>

<ParamField path="api_key" type="str" default="&#x22;&#x22;">
  Krisp SDK API key. If empty, falls back to the `KRISP_VIVA_API_KEY`
  environment variable.
</ParamField>

```python theme={null}
from pipecat.turns.user_start import (
    KrispVivaIPUserTurnStartStrategy,
    TranscriptionUserTurnStartStrategy,
)

strategy = KrispVivaIPUserTurnStartStrategy(
    model_path="/path/to/ip_model.kef",
    threshold=0.5,
)

# Use with a fallback strategy
strategies = UserTurnStrategies(
    start=[
        KrispVivaIPUserTurnStartStrategy(threshold=0.5),
        TranscriptionUserTurnStartStrategy(),  # Fallback
    ],
)
```

<Note>
  Requires the Krisp Python SDK. See the [Krisp VIVA
  guide](/pipecat/features/krisp-viva) for installation instructions.
</Note>

### ExternalUserTurnStartStrategy

Delegates turn start detection to an external processor. This strategy listens for `UserStartedSpeakingFrame` frames emitted by other components in the pipeline (such as speech-to-speech services).

```python theme={null}
from pipecat.turns.user_start import ExternalUserTurnStartStrategy

strategy = ExternalUserTurnStartStrategy()
```

<Note>
  This strategy automatically sets `enable_interruptions=False` and
  `enable_user_speaking_frames=False` since these are expected to be handled by
  the external processor.
</Note>

## Stop Strategies

Stop strategies determine when a user's turn ends and the bot should respond.

### Base Parameters

All stop strategies inherit these parameters:

<ParamField path="enable_user_speaking_frames" type="bool" default="True">
  If True, the aggregator will emit frames indicating when the user stops
  speaking. Disable this if another component already generates these frames.
</ParamField>

### SpeechTimeoutUserTurnStopStrategy

Signals the end of a user turn using two independent timers after VAD detects silence. The user turn stop is triggered only when both timers have finished and at least one transcript has been received:

* **user\_speech\_timeout**: Policy floor — the window in which the user may resume speaking after a pause. Always runs to completion.
* **stt\_timeout**: Safety net for STT latency — the P99 time for the STT service to return a final transcript after VAD stop. Short-circuited when the STT service emits a finalized transcript (`TranscriptionFrame.finalized=True`), since finalization means STT has nothing more to send.

For STT services that support finalization (Speechmatics, Soniox, Deepgram Flux, AssemblyAI), user turns now end as soon as `user_speech_timeout` elapses after VAD stop, rather than waiting for both timers.

<ParamField path="user_speech_timeout" type="float" default="0.6">
  How long to wait (in seconds) after VAD detects silence before finalizing the
  user turn. This is the minimum wait time and always runs to completion.
</ParamField>

```python theme={null}
from pipecat.turns.user_stop import SpeechTimeoutUserTurnStopStrategy

strategy = SpeechTimeoutUserTurnStopStrategy(user_speech_timeout=0.6)
```

<Note>
  Built-in STT P99 latency values assume `VADParams.stop_secs=0.2` (the
  recommended default). If you change `stop_secs`, the strategy will log a
  warning suggesting you re-run the [stt-benchmark](https://github.com/pipecat-ai/stt-benchmark)
  with your VAD settings and pass the measured TTFS P99 latency to your STT
  service constructor via `ttfs_p99_latency`. The strategy will also warn if
  `stop_secs >= STT p99 latency`, which collapses the STT wait timeout to 0s
  and may cause delayed turn detection.
</Note>

### TurnAnalyzerUserTurnStopStrategy

Uses an AI-powered turn detection model to determine when the user has finished speaking. This provides more intelligent end-of-turn detection that can understand conversational context.

<ParamField path="turn_analyzer" type="BaseTurnAnalyzer" required>
  The turn detection analyzer instance to use for end-of-turn detection.
</ParamField>

```python theme={null}
from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3
from pipecat.turns.user_stop import TurnAnalyzerUserTurnStopStrategy

strategy = TurnAnalyzerUserTurnStopStrategy(
    turn_analyzer=LocalSmartTurnAnalyzerV3()
)
```

<Tip>
  See the [Smart Turn
  Detection](/api-reference/server/utilities/turn-detection/smart-turn-overview)
  documentation for more information on available turn analyzers.
</Tip>

<Note>
  Built-in STT P99 latency values assume `VADParams.stop_secs=0.2` (the
  recommended default). If you change `stop_secs`, the strategy will log a
  warning suggesting you re-run the [stt-benchmark](https://github.com/pipecat-ai/stt-benchmark)
  with your VAD settings and pass the measured TTFS P99 latency to your STT
  service constructor via `ttfs_p99_latency`. The strategy will also warn if
  `stop_secs >= STT p99 latency`, which collapses the STT wait timeout to 0s
  and may cause delayed turn detection.
</Note>

### ExternalUserTurnStopStrategy

Delegates turn stop detection to an external processor. This strategy listens for `UserStoppedSpeakingFrame` frames emitted by other components in the pipeline.

<ParamField path="timeout" type="float" default="0.5">
  A short delay in seconds used to handle consecutive or slightly delayed
  transcriptions.
</ParamField>

```python theme={null}
from pipecat.turns.user_stop import ExternalUserTurnStopStrategy

strategy = ExternalUserTurnStopStrategy()
```

## Helper Functions

Pipecat provides helper functions to compose custom strategy lists that extend the defaults.

### default\_user\_turn\_start\_strategies()

Returns the default user turn start strategies: `[VADUserTurnStartStrategy, TranscriptionUserTurnStartStrategy]`.

Useful when building a custom strategy list that extends the defaults, such as adding wake phrase detection before the standard strategies.

```python theme={null}
from pipecat.turns.user_start import WakePhraseUserTurnStartStrategy
from pipecat.turns.user_turn_strategies import default_user_turn_start_strategies

# Add wake phrase detection before the defaults
start_strategies = [
    WakePhraseUserTurnStartStrategy(phrases=["hey pipecat"]),
    *default_user_turn_start_strategies(),
]
```

### default\_user\_turn\_stop\_strategies()

Returns the default user turn stop strategies: `[TurnAnalyzerUserTurnStopStrategy(LocalSmartTurnAnalyzerV3)]`.

Useful when building a custom strategy list that extends or replaces the defaults.

```python theme={null}
from pipecat.turns.user_turn_strategies import default_user_turn_stop_strategies

# Use the defaults
stop_strategies = default_user_turn_stop_strategies()
```

## UserTurnStrategies

Container for configuring user turn start and stop strategies.

<ParamField path="start" type="List[BaseUserTurnStartStrategy]" default="[VADUser...(), TranscriptionUser...()]">
  List of strategies used to detect when the user starts speaking. The first
  strategy to trigger will signal the start of the user's turn.
</ParamField>

<ParamField path="stop" type="List[BaseUserTurnStopStrategy]" default="[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())]">
  List of strategies used to detect when the user stops speaking and expects a
  response. Defaults to AI-powered turn detection using
  `LocalSmartTurnAnalyzerV3`.
</ParamField>

## ExternalUserTurnStrategies

A convenience class that preconfigures `UserTurnStrategies` with external strategies for both start and stop detection. Use this when an external processor (such as a speech-to-speech service) controls turn management.

```python theme={null}
from pipecat.turns.user_turn_strategies import ExternalUserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=ExternalUserTurnStrategies(),
    ),
)
```

<Note>
  When an STT service acts as the turn controller, you can optionally include a
  VAD (such as `SileroVADAnalyzer`) in your transport. The VAD is not required
  for core turn management functionality, but it does enable useful STT
  metrics. Omit it if you don't need those metrics.
</Note>

## Usage Examples

### Default Behavior

The default configuration uses VAD for turn start detection and AI-powered Smart Turn for turn end detection:

```python theme={null}
from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3
from pipecat.turns.user_turn_strategies import UserTurnStrategies

# This is equivalent to the default behavior
strategies = UserTurnStrategies(
    start=[VADUserTurnStartStrategy(), TranscriptionUserTurnStartStrategy()],
    stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())],
)
```

### Minimum Words for Interruption

Require users to speak at least 3 words before they can interrupt the bot:

```python theme={null}
from pipecat.turns.user_start import MinWordsUserTurnStartStrategy
from pipecat.turns.user_stop import SpeechTimeoutUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=UserTurnStrategies(
            start=[MinWordsUserTurnStartStrategy(min_words=3)],
            stop=[SpeechTimeoutUserTurnStopStrategy()],
        ),
    ),
)
```

### Wake Phrase Detection

Require a wake phrase before allowing interaction, then use the default turn strategies:

```python theme={null}
from pipecat.turns.user_start import WakePhraseUserTurnStartStrategy
from pipecat.turns.user_turn_strategies import (
    UserTurnStrategies,
    default_user_turn_start_strategies,
)

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=UserTurnStrategies(
            start=[
                WakePhraseUserTurnStartStrategy(phrases=["hey pipecat"]),
                *default_user_turn_start_strategies(),
            ],
        ),
    ),
)
```

### Local Smart Turn Detection

Use a local turn detection model instead of a cloud service:

```python theme={null}
from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3
from pipecat.turns.user_stop import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=UserTurnStrategies(
            stop=[
                TurnAnalyzerUserTurnStopStrategy(
                    turn_analyzer=LocalSmartTurnAnalyzerV3()
                )
            ]
        ),
    ),
)
```

## Related

* [User Input Muting](/pipecat/fundamentals/user-input-muting) - Control when user input is ignored
* [Smart Turn Detection](/api-reference/server/utilities/turn-detection/smart-turn-overview) - AI-powered turn detection
