> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daily.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting started with the Daily Python SDK

> An overview of daily-python functionality with examples for joining meetings, handling events, and sending and receiving media.

<Card icon="cat" href="https://docs.pipecat.ai/pipecat/get-started/quickstart" title="Pipecat Quickstart">
  Building a voice or multimodal AI agent? [Pipecat](https://www.pipecat.ai/) is built on top of `daily-python` and is the faster path — see the [Pipecat Quickstart guide](https://docs.pipecat.ai/pipecat/get-started/quickstart).
</Card>

## Installation

See the [installation guide](/docs/python/installation) for setup instructions.

## Core concepts

### Initializing

[`daily.Daily.init()`](https://reference-python.daily.co/api_reference.html#daily.Daily.init)

Before using the SDK, initialize the `Daily` context:

```python theme={null}
from daily import *
Daily.init()
```

### Creating a call client

[`daily.CallClient()`](https://reference-python.daily.co/api_reference.html#daily.CallClient)

Most SDK functionality lives in the `CallClient` class. Create one after initializing:

```python theme={null}
client = CallClient()
```

### Releasing a call client

[`daily.CallClient.release()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.release)

Once the client is no longer needed, explicitly release its internal resources. This is important when the client holds a circular reference (e.g. via an event handler — see [Handling events](#handling-events) below).

```python theme={null}
client.release()
```

### Joining a meeting

[`daily.CallClient.join()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.join)

Join a Daily meeting with its URL:

```python theme={null}
client.join("https://my.daily.co/meeting")
```

To join a private room or join as the meeting owner, pass a [meeting token](/reference/rest-api/meeting-tokens/create-meeting-token):

```python theme={null}
client.join("https://my.daily.co/meeting", meeting_token="MY_TOKEN")
```

### Leaving a meeting

[`daily.CallClient.leave()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.leave)

Always leave the meeting when done to clean up network connections:

```python theme={null}
client.leave()
```

### Setting the user name

[`daily.CallClient.set_user_name()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.set_user_name)

```python theme={null}
client.set_user_name("Jane Doe")
```

### Setting client permissions

Meeting owners can control whether participants have presence in a meeting, can send media, or can manage other participants. Permissions can be set dynamically from within a meeting or configured in advance with a [meeting token](/reference/rest-api/meeting-tokens/create-meeting-token).

A common use case for `daily-python` is to export media from a call as a hidden participant. To do this, use the REST API to create a meeting token with the [`permissions`](/reference/rest-api/meeting-tokens/create-meeting-token#body-properties-permissions) object's `hasPresence` set to `false`, then pass the resulting JWT to `join()`:

```python theme={null}
client.join(
    "https://my.daily.co/meeting",
    meeting_token="MY_TOKEN")
```

### Completion callbacks

Some `CallClient` methods are asynchronous. Pass an optional callback to be notified when they complete:

```python theme={null}
def on_joined(join_data, error):
    if not error:
        print("We just joined the meeting!")

client.join("https://my.daily.co/meeting", completion=on_joined)
```

### Handling events

To listen and react to various meeting events, such as participant updates, recordings started or ended, etc., simply subclass [`daily.EventHandler`](https://reference-python.daily.co/api_reference.html#daily.EventHandler) and implement the relevant event handler methods. For example:

```python theme={null}
class MyApp(EventHandler):

    def on_participant_joined(self, participant):
        print("New participant joined!")
```

Then, register the event handler when creating the call client:

```python theme={null}
class MyApp(EventHandler):

    def __init__(self):
        self.client = CallClient(event_handler=self)
```

Note the circular reference between `MyApp` and the client — make sure to call `client.release()` during cleanup.

## Inputs and publishing

**Inputs** control devices — whether a camera is enabled and at what resolution, or which microphone is selected.

**Publishing settings** control whether the input is being sent, and at what quality. A camera can be enabled via inputs but not published (i.e. not sent to other participants).

See [`daily.CallClient.inputs`](https://reference-python.daily.co/api_reference.html#daily.CallClient.inputs) and [`daily.CallClient.publishing`](https://reference-python.daily.co/api_reference.html#daily.CallClient.publishing) for details.

## Subscriptions and subscription profiles

**Subscriptions** define which media you receive, from which participants, and the quality you receive it at — for example, you may subscribe to audio from all participants but only subscribe to video from specific ones or you may only subscribe to low-quality video from certain participants.

**Subscription profiles** give a named set of subscription settings. The built-in `base` profile is applied to all remote participants' camera and microphone streams by default.

### Updating subscription profiles

Update the `base` profile to change default subscriptions for all participants — for example, to subscribe to microphone only:

```python theme={null}
client.update_subscription_profiles({
    "base": {
        "camera": "unsubscribed",
        "microphone": "subscribed"
    }
})
```

Define additional profiles to handle different quality tiers:

```python theme={null}
client.update_subscription_profiles({
    "lower": {
        "camera": {
            "subscriptionState": "subscribed",
            "settings": { "maxQuality": "low" }
        },
        "microphone": "unsubscribed"
    },
    "higher": {
        "camera": {
            "subscriptionState": "subscribed",
            "settings": { "maxQuality": "high" }
        },
        "microphone": "unsubscribed"
    }
})
```

### Updating subscriptions for participants

Update a specific participants' subscriptions to use a custom or `"base"` profile:

```python theme={null}
client.update_subscriptions({
    "eb762a39-1850-410e-9b31-92d7b21d515c": {
        "profile": "higher",
    },
    "2aa78bc2-1a0b-4f2b-8447-baa6a95bca1a": {
        "profile": "base"
    }
})
```

Or override specific settings for a participant:

```python theme={null}
client.update_subscriptions({
    "eb762a39-1850-410e-9b31-92d7b21d515c": {
        "profile": "base",
        "media": {
            "camera": "unsubscribed"
        }
    },
})
```

You can update subscriptions profiles and participant subscriptions in a single call:

```python theme={null}
client.update_subscriptions({
    "eb762a39-1850-410e-9b31-92d7b21d515c": {
        "profile": "base",
        "media": {
            "camera": "subscribed"
        }
    }
}, {
    "base": {
        "camera": "unsubscribed",
        "microphone": "subscribed"
    },
})
```

## Sending media

`daily-python` supports virtual video and audio devices for simulating cameras, speakers, and microphones.

### Sending video

Cameras are used to send video into the meeting. A camera is a live stream, so it needs to generate images at a certain framerate.

To start, we need to create a virtual camera with a certain width, height, and an optional color format (frames written to the camera should then be in this color format):

```python theme={null}
camera = Daily.create_camera_device("my-camera",
    width = 1024,
    height = 1024,
    color_format = "RGB")
```

Once the camera is selected, we need to choose it as our default camera input. This is done through the call client input settings:

```python theme={null}
client.update_inputs({
    "camera": {
        "isEnabled": True,
        "settings": {
            "deviceId": "my-camera"
        }
    }
})
```

Finally, we can just write frames to the camera which are then sent as the call client video stream. In the following example, we load a PNG file (using the [Pillow](https://pillow.readthedocs.io) library) in RGB format and we send it 30 times per second.

```python theme={null}
from PIL import Image
im = Image.open("image.png")
while True:
    camera.write_frame(im.tobytes())
    time.sleep(0.033)
```

See [`daily.Daily.create_camera_device`](https://reference-python.daily.co/api_reference.html#daily.Daily.create_camera_device) and [`daily.CallClient.update_inputs`](https://reference-python.daily.co/api_reference.html#daily.CallClient.update_inputs) for more details.

### Sending audio

Create a virtual microphone and write audio frames to it, similar to the virtual camera:

```python theme={null}
microphone = Daily.create_microphone_device("my-mic", sample_rate=16000, channels=1)

client.update_inputs({
    "camera": False,
    "microphone": {
        "isEnabled": True,
        "settings": { "deviceId": "my-mic" }
    }
})

# After joining, write audio frames
microphone.write_frames(frames)
```

See [`daily.Daily.create_microphone_device`](https://reference-python.daily.co/api_reference.html#daily.Daily.create_microphone_device) and [`daily.CallClient.update_inputs`](https://reference-python.daily.co/api_reference.html#daily.CallClient.update_inputs) for more details.

<Note>
  If you are using multiple call clients, where each need their own microphone, create separate processes. Multiple microphones can exist simultaneously, but only one can be active per client.
</Note>

## Receiving media

### Receiving video

[`daily.CallClient.set_video_renderer()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.set_video_renderer)

Register a callback to receive video frames from a specific participant:

```python theme={null}
client.set_video_renderer(PARTICIPANT_ID, on_video_frame)

def on_video_frame(participant_id, video_frame):
    print(f"New frame from {participant_id}")
```

`video_frame` is a [`daily.VideoFrame`](https://reference-python.daily.co/api_reference.html#daily.VideoFrame).

### Receiving audio

Audio can be received from an individual participant or from all meeting participants in a single mixed track.

For individual participant audio, register a callback using [`daily.CallClient.set_audio_renderer()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.set_audio_renderer):

```python theme={null}
client.set_audio_renderer(PARTICIPANT_ID, on_audio_data)

def on_audio_data(participant_id, audio_data):
    print(f"New audio data from {participant_id}")
```

`audio_data` is a [`daily.AudioData`](https://reference-python.daily.co/api_reference.html#daily.AudioData).

#### Receiving mixed audio

Create a virtual speaker to receive mixed audio from all meeting participants:

```python theme={null}
speaker = Daily.create_speaker_device("my-speaker", sample_rate=16000, channels=1)
Daily.select_speaker_device("my-speaker")

# After joining, read audio frames (e.g. every 10ms)
while True:
    buffer = speaker.read_frames(160)
    time.sleep(0.01)
```

Audio is 16-bit linear PCM.

See [`daily.Daily.create_speaker_device`](https://reference-python.daily.co/api_reference.html#daily.Daily.create_speaker_device) and [`daily.Daily.select_speaker_device`](https://reference-python.daily.co/api_reference.html#daily.Daily.select_speaker_device) for more details.

## Transcription

[`start_transcription()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.start_transcription)\
[`stop_transcription()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.stop_transcription)

Room owners or participants with the `'transcription'` [canAdmin permission](/reference/rest-api/meeting-tokens/create-meeting-token#body-properties-permissions-can-admin-one-of-0) can start and stop transcription:

```python theme={null}
client.start_transcription()
```

Optional configuration settings:

| Name                 | Type             | Description                                                                                     |
| -------------------- | ---------------- | ----------------------------------------------------------------------------------------------- |
| `language`           | `str`            | See [Deepgram language docs](https://developers.deepgram.com/docs/language)                     |
| `model`              | `str`            | See [Deepgram model docs](https://developers.deepgram.com/docs/model)                           |
| `profanity_filter`   | `bool`           | See [Deepgram profanity filter docs](https://developers.deepgram.com/docs/profanity-filter)     |
| `redact`             | `bool` or `list` | See [Deepgram redaction docs](https://developers.deepgram.com/docs/redaction)                   |
| `extra`              | `dict`           | Additional Deepgram [streaming options](https://developers.deepgram.com/docs/features-overview) |
| `includeRawResponse` | `bool`           | Whether to include Deepgram's raw response in transcription messages                            |

```python theme={null}
client.start_transcription({
    'language': 'fr-CA',
    'model': 'meeting',
})
```

Listen for transcription events via [`on_transcription_message`](https://reference-python.daily.co/api_reference.html#daily.EventHandler.on_transcription_message), [`on_transcription_started`](https://reference-python.daily.co/api_reference.html#daily.EventHandler.on_transcription_started), and [`on_transcription_stopped`](https://reference-python.daily.co/api_reference.html#daily.EventHandler.on_transcription_stopped).

Stop transcription with:

```python theme={null}
client.stop_transcription()
```

## Recording

[`daily.CallClient.start_recording()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.start_recording)\
[`daily.CallClient.stop_recording()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.stop_recording)

With [recording enabled](/reference/rest-api/rooms/update-room#body-properties-enable-recording-one-of-0) on the room, you can start/stop a cloud recording from your Python client:

```python theme={null}
client.start_recording()
client.stop_recording()
```

Multiple recording sessions can run simultaneously by specifying a unique `stream_id` UUID. For layout options, see the [recording layout reference](/reference/daily-js/types/daily-streaming-layout-config).

See also Daily's [recording guide](/docs/guides/features/recording) for more details on recording features and capabilities.

## Chatting with Prebuilt Clients

[`send_prebuilt_chat_message()`](https://reference-python.daily.co/api_reference.html#daily.CallClient.send_prebuilt_chat_message)

When participants are in a [Daily Prebuilt](/docs/prebuilt) call, your Python client can send messages to Prebuilt's chat like so:

```python theme={null}
client.send_prebuilt_chat_message("Hello, world", "Daily Python Bot")
```

## Reference

Full API reference, types, and method signatures: [reference-python.daily.co](https://reference-python.daily.co/api_reference.html)
