Skip to main content
This guide covers the Python SDK for pipecat-ai. The package is available on PyPI. A Node.js SDK is coming soon.

Video tutorial

Prerequisites

  • An active Tuner account
  • A Tuner agent with provider Pipecat
  • A Tuner API key, your workspace ID and the agent’s Agent Remote ID. See API keys.
  • Python 3.11 to 3.13 (3.14 is not yet supported due to Pipecat dependencies)
  • A Python project running pipecat-ai v1.0.0 or later

Overview

tuner-pipecat-sdk is an observer that captures latency signals, transcript segments, and usage metadata from your Pipecat pipeline, then sends a structured CallPayload to Tuner when the call ends. You don’t make any API calls yourself. If your agent’s LLM step is a LangChain runnable or LangGraph graph, the same observer also captures node transitions, tool calls, and token usage from that layer. See LangChain and LangGraph observability below.
1

Install the SDK

Add the package to your project with pip.
2

Pass your credentials

Give the observer your Tuner API key, workspace ID, and Agent Remote ID.
3

Add the observer

Create an observer instance and register it on your pipeline task.
4

Enable simulation

Required only if you use Call Simulation. See Enable simulation.

Step 1: Install the SDK

Requirements: Python 3.11 to 3.13, pipecat-ai>=1.0.0. Do not use Python 3.14: Pipecat dependencies (onnxruntime, numba) do not yet have 3.14 wheels. Optional extras:

Step 2: Pass your credentials

The Observer does not read environment variables. Pass the credentials as constructor arguments. You can load them from your own environment variables, as below.
Use the Agent Remote ID from Agent Settings > Agent Connection, not your agent’s display name. It is a UUID (for example fa4da74c-...). Copy your value from the Tuner dashboard.

Step 3: Add the observer

Create an Observer instance and attach turn tracking:
Observer is a pipeline-level observer. Register it, its latency_observer and the turn tracker in observers=[...] on the PipelineTask, not as a processor inside Pipeline([...]):
Without enable_metrics and enable_usage_metrics, the observer logs warnings and LLM/TTS metric fields are absent from the payload.
From pipecat-ai 1.3, PipelineWorker replaces PipelineTask. The examples on this page use PipelineTask.
When Pipecat emits EndFrame or CancelFrame, the observer sends the call to Tuner in the background. If the request fails, the SDK logs the failure and never raises or blocks your pipeline. If a call doesn’t show up in Tuner, check your logs for [tuner] failed to deliver call. For more examples, see the tuner-pipecat-sdk-python examples.

Enable simulation

Required for Call Simulation. Skip it otherwise.

Inbound

Tuner calls your agent over SIP. Your carrier sends each call to a webhook, then opens a WebSocket for the audio. Tuner’s SIP data reaches the webhook but not the WebSocket. Forward it from the webhook, then attach it in your bot.
1

Add your SIP URI in Tuner

Add your agent’s SIP URI in Agent Settings > Simulation Setup. Get it from your SIP provider, then see Set up inbound simulation.
2

Forward the SIP data from your webhook

Read the SIP data from the carrier’s request and put it on the WebSocket.
Set the Voice URL of the Twilio SIP Domain that Tuner dials to this route. Pipecat’s built-in dev runner returns TwiML with no <Parameter> tags, so use your own webhook.
3

Attach the SIP data in your bot

In your WebSocket handler, read the SIP data from the first message and attach it to the observer. Do this before the call ends.
On Twilio, the call_data from Pipecat’s parse_telephony_websocket also works. On Telnyx, pass the raw start message, because parse_telephony_websocket drops its custom_parameters.
Twilio forwards SipCallId and X-Correlation-Id. Telnyx’s call.initiated event has no SIP Call-ID, so X-Correlation-Id links a Telnyx call. Tuner links the call on either one. You can call attach_sip more than once. Headers merge, and the first non-empty value wins.
The SDK reads the SIP data for these carriers but doesn’t build the forwarding. You configure the carrier yourself, then attach in your bot.Web calls have no SIP data. Skip this section for them.
Register an object with a name and extract(payload) -> SipInfo. Add forward_to_websocket(info, ws_url) -> Forward to support forwarding.
These methods still work in 0.2.9 and warn once. Use the replacement.

Outbound

Your agent calls a Simulated Caller at a SIP URI that Tuner sends to your trigger endpoint.
  1. Configure the trigger endpoint in Agent Settings > Simulation Setup. See Set up outbound simulation.
  2. Report the SIP URI your agent dialed as recipient, exactly as Tuner sent it. Reading it from the stream needs tuner-pipecat-sdk 0.2.9 or later.
If your bot gets audio from a Twilio or Telnyx media stream, put the SIP URI on the stream when you place the call. Then the bot reads it from the start message.
If your bot already has the SIP URI, pass it directly:

Check simulation works

Start a simulation run. See Run a simulation. When the call ends, check its result in the run. If it shows Unreported, Tuner never received a matching call from your agent. See Fix an Unreported run.

End-of-utterance (EOU) delay

Wire your user context aggregator to the observer to capture how long the pipeline took to decide the user was done talking: the gap between the user going silent and the turn closing. This appears on every user turn in the transcript view as eou_delay, eou_confidence, and eou_reason.
eou_reason tells you which signal closed the turn, so eou_delay means something different depending on the value: All three fields are omitted from a turn’s metadata when nothing decided that turn’s end.

LangChain and LangGraph observability

If you use LangGraph or LangChain for your LLM step, the observer can capture node transitions, tool calls, and token usage from inside that runnable alongside the standard call data. Install the langchain extra and see LangChain / LangGraph.

Configuration options

Override the default call type label (default: "web_call"):
Provide a recording URL if available. Default is "pipecat://no-recording":
The URL must be a public https:// link. Tuner stores the default or any other value as sent, but treats the call as having no recording: it has no playback in call details and can’t be added to a Dataset.
Record why a call ended by passing a disconnection_reason_resolver callable. The resolver is called at flush time and should return a string or None.Use the built-in constants from DisconnectReason or pass a custom string:
Specify your ASR, LLM, and TTS models. They are recorded as call metadata:
Attach arbitrary key-value data to every call record, such as environment, region, deployment version, or tenant:
Metadata can also be used as an eval input. See Evaluate agents with per-call instructions.
Track which version of your agent handled each call. Set APP_VERSION in your environment:
If APP_VERSION is not set, the observer reads GITHUB_RUN_NUMBER, CIRCLE_BUILD_NUM or BUILD_NUMBER. The value must be an integer. The constructor argument takes priority over all of them:
With the traces extra installed, the observer forwards Pipecat’s OpenTelemetry spans to Tuner. forward_traces defaults to True. To turn it off:
See OpenTelemetry traces.
Log the full transcript when flushing:
Provide a callable that receives the call’s usage summary (CallUsage) and returns the call cost in USD cents. Implement the method that matches your pricing plan; the snippet below is illustrative.
stt_audio_seconds is the call’s wall-clock duration in seconds, used as a proxy for STT duration.

Full example

Using LangChain or LangGraph for your LLM step instead of a native Pipecat LLM service? Swap llm for a LangchainProcessor wrapping observer.wrap_graph(...) or observer.wrap_chain(...). See LangChain / LangGraph.

OpenTelemetry traces

Pipecat emits OpenTelemetry spans for every conversation when tracing is on. The SDK forwards them to Tuner, and they appear as a span tree on the call’s Traces tab. See Traces for how to read one.
Requires tuner-pipecat-sdk 0.2.8 or later.
1

Install the tracing extras

Without the traces extra, trace forwarding is skipped with a debug log, and the rest of the observer works as usual.
2

Turn on tracing in Pipecat

Set enable_tracing=True on your PipelineTask. This is Pipecat’s own switch for emitting spans. The SDK can’t set it for you, because you create the task after the observer.
3

Keep forward_traces on

forward_traces defaults to True on the Observer. The SDK sends spans to Tuner with the API key and base URL you passed to the Observer, and tags every span with your call_id. You don’t need setup_tracing(...), a TracerProvider, an exporter, or any OTEL_* environment variable.If you already call Pipecat’s setup_tracing(...) to export traces elsewhere, the SDK adds Tuner as an extra destination. If you configure an exporter yourself, use the OTLP HTTP exporter: Tuner does not accept gRPC.To stop forwarding traces, pass forward_traces=False. Pipecat’s enable_tracing is a separate switch that controls whether Pipecat produces spans at all.
4

Check that it worked

Open the call in Tuner. A Traces tab appears on the call details page once spans have been received and matched. Matching completes when the call itself is ingested, so the tab can take a moment to appear after a call ends.

Span reference

The span names come from Pipecat, so they are the same ones you would see in any other OpenTelemetry backend. Service spans nest under turns, under one conversation span:
Realtime models such as Gemini Live and OpenAI Realtime replace the llm span with llm_setup, llm_response, and llm_tool_call or llm_tool_result. See Pipecat’s OpenTelemetry documentation for the full set, and Traces for how to read the tree in Tuner.

Webhooks

Tuner can notify your systems when it has something to report on a call. See Webhooks.

Before you finish

  • A test call appears in Call Logs.
  • Your API key, workspace ID and Agent Remote ID come from API keys.
  • If you use Call Simulation: Enable simulation is done for your agent’s call direction, and one simulated call shows a result other than Unreported.

Troubleshooting

Python 3.14: Pipecat pins onnxruntime versions that have no 3.14 wheels. Switch to Python 3.12 or 3.13 and create a new venv.
Same as above: use Python 3.12 or 3.13.
  • Verify that agent_id is the Agent Remote ID from Agent Settings > Agent Connection (not your agent’s display name).
  • Confirm workspace_id is correct.
  • Ensure enable_metrics=True and enable_usage_metrics=True are set on PipelineParams.
  • Check your application logs for [tuner] failed to deliver call.
  • Ensure api_key starts with tr_api_ and is valid.
  • Confirm the API key belongs to the correct workspace.
  • sip_call_id is the Twilio CA… CallSid: your TwiML had no SipCallId parameter. Return forward_to_websocket(...).twiml from your webhook.
  • No X-Correlation-Id on a Telnyx call: the stream started without custom_parameters. Send fwd.stream as the streaming_start body.
  • sip_call_id is null: attach_sip never ran. Call it with the WebSocket start message.
  • ValueError: Unknown provider: the name is misspelled. Use a built-in name or register_provider.
  • See Fix an Unreported run.
The langchain extra isn’t installed. Run pip install 'tuner-pipecat-sdk[langchain]'.
  1. enable_tracing=True is missing on the PipelineTask. Pipecat emits no spans without it.
  2. The traces extra isn’t installed. Install tuner-pipecat-sdk[traces] and pipecat-ai[tracing].
  3. forward_traces=False is set on the Observer.
  4. The API key is wrong or revoked. Tuner rejects the spans with 401 or 403.

Next steps

Configure your agent

Set up call outcomes, user intents, and evals.

Custom integration

Learn about the underlying API if you need more control.

Classify calls

Define how Tuner categorizes your calls.

Alerts

Get notified when issues are detected.