This project demonstrate transcription generation using the Zoom RTMS (Real-Time Meeting Service). It focuses on capturing transcript data and generating VTT (Web Video Text Tracks), SRT (SubRip Subtitle), and plain text transcripts from Zoom meetings.
Before running the application, ensure you have the following environment variables set in a .env file:
ZOOM_SECRET_TOKEN: Secret token for URL validationZOOM_CLIENT_ID: Zoom client IDZOOM_CLIENT_SECRET: Zoom client secret
PORT: The port on which the Express server runs (default: 3000)
The application follows this sequence:
- Starts an Express server on port 3000
- Listens for webhook events at
/webhookendpoint - Handles URL validation challenges from Zoom
- When a meeting starts:
- Receives
meeting.rtms_startedevent - Establishes WebSocket connection to signaling server
- Sends handshake with authentication signature
- Receives media server URL from signaling server
- Establishes WebSocket connection to media server
- Sends media handshake with authentication
- Begins receiving transcript data
- Receives
- During the meeting:
- Maintains WebSocket connections with keep-alive messages
- Receives transcript data, format and saves them in popular transcript format
- Handles any connection errors
- When a meeting ends:
- Receives
meeting.rtms_stoppedevent - Closes all active WebSocket connections
- Receives
-
Start the server:
node index.js
-
Start a Zoom meeting. The application will:
- Receive the
meeting.rtms_startedevent - Establish WebSocket connections
- Begin capturing transcript data
- Append the transcript data to popular format such as vtt, srt and txt
- Receive the
- Real-time transcript data capture
- WebSocket connection management for both signaling and media servers
- MeetingUuid based folder creation and unique filenames
- Keep-alive message handling
- Error handling for WebSocket connections
- URL validation handling
- The application processes and saves transcript data utilizing absolute timestamp and relative timestamp
- Server runs on port 3000 by default, if PORT is not specificed in .env
- Webhook endpoint is available at
http://localhost:3000/webhook - Requires FFmpeg to be installed and accessible in your PATH
- Node.js (v14 or higher recommended)
- ngrok for exposing your local server to the internet
- Zoom App configuration with RTMS scopes enabled
-
No Transcript Files Generated:
- Verify recordings folder is present in your root folder
- Check that the Zoom app has the correct RTMS scopes
- Ensure the webhook URL is correctly configured in the Zoom app
-
Connection Issues:
- Verify ngrok is running and the tunnel is active
- Check that the Zoom app credentials in
.envare correct - Ensure the webhook endpoint is accessible from the internet
The project saves RTMS transcript events to local storage. 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 transcript/save_transcript_sdk/Dockerfile -t rtms-transcript-save_transcript_sdk .
docker run --rm --env-file transcript/save_transcript_sdk/.env -e ZM_RTMS_PORT=8080 -p 8080:8080 rtms-transcript-save_transcript_sdkRun 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 ZM_RTMS_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.