This example receives audio, video, and transcript data from a Zoom Video SDK session through RTMS. It routes incoming media by msg_type and logs connection and media metadata rather than writing media files.
- Python 3.7 or higher
- Zoom Video SDK credentials (SDK Key and Secret)
- Install the required dependencies:
pip install -r requirements.txt- Create a
.envfile in the same directory with your Zoom credentials:
ZOOM_SECRET_TOKEN=your_secret_token
ZOOM_CLIENT_ID=your_client_id
ZOOM_CLIENT_SECRET=your_client_secret
- Start the server:
gunicorn --bind 0.0.0.0:3000 index:app
# For local development only:
python3 index.py- The server will start on port 3000. You'll need to expose this port to the internet using a tool like ngrok:
ngrok http 3000-
Configure your Video SDK app's webhook URL to point to your exposed endpoint (e.g.,
https://your-ngrok-url/webhook) -
Start a Video SDK session and begin streaming. The server will classify incoming audio, video, and transcript messages and log their metadata.
.
├── index.py # Main entry point that handles webhook events, WebSocket connections, and media processing
├── .env # Secrets and config variables (not committed)
├── .env.example # Template for environment variables
├── requirements.txt # Dependencies
├── readme.md # This file
├── .gitignore # Git ignore rules
├── __pycache__/ # Python bytecode (not committed)
└── venv/ # Virtual environment (not committed)
This sample is implemented as a single index.py file that contains all the functionality:
- Environment Configuration - Loads settings from .env file
- HTTP Server - Flask server handling webhook endpoints
- WebSocket Management - Handles signaling and media connections to Zoom
- Media Processing - Processes incoming audio, video, and transcript data
- Client Broadcast - Forwards events to clients
System Communication
┌──────────────┐
│ Zoom SDK │ ─────► HTTP Webhooks
└──────────────┘ (session events)
│
▼
┌──────────────┐
│ index.py │◄────────── WebSocket connections
└──────────────┘ (signaling + media streams)
│
▼
┌──────────────┐
│ Client Apps │ ◄───────── Real-time data
└──────────────┘ (processed media streams)
- The server listens for Video SDK webhook events from Zoom
- When the session starts, it establishes WebSocket connections to Zoom's signaling and media servers
- Audio, Video and Transcript data is received through the media WebSocket connection
- The audio/video/transcript msg type is printed to the console
- Keep the
.envfile secret and do not commit to version control. - In production, run behind HTTPS and validate webhook signatures.
- This is a basic example that checks the msg type and prints the data type received. In a production environment, you would typically process or save this data.
- The server handles both signaling and media WebSocket connections
- Keep-alive messages are automatically responded to maintain the connection
The project runs the Python Video SDK RTMS webhook and media receiver. Its multi-stage Dockerfile keeps build tooling out of the final runtime image and does not hard-code a CPU architecture.
Build and run it from the rtms-samples repository root:
docker build -f video-sdk/vsdk_working_python/Dockerfile -t rtms-video-sdk-vsdk_working_python .
docker run --rm --env-file video-sdk/vsdk_working_python/.env -p 3000:3000 rtms-video-sdk-vsdk_working_pythonRun the build from the repository root because the Dockerfile uses repository-relative paths. Runtime secrets are supplied with --env-file and are excluded from the image build context.
Normal Zoom webhook deliveries are verified against the exact raw request body using
x-zm-signature and x-zm-request-timestamp. Configure ZOOM_SECRET_TOKEN with the
Marketplace app's webhook Secret Token. Requests with missing, invalid, or stale
signatures are rejected; the default replay window is 300 seconds and can be changed
with WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS.