{"id":8923,"library":"daily-python","title":"Daily Client SDK for Python","description":"Daily's Python SDK provides everything needed to build real-time video, audio, and AI-powered voice agents with WebRTC infrastructure. It allows headless bots to connect to Daily rooms and process media and event data streams, supporting various use cases from virtual devices to transcription. The current version is 0.27.0, and the library maintains an active release cadence with frequent updates and new features.","status":"active","version":"0.27.0","language":"en","source_language":"en","source_url":"https://github.com/daily-co/daily-python","tags":["video","audio","webrtc","sdk","real-time","ai","voice-bots"],"install":[{"cmd":"pip install daily-python","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Required runtime environment.","package":"Python","version":">=3.7"},{"reason":"System library dependency for the underlying Rust/C++ core.","package":"glibc","version":">=2.28"}],"imports":[{"symbol":"CallClient","correct":"from daily import CallClient"},{"symbol":"Daily","correct":"from daily import Daily"},{"symbol":"EventHandler","correct":"from daily import EventHandler"},{"symbol":"LogLevel","correct":"from daily import LogLevel"},{"symbol":"CustomAudioSource","correct":"from daily import CustomAudioSource"},{"symbol":"CustomVideoTrack","correct":"from daily import CustomVideoTrack"}],"quickstart":{"code":"import os\nimport time\nimport threading\nfrom daily import Daily, CallClient, EventHandler, LogLevel\n\n# Replace with your Daily room URL and token (optional)\nDAILY_ROOM_URL = os.environ.get('DAILY_ROOM_URL', 'https://your-domain.daily.co/your-room')\nDAILY_TOKEN = os.environ.get('DAILY_TOKEN', None)\n\nclass MyEventHandler(EventHandler):\n    def on_participant_joined(self, participant):\n        print(f\"Participant joined: {participant['info']['userName']} (ID: {participant['id']})\")\n\n    def on_participant_left(self, participant, reason):\n        print(f\"Participant left: {participant['info']['userName']} (ID: {participant['id']}) - Reason: {reason}\")\n\n    def on_joined_meeting(self, data, error):\n        if error:\n            print(f\"Failed to join meeting: {error}\")\n            self.join_event.set() # Signal completion even on error\n        else:\n            print(\"Successfully joined the meeting!\")\n            self.join_event.set()\n\n    def on_error(self, error):\n        print(f\"An error occurred in the Daily SDK: {error}\")\n\n    def set_join_event(self, event):\n        self.join_event = event\n\n\ndef main():\n    # Initialize the Daily SDK with optional logging\n    Daily.init(log_level=LogLevel.INFO)\n    print(\"Daily SDK initialized.\")\n\n    event_handler = MyEventHandler()\n    client = CallClient(event_handler=event_handler)\n\n    join_completion_event = threading.Event()\n    event_handler.set_join_event(join_completion_event)\n\n    print(f\"Attempting to join room: {DAILY_ROOM_URL}\")\n    client.join(\n        meeting_url=DAILY_ROOM_URL,\n        meeting_token=DAILY_TOKEN,\n        completion=event_handler.on_joined_meeting\n    )\n\n    # Wait for the join operation to complete\n    join_completion_event.wait(timeout=30) # Wait up to 30 seconds\n\n    if join_completion_event.is_set() and client.is_joined():\n        print(\"Client is active in the meeting. Waiting for 10 seconds...\")\n        time.sleep(10) # Stay in the meeting for a short period\n\n        print(\"Leaving meeting...\")\n        leave_completion_event = threading.Event()\n        client.leave(completion=lambda data, error: leave_completion_event.set())\n        leave_completion_event.wait(timeout=10)\n        print(\"Left meeting.\")\n    else:\n        print(\"Failed to join meeting or timed out.\")\n\n    client.release()\n    Daily.deinit()\n    print(\"Daily SDK deinitialized.\")\n\nif __name__ == \"__main__\":\n    main()","lang":"python","description":"This quickstart initializes the Daily Python SDK, sets up a basic event handler to respond to participant events, creates a `CallClient`, and joins a Daily meeting room. It uses environment variables for the room URL and token for security and ease of configuration. The example includes graceful joining and leaving of a meeting."},"warnings":[{"fix":"Update your completion callbacks to expect two arguments: `(id, error)` instead of `(error)`.","message":"The callback signatures for `CallClient.start_dialout()` and `CallClient.start_recording()` changed in `v0.21.0`. They now return `(session_id, error)` and `(stream_id, error)` respectively, instead of just `error`.","severity":"breaking","affected_versions":">=0.21.0"},{"fix":"If specific silence control is needed, instantiate `CustomAudioSource(..., auto_silence=False)`.","message":"The `CustomAudioSource` constructor's `auto_silence` parameter now defaults to `True` in `v0.27.0`. This means silence is automatically sent when no audio frames are being written. If you need precise control over when audio is sent (e.g., to send no audio when idle), explicitly set `auto_silence=False`.","severity":"gotcha","affected_versions":">=0.27.0"},{"fix":"Always check the `error` parameter in completion callbacks and handle potential `None` values for data parameters if an error occurs. Use `threading.Event` or similar mechanisms for synchronization if your application flow depends on async operation completion.","message":"Asynchronous operations like `client.join()`, `start_recording()`, and `start_dialout()` use completion callbacks. Forgetting to handle the `error` parameter or assuming success can lead to silent failures or `AttributeError` if attempting to process `None` data.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure `daily-python` is installed (`pip install daily-python`) and import statements are `from daily import CallClient` (or other specific symbols). Verify Python environment activation.","cause":"Attempting to import `CallClient` (or other core classes) from a wrong path, or the `daily-python` package is not correctly installed or in the Python path.","error":"ImportError: cannot import name 'CallClient' from 'daily'"},{"fix":"Double-check `DAILY_ROOM_URL` and `DAILY_TOKEN`. Ensure your Daily domain settings allow the client to join. Check network connectivity. Review the `error` message in the `on_joined_meeting` callback for specific diagnostics.","cause":"Common causes include an invalid `meeting_url` or `meeting_token`, network connectivity issues, or domain configuration problems (e.g., meeting not enabled, permissions).","error":"Failed to join meeting: Daily error: <specific error message>"},{"fix":"Before accessing fields on callback parameters, add a check to ensure the object is not `None` and that no error was reported. For example, `if data and not error:`.","cause":"This typically occurs in a callback when you attempt to access a dictionary-like property (e.g., `participant['info']`) on an object that is `None`. This usually means an error occurred in the preceding asynchronous operation, and the data object was `None` instead of the expected payload.","error":"TypeError: 'NoneType' object is not subscriptable"}]}