Skip to main content

Overview

DailyTransport provides real-time audio and video communication using Daily’s hosted WebRTC platform. It handles bidirectional media streams, participant management, transcription, recording, and telephony features without requiring your own WebRTC infrastructure. Daily manages all the complexity of WebRTC connections, NAT traversal, and global media routing.

Installation

To use DailyTransport, install the required dependencies:
pip install "pipecat-ai[daily]"

Prerequisites

Daily Account Setup

Before using DailyTransport, you need:
  1. Daily Account: Sign up at Daily Dashboard
  2. API Key: Generate a Daily API key from your dashboard
  3. Room Creation: Daily rooms must be created before connecting (see Usage section)

Required Environment Variables

  • DAILY_API_KEY: Your Daily API key for room creation and management

Key Features

  • Hosted WebRTC: No infrastructure setup required - Daily handles all WebRTC complexity
  • Multi-participant Support: Handle multiple participants with individual audio/video tracks
  • Built-in Transcription: Real-time speech-to-text with Deepgram integration
  • Telephony Integration: [Dial-in/dial-out support for phone numbers via SIP/PSTN
  • Recording & Streaming: Built-in call recording and live streaming capabilities
  • Global Infrastructure: Daily’s edge network ensures low latency worldwide
  • Advanced Controls: Participant management, permissions, and media routing

Configuration

DailyTransport

room_url
str
required
URL of the Daily room to connect to.
token
str
default:"None"
Authentication token for the room. Required for private rooms or when specific permissions are needed.
bot_name
str
required
Display name for the bot in the call.
params
DailyParams
default:"DailyParams()"
Transport configuration parameters. See DailyParams below and TransportParams for inherited base parameters.
input_name
str
default:"None"
Optional name for the input transport processor.
output_name
str
default:"None"
Optional name for the output transport processor.

DailyParams

Inherits all parameters from TransportParams (audio, video, VAD settings) with these additional fields:
api_url
str
default:"https://api.daily.co/v1"
Daily API base URL.
api_key
str
default:""
Daily API authentication key.
audio_in_user_tracks
bool
default:"True"
Receive users’ audio in separate tracks rather than a mixed stream.
dialin_settings
DailyDialinSettings
default:"None"
Settings for dial-in functionality. See DailyDialinSettings below.
camera_out_enabled
bool
default:"True"
Whether to enable the main camera output track.
microphone_out_enabled
bool
default:"True"
Whether to enable the main microphone track.
transcription_enabled
bool
default:"False"
Whether to enable Daily’s built-in speech transcription (powered by Deepgram).
transcription_settings
DailyTranscriptionSettings
default:"DailyTranscriptionSettings()"
Configuration for the transcription service. See DailyTranscriptionSettings below.

DailyDialinSettings

Settings for Daily’s dial-in (SIP) functionality.
call_id
str
default:""
Call ID (UUID) representing the session ID in the SIP network.
call_domain
str
default:""
Call domain (UUID) representing your Daily domain on the SIP network.

DailyTranscriptionSettings

Configuration for Daily’s built-in transcription service (Deepgram).
language
str
default:"en"
ISO language code for transcription.
model
str
default:"nova-2-general"
Deepgram transcription model to use.
profanity_filter
bool
default:"True"
Whether to filter profanity from transcripts.
redact
bool
default:"False"
Whether to redact sensitive information.
endpointing
bool
default:"True"
Whether to use endpointing to determine speech segments.
punctuate
bool
default:"True"
Whether to add punctuation to transcripts.
includeRawResponse
bool
default:"True"
Whether to include raw response data from Deepgram.
extra
Mapping[str, Any]
default:"{\"interim_results\": True}"
Additional parameters passed to the Deepgram transcription service.

Usage

DailyTransport connects your Pipecat bot to Daily rooms where it can communicate with participants through audio, video, and data channels. Rooms must be created using the Daily API before your bot can join. The transport integrates with Pipecat’s pipeline to process participant audio through your STT, LLM, and TTS services, then send responses back to participants. See the complete example for a full implementation including:
  • Daily room creation and token management
  • Transport configuration with transcription and VAD
  • Pipeline integration with participant event handling
  • Advanced features like recording and dial-out

Event Handlers

DailyTransport provides event handlers for room lifecycle, participant management, messaging, telephony, and recording. Register handlers using the @event_handler decorator on the transport instance.

Events Summary

EventDescription
on_joinedBot joined the room
on_leftBot left the room
on_before_leaveAbout to leave the room (sync)
on_errorTransport error occurred
on_call_state_updatedCall state changed
on_first_participant_joinedFirst participant joined the room
on_participant_joinedA participant joined
on_participant_leftA participant left
on_participant_updatedA participant’s state updated
on_client_connectedA participant connected
on_client_disconnectedA participant disconnected
on_active_speaker_changedActive speaker changed
on_app_messageApp message received
on_transcription_messageTranscription message received
on_recording_startedRecording started
on_recording_stoppedRecording stopped
on_recording_errorRecording error occurred
on_dialin_connectedDial-in call connected
on_dialin_readyDial-in SIP endpoint ready
on_dialin_stoppedDial-in call stopped
on_dialin_errorDial-in error
on_dialin_warningDial-in warning
on_dialout_answeredDial-out call answered
on_dialout_connectedDial-out call connected
on_dialout_stoppedDial-out call stopped
on_dialout_errorDial-out error
on_dialout_warningDial-out warning

Room Lifecycle

on_joined

Fired when the bot successfully joins the Daily room.
@transport.event_handler("on_joined")
async def on_joined(transport, data):
    print(f"Bot joined the room: {data}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
datadictJoin event data from Daily

on_left

Fired when the bot leaves the Daily room.
@transport.event_handler("on_left")
async def on_left(transport):
    print("Bot left the room")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance

on_before_leave

Fired synchronously just before the bot leaves the room. Use this for cleanup that must happen before disconnection, such as stopping transcription.
@transport.event_handler("on_before_leave")
async def on_before_leave(transport):
    print("About to leave the room...")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
This is a synchronous event — the bot will not leave the room until all handlers complete. Keep handlers fast.

on_error

Fired when a transport-level error occurs.
@transport.event_handler("on_error")
async def on_error(transport, error):
    print(f"Transport error: {error}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
errorstrError message

on_call_state_updated

Fired when the call state changes (e.g., joining, joined, leaving, left).
@transport.event_handler("on_call_state_updated")
async def on_call_state_updated(transport, state):
    print(f"Call state: {state}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
statestrThe new call state

Participants

on_first_participant_joined

Fired when the first participant (other than the bot) joins the room. This is commonly used to start the conversation.
@transport.event_handler("on_first_participant_joined")
async def on_first_participant_joined(transport, participant):
    await task.queue_frame(TTSSpeakFrame("Hello! How can I help you today?"))
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
participantdictParticipant data from Daily

on_participant_joined

Fired when any participant joins the room.
@transport.event_handler("on_participant_joined")
async def on_participant_joined(transport, participant):
    print(f"Participant joined: {participant['id']}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
participantdictParticipant data from Daily
When a participant joins, both on_participant_joined and on_client_connected fire. Use on_first_participant_joined if you only need to react to the first participant.

on_participant_left

Fired when a participant leaves the room.
@transport.event_handler("on_participant_left")
async def on_participant_left(transport, participant, reason):
    print(f"Participant {participant['id']} left: {reason}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
participantdictParticipant data from Daily
reasonstrReason the participant left

on_participant_updated

Fired when a participant’s state changes (e.g., audio/video tracks enabled/disabled).
@transport.event_handler("on_participant_updated")
async def on_participant_updated(transport, participant):
    print(f"Participant updated: {participant['id']}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
participantdictUpdated participant data from Daily

on_client_connected / on_client_disconnected

Transport-agnostic aliases that fire alongside on_participant_joined and on_participant_left respectively, for compatibility with other transports. Same parameters as their counterparts.
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, participant):
    print(f"Client connected: {participant['id']}")

on_active_speaker_changed

Fired when the active speaker in the room changes.
@transport.event_handler("on_active_speaker_changed")
async def on_active_speaker_changed(transport, participant):
    print(f"Active speaker: {participant['id']}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
participantdictActive speaker participant data

Messaging

on_app_message

Fired when an app message is received from a participant.
@transport.event_handler("on_app_message")
async def on_app_message(transport, message, sender):
    print(f"Message from {sender}: {message}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
messageAnyThe message content
senderstrThe sender’s participant ID

on_transcription_message

Fired when a transcription message is received from Daily’s built-in transcription service.
@transport.event_handler("on_transcription_message")
async def on_transcription_message(transport, message):
    print(f"Transcription: {message['text']}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
messagedictTranscription message with text, participantId, timestamp, and rawResponse fields

Recording

on_recording_started / on_recording_stopped / on_recording_error

Events for monitoring Daily’s built-in recording feature.
@transport.event_handler("on_recording_started")
async def on_recording_started(transport, status):
    print(f"Recording started: {status}")

@transport.event_handler("on_recording_error")
async def on_recording_error(transport, stream_id, message):
    print(f"Recording error for {stream_id}: {message}")
Parameters:
EventParameters
on_recording_startedtransport, status (str)
on_recording_stoppedtransport, stream_id (str)
on_recording_errortransport, stream_id (str), message (str)

Telephony: Dial-in

Events for monitoring incoming phone calls. See the telephony guides for setup details.

on_dialin_ready

Fired when the dial-in SIP endpoint is ready to receive calls. If dialin_settings are configured, Pipecat automatically calls the Daily pinlessCallUpdate API.
@transport.event_handler("on_dialin_ready")
async def on_dialin_ready(transport, sip_endpoint):
    print(f"Dial-in ready at: {sip_endpoint}")
Parameters:
ParameterTypeDescription
transportDailyTransportThe transport instance
sip_endpointstrThe SIP endpoint URI

on_dialin_connected / on_dialin_stopped / on_dialin_error / on_dialin_warning

Lifecycle events for dial-in calls. All receive (transport, data) where data is a dict with event details.
@transport.event_handler("on_dialin_connected")
async def on_dialin_connected(transport, data):
    print(f"Dial-in connected: {data}")

@transport.event_handler("on_dialin_error")
async def on_dialin_error(transport, data):
    print(f"Dial-in error: {data}")

Telephony: Dial-out

Events for monitoring outgoing phone calls. All receive (transport, data) where data is a dict with event details.
EventDescription
on_dialout_answeredDial-out call was answered
on_dialout_connectedDial-out call connected
on_dialout_stoppedDial-out call stopped
on_dialout_errorDial-out error occurred
on_dialout_warningDial-out warning
@transport.event_handler("on_dialout_answered")
async def on_dialout_answered(transport, data):
    print(f"Dial-out answered: {data}")

@transport.event_handler("on_dialout_error")
async def on_dialout_error(transport, data):
    print(f"Dial-out error: {data}")

Additional Resources