> ## 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.

# Pipecat Backchannel

> Backchannel implementation that plays short listening sounds while the user is still speaking

export const CommunityMaintained = ({maintainer, maintainerUrl, repo}) => <Note>
    <strong>Community-maintained integration.</strong> This service is built and
    maintained by{" "}
    <a href={maintainerUrl} target="_blank" rel="noreferrer">
      {maintainer}
    </a>
    . Pipecat does not test or officially support it. Please report issues and
    request changes on the{" "}
    <a href={repo} target="_blank" rel="noreferrer">
      source repository
    </a>
    . Learn more about{" "}
    <a href="/api-reference/server/services/community-integrations">
      community integrations
    </a>
    .
  </Note>;

<CommunityMaintained maintainer="maisterr" maintainerUrl="https://github.com/maisterr" repo="https://github.com/maisterr/pipecat-backchannel" />

## Overview

`Backchannel` makes your bot sound like it's listening while the user is still
talking. It plays short continuers ("mhm", "yeah", "right") on pauses that the
turn model reads as incomplete, so the user gets a live-sounding call instead of
silence until they finish.

A backchannel takes no turn: every frame passes through unchanged, and nothing
reaches the LLM context, so the bot's conversation history has no record that it
happened.

Clips are recorded once from your own TTS service and cached on disk, so they
come out in the bot's voice and cost no LLM call and no network round trip at
playback time.

<CardGroup cols={2}>
  <Card title="Source Repository" icon="github" href="https://github.com/maisterr/pipecat-backchannel">
    Source code, examples, and issues for the Backchannel integration
  </Card>

  <Card title="PyPI Package" icon="cube" href="https://pypi.org/project/pipecat-backchannel/">
    The `pipecat-backchannel` package on PyPI
  </Card>
</CardGroup>

## Installation

This is a community-maintained package distributed separately from `pipecat-ai`:

```bash theme={null}
uv add pipecat-backchannel
```

## Prerequisites

No account or API key of its own. Clips are recorded through the TTS service
already in your pipeline, so whichever keys that service needs are the only ones
involved.

* **Pipecat 1.6.0 or later**: `pipecat-ai>=1.6.0,<2`
* **A TTS service in the pipeline**: used once to record the clips, unless you
  pass your own `synthesizer` or pre-recorded `cache`
* **Writable working directory**: clips are cached in `.clip_cache/` by default.
  Delete that directory after changing voice.

The first session records the clips and is held in startup while it does. Call
`prewarm()` at application start to move that cost out of the request path.

## Configuration

Constructor arguments for `Backchannel`. Every default works unconfigured; each
argument replaces one part of that default.

<ParamField path="params" type="BackchannelParams" default="None">
  Timing and frequency of the gate. See [Params](#params) below.
</ParamField>

<ParamField path="clip_groups" type="Mapping[str, Sequence[str]]" default="None">
  The clip inventory, grouped by conversational function (continuer, agreement,
  hesitation, surprise). Give each group at least two clips, or it repeats
  itself.
</ParamField>

<ParamField path="selector" type="ClipSelector" default="None">
  Which clip to play at a given moment. Defaults to `HeuristicClipSelector`.
</ParamField>

<ParamField path="turn_factory" type="Callable[[], BaseTurnAnalyzer]" default="None">
  Builds the end-of-turn classifier for each pipeline. Defaults to
  `shared_turn_analyzer`, giving each pipeline its own analyzer over one
  process-wide ONNX model.
</ParamField>

<ParamField path="synthesizer" type="ClipSynthesizer" default="None">
  Produces clips instead of recording them from the pipeline's TTS service. Only
  needed to use a different voice than the bot's own.
</ParamField>

<ParamField path="cache" type="ClipCache" default="None">
  Where clips are kept between runs. Defaults to `FileClipCache(".clip_cache")`.
</ParamField>

<ParamField path="volume" type="float" default="0.6">
  How loud clips play, relative to the recording. Below 1.0 by default, because
  a backchannel belongs underneath the person who still has the floor.
</ParamField>

<ParamField path="placement" type="AutoPlacement" default="None">
  How the processors find their positions in the pipeline.
</ParamField>

### Params

Runtime tuning passed via the `params` constructor argument using
`BackchannelParams(...)`.

| Parameter                      | Type    | Default | Description                                                                          |
| ------------------------------ | ------- | ------- | ------------------------------------------------------------------------------------ |
| `min_speech_before_eligible_s` | `float` | `0.7`   | Ignore pauses this soon after a turn starts.                                         |
| `cooldown_s`                   | `float` | `2.5`   | Minimum time between two backchannels.                                               |
| `fire_probability`             | `float` | `0.8`   | Chance of firing at an otherwise eligible pause. Below 1.0, or it sounds mechanical. |
| `vad_start_secs`               | `float` | `0.2`   | `start_secs` for this processor's own VAD.                                           |
| `vad_stop_secs`                | `float` | `0.2`   | `stop_secs` for its own VAD; also how long a pause must last before anything fires.  |

<Note>
  The integration runs its own VAD and turn analyzer, separate from the
  pipeline's: pause timing needs the opposite settings from turn-taking. Expect
  roughly 2x that inference while the user speaks, and measure before a large
  deployment. See the [source
  repository](https://github.com/maisterr/pipecat-backchannel) for the
  authoritative, up-to-date list of parameters and defaults.
</Note>

## Usage

`Backchannel` is a wrapper around your processor list, not a service you place
yourself. It inserts its processors for you and returns a new list:

```python theme={null}
from pipecat_backchannel import Backchannel

backchannel = Backchannel()  # one per process, not per session

pipeline = Pipeline(backchannel([
    transport.input(),
    stt,
    context_aggregator.user(),
    llm,
    tts,
    transport.output(),
    context_aggregator.assistant(),
]))
```

Record the clips at application startup so the first caller doesn't wait:

```python theme={null}
await backchannel.prewarm(tts=make_tts())  # throwaway TTS instance
```

Some stretches of a call want a silent listener: a dictated card number, or a
form where each pause belongs to a field. Pull the gate out of the returned list
and flip it at any time:

```python theme={null}
from pipecat_backchannel.processor import BackchannelProcessor

processors = backchannel([transport.input(), stt, llm, tts, transport.output()])
pipeline = Pipeline(processors)

gate = next(p for p in processors if isinstance(p, BackchannelProcessor))
gate.enabled = False  # frames still pass through; no clips fire
```

## Compatibility

Tested with Pipecat v1.6.0. Check the [source
repository](https://github.com/maisterr/pipecat-backchannel) for the latest
tested version and changelog.
