Skip to main content

pipecat-roark

A Roark analytics observer for Pipecat. Drop one observer into your pipeline — Roark captures call lifecycle, transcripts, tool calls, and a stereo audio recording. No other code changes required.

  • Tested with pipecat-ai 0.0.108 (compatible with >= 0.0.104, < 1)
  • Python 3.10+
  • Runtime-agnostic — same code runs self-hosted and on Pipecat Cloud

Maintained by Roark. File issues at https://github.com/roarkhq/sdk-roark-analytics-python-pipecat/issues.


Contents


Quick start

1. Install

pip install pipecat-roark

2. Create a Pipecat integration & API key

Every Roark API key is bound to a specific integration — the key only works for the integration it was created under. Before you can send calls from this package, create the integration first:

  1. In the Roark dashboard, go to Integrations and create a new Pipecat integration.
  2. Open that integration and generate an API key for it.
  3. Copy the key (represented as rk_live_replace_me below) — this is the value you'll set as ROARK_API_KEY below.

Use the key created under the Pipecat integration. A key from a different integration (or an account-level key not bound to one) will be rejected.

3. Configure

Set one env var:

ROARK_API_KEY=rk_live_replace_me

The Roark API key is all you configure — the observer knows its own service endpoints. ROARK_API_KEY can also be passed as api_key= to RoarkObserver.

4. Wire the observer

Inside your Pipecat bot(runner_args) entry point, drop RoarkObserver into the pipeline's observers=[...] list. Splice the auto-created roark.audio_processor after transport.output() so it sees the bot's audio post-TTS:

from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat_roark import RoarkObserver

roark = RoarkObserver(
    api_key="rk_live_replace_me",
    agent_id="support-bot-v3",
    runner_args=runner_args,
    agent_name="Support Bot v3",
    agent_prompt=SYSTEM_PROMPT,
)

pipeline = Pipeline([
    transport.input(), stt, context_aggregator.user(), llm, tts,
    transport.output(),
    roark.audio_processor,          # after transport.output() — L=user, R=bot
    context_aggregator.assistant(),
])

task = PipelineTask(pipeline, params=PipelineParams(observers=[roark]))

That's it — transcripts, tool calls, and the stereo recording flow to Roark automatically.


How it works

The observer subscribes to Pipecat frames and ships a compact event timeline to Roark:

Phase What's captured
Pipeline start call-started POST + recording begins. Agent is lazy-registered on Roark the first time it sees this agent_id.
User turns Final TranscriptionFrames (interim transcriptions ignored).
Assistant turns TTSTextFrame chunks aggregated between BotStoppedSpeakingFrame / InterruptionFrame boundaries.
Tool calls FunctionCallInProgressFrame + FunctionCallResultFrame, paired by toolCallId.
Audio Stereo PCM chunks emitted by AudioBufferProcessor, streamed via presigned upload URLs (POST /v1/integrations/pipecat/chunk-upload-url).
Pipeline end EndFrame / CancelFrame / StopFrame (or aflush()) flushes in-flight turns, drains uploads, and POSTs call-ended. Roark finalizes the recording on its side.

Transcripts and tool calls are forwarded in Pipecat's native shape — Roark maps them to its internal schema on its side.

Audio capture defaults

The observer always creates a sane-default AudioBufferProcessor (stereo, ~256 KB chunks) exposed as roark.audio_processor. The sample rate is adopted from the pipeline's StartFrame, so it tracks whatever the transport/provider negotiated — 8 kHz on Twilio/Telnyx, 16/24/48 kHz on Daily/LiveKit, etc. The rate is forwarded to Roark as the recording sample rate.

Failure mode

Failures are logged and swallowed — the observer never raises into the pipeline. Your call keeps running even if Roark is unreachable.


Running modes

RoarkObserver is runtime-agnostic — the same observer wiring works whether your Pipecat agent runs as a self-hosted process or is deployed to Pipecat Cloud. Write one bot(runner_args) entry point with Pipecat's create_transport helper, and the same file runs in both modes — see examples/bot.py.

Both modes use the same ROARK_API_KEY — the key created under your Pipecat integration (see Create a Pipecat integration & API key). Only where the key is stored differs: a local .env / secrets manager self-hosted, deployment secrets on Pipecat Cloud.

Self-hosted Pipecat Cloud
Entry point python bot.py → pipecat.runner.run.main() dispatches to bot() Platform invokes bot(runner_args) per session
Room/token You provision (Daily REST, pipecat.runner.daily.configure, …) Injected via DailyRunnerArguments
Env vars .env / your secrets manager pcc secrets set <name> KEY=value …
Teardown EndFrame is reliable Sessions can vanish — wire aflush() on disconnect
Observer wiring ← identical → ← identical →

Self-hosted

cp .env.example .env
# fill in ROARK_API_KEY
uv sync --all-extras
uv run python examples/bot.py --transport daily   # or: --transport webrtc

Pipecat Cloud

Set the same vars as deployment secrets, then deploy:

pcc secrets set roark-secrets \
    ROARK_API_KEY=rk_live_replace_me

pcc deploy
pcc agent start <agent-name>

Reference the secrets from your pcc-deploy.toml so the container sees them as os.environ["ROARK_API_KEY"] (etc.) at runtime.


Examples

Two example files ship with the package:

  • examples/basic_observer.py — minimal transport-agnostic wiring sketch. Shows where RoarkObserver and roark.audio_processor slot into a Pipeline / PipelineTask. STT / LLM / TTS stages are omitted — copy them into your own pipeline.
  • examples/bot.py — runnable foundational voice assistant (Deepgram STT → OpenAI LLM → Cartesia TTS) with RoarkObserver wired in. Same file runs self-hosted (--transport webrtc / --transport daily) and deploys to Pipecat Cloud unchanged.
cp .env.example .env
# fill in:
#   ROARK_API_KEY
#   DEEPGRAM_API_KEY, OPENAI_API_KEY, CARTESIA_API_KEY

uv sync --all-extras
uv pip install "pipecat-ai[silero,deepgram,openai,cartesia,webrtc,daily]"

# Local browser via Pipecat's built-in WebRTC (no third-party transport account):
uv run python examples/bot.py --transport webrtc
# Or Daily (see Pipecat runner docs for transport-specific setup):
uv run python examples/bot.py --transport daily

Advanced

Call identity

Pass the runner_args received by your Pipecat bot entry point directly to the observer. It resolves one call ID internally, in this order:

  1. SmallWebRTC runner_args.webrtc_connection.pc_id.
  2. Pipecat Cloud runner_args.session_id.
  3. A random UUID, generated once for this observer.

The native SmallWebRTC and Pipecat Cloud identifiers let Roark correlate both sides of a supported simulation automatically. Other runner and transport types still ingest normally, but their UUID fallback is local to the observer and does not provide native-ID simulation merging.

The resolved value is available through the read-only observer.pipecat_call_id property. Applications do not need to generate or forward an identifier themselves.

Bring your own AudioBufferProcessor

If you need to tune sample rate, channel count, or buffer size, instantiate AudioBufferProcessor yourself and pass it via audio_buffer_processor=:

from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor

audio_buffer = AudioBufferProcessor(sample_rate=16000, num_channels=1, buffer_size=128 * 1024)

pipeline = Pipeline([..., transport.output(), audio_buffer, ...])

RoarkObserver(
    api_key="rk_live_replace_me",
    agent_id="support-bot-v3",
    runner_args=runner_args,
    audio_buffer_processor=audio_buffer,
)

Handling WebRTC disconnects

Pipecat's WebRTC transports (notably SmallWebRTC) sometimes tear down without pushing EndFrame through observers. Call aflush() from the disconnect handler to guarantee the call is finalized on Roark:

@transport.event_handler("on_client_disconnected")
async def _on_disconnect(_, __):
    await roark_observer.aflush(reason="client-disconnected")

aflush() is idempotent — the regular EndFrame path will no-op on the next call.

Correlating with OpenTelemetry tracing

If you also enable Pipecat's OpenTelemetry tracing (PipelineTask(enable_tracing=True)), use the observer's resolved, read-only call ID as PipelineTask.conversation_id. Each Roark call can then be looked up by the same value in your tracing backend:

from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat_roark import RoarkObserver

roark = RoarkObserver(
    api_key="rk_live_replace_me",
    agent_id="support-bot-v3",
    runner_args=runner_args,
)

task = PipelineTask(
    pipeline,
    params=PipelineParams(observers=[roark]),
    enable_tracing=True,
    conversation_id=roark.pipecat_call_id,
)

Pipecat sets conversation.id as a span attribute on a root "conversation" span (and propagates it to every child span). The OTel traceId itself is auto-generated and unrelated to your call ID; correlation happens by attribute value. To find the trace for a Roark call, query your backend by conversation.id = <pipecatCallId> (e.g., Honeycomb: where conversation.id = "...", Jaeger: tag filter, Datadog: @conversation.id:...).

Because roark.pipecat_call_id is read-only, the lifecycle payload and tracing attribute cannot drift after observer construction.


Troubleshooting

Do I need enable_tracing=True on PipelineTask?

No. RoarkObserver captures raw frames — it does not consume OpenTelemetry spans. The tracing flag is unrelated. If you do enable it and want Roark calls linked to their traces, see Correlating with OpenTelemetry tracing.

Calls aren't finalizing on Roark

Some transports (notably SmallWebRTC) tear down without pushing EndFrame through observers. Wire aflush() into your disconnect handler — see Handling WebRTC disconnects.

Recording captures user audio only / bot audio only

The AudioBufferProcessor must sit after transport.output() so it sees the bot's audio post-TTS. If it's placed earlier in the pipeline, the bot channel will be silent.

Transcripts arrive empty

The observer warns call-ended with empty transcript ... no TranscriptionFrame or TTSTextFrame was observed during the call when nothing was captured. Usually this means the STT service isn't emitting finalized TranscriptionFrames, or the pipeline ended before any speech was processed.


Configuration reference

Parameter Type Default Notes
api_key str — Required. Roark API key.
agent_id str — Required. Customer-stable agent identifier.
runner_args object — Required. The arguments passed to your Pipecat bot entry point. Used to resolve a native SmallWebRTC or Pipecat Cloud identifier when available.
agent_name str | None None Display name.
agent_prompt str | None None System prompt. Persisted as the agent's prompt revision.
audio_buffer_processor AudioBufferProcessor | None None Power-user override — pass your own AudioBufferProcessor to control sample rate / channels / buffer size. If omitted, the observer creates a default (stereo, ~256 KB chunks; sample rate adopted from the pipeline's StartFrame) accessible via observer.audio_processor.
pipecat_call_id str | None None Deprecated and ignored. Accepted for compatibility and scheduled for removal in 0.3.0. Pass runner_args instead.

observer.pipecat_call_id is the read-only resolved call ID. Use it as PipelineTask(conversation_id=...) when OpenTelemetry tracing is enabled.


Development

uv sync --all-extras
uv run pytest
uv run ruff check .

License

MIT — see LICENSE.

Metadata

Release files for pipecat-roark 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pipecat-roark 0.2.1
File Size Uploaded Provenance Actions
pipecat_roark-0.2.1.tar.gz 233.1 kB With provenance Details for pipecat_roark-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pipecat-roark 0.2.1
File Interpreter ABI Platform Actions
pipecat_roark-0.2.1-py3-none-any.whl Python 3 none any Details for pipecat_roark-0.2.1-py3-none-any.whl

Total release size: 257.7 kB

Release files / pipecat_roark-0.2.1.tar.gz

Download URL pipecat_roark-0.2.1.tar.gz
Size 233.1 kB
Tags Source
SHA-256 checksum
How to use checksums
718bef9f4250a91082c70c3496c2b73ba863c0bdd6e6b83e2f462d2b77cfd22b
BLAKE2b-256 checksum
How to use checksums
e68915180f1236104ac54bc32e96b82a29e3b4d39805b4486aa2a6b423fdf8cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / pipecat_roark-0.2.1-py3-none-any.whl

Download URL pipecat_roark-0.2.1-py3-none-any.whl
Size 24.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2fb09c3adf8e5bd7d6834ec3c25aaa30145602146f91015b0a9cd9725ecf53b8
BLAKE2b-256 checksum
How to use checksums
93aa1131378a915caa40e2fe904c89d0d833c0e981fe34da78025c19ed6b872f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Security for pipecat-roark 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pipecat_roark-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page