Skip to main content
The Observer pattern in Pipecat allows non-intrusive monitoring of frames as they flow through the pipeline. Observers can watch frame traffic without affecting the pipeline’s core functionality.

Base Observer

All observers must inherit from BaseObserver and can implement these methods:
  • on_push_frame(data: FramePushed): Called when a frame is pushed from one processor to another
  • on_process_frame(data: FrameProcessed): Called when a frame is being processed by a processor
  • on_pipeline_started(): Called after the StartFrame has been processed by all processors in the pipeline
  • on_processor_setup(data: ProcessorSetUp): Called once each processor has been set up
  • on_startup_warmup(data: StartupWarmup): Deprecated since 1.12.0. Never called. Will be removed in 2.0.0.
ProcessorSetUp carries the processor and the started_at_ns / finished_at_ns bracketing its setup(). Services connect during setup, so this is where that cost can be measured. Processors are set up concurrently, so these arrive in completion order rather than pipeline order, and the times come from time.monotonic_ns() because the pipeline clock isn’t running yet.

Frame Push Behavior

A frame is pushed again by every processor that passes it along. By default, an observer receives every push. An observer that handles a frame once (such as one that reports the moment a frame represents) should set observe_every_push=False and will be told about a frame only on its first push. The FramePushed event includes a first_push field that identifies whether this is the first time a frame is being pushed, allowing observers to distinguish the initial push from subsequent relays.
Example: Observer that handles each frame once

Lifecycle and Cleanup

The pipeline calls setup() on each observer when it starts and cleanup() when it stops. If your observer spawns background work, use self.create_task() so the task is tracked by the pipeline’s task manager, and override cleanup() to cancel it. Always call super().cleanup(), which waits for any in-flight event handlers to finish.
If you give your observer a custom __init__, you must call super().__init__(). Skipping it leaves the observer partially initialized and raises errors such as 'CustomObserver' object has no attribute '_name' at runtime.

Available Observers

Pipecat provides several built-in observers:
  • LLMLogObserver: Logs LLM activity and responses
  • TranscriptionLogObserver: Logs speech-to-text transcription events
  • RTVIObserver: Converts internal frames to RTVI protocol messages for server to client messaging
  • ServiceMetricsObserver: Reports service latency and usage metrics as structured records
  • StartupTimingObserver: Measures processor startup times and transport readiness
  • UserBotLatencyObserver: Measures user-to-bot response latency
  • TurnTrackingObserver: Tracks conversation turns and events

Using Multiple Observers

You can attach multiple observers to a pipeline worker. Each observer will be notified of all frames:

Example: Debug Observer

Here’s an example observer that logs interruptions and bot speaking events:

Common Use Cases

Observers are particularly useful for:
  • Debugging frame flow
  • Logging specific events
  • Monitoring pipeline behavior
  • Collecting metrics
  • Converting internal frames to external messages