Setup Zoom Websockets
AnthropicOfficialCreated by ZoomDistributed by Anthropic
- Skill
- Tool integration
- Automation and integrations
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a reference for integrating Zoom WebSockets to receive real-time event notifications. It covers the architectural differences between WebSockets and webhooks, setup requirements via the Zoom Marketplace, and implementation details for connection management, including authentication, keep-alive heartbeats, and reconnection strategies.
What it does
- Explains the technical trade-offs between Zoom WebSockets and webhooks.
- Provides a step-by-step guide to configuring WebSocket subscriptions in the Zoom Marketplace.
- Includes code patterns for authenticating via Server-to-Server OAuth.
- Demonstrates how to establish and maintain a persistent WebSocket connection.
- Outlines best practices for connection heartbeats and automatic reconnection logic.
- Lists common event types available through the WebSocket stream.
When to use it
- When your application requires real-time, low-latency event updates.
- When security requirements prevent the use of public webhook endpoints.
- When you need to avoid the overhead of individual HTTP requests for every event.
- When you require a stateful, bidirectional communication channel with Zoom.
Advantages
- Lower latency compared to traditional webhook polling or push models.
- Eliminates the need to expose and secure public-facing webhook endpoints.
- Provides a persistent, stateful connection for reliable event delivery.
- Supports secure, direct communication between your server and Zoom.
Usage examples
- “How do I connect to Zoom WebSockets?”
- The skill provides a Node.js implementation using the 'ws' library, showing how to fetch an S2S OAuth token and initialize the WebSocket connection.
- “Should I use webhooks or WebSockets for Zoom events?”
- The skill includes a comparison table highlighting that WebSockets are better for low-latency and high-security needs, while webhooks are simpler for basic event notifications.
- “How do I keep my Zoom WebSocket connection alive?”
- The skill provides a code snippet for implementing a 30-second heartbeat ping to prevent Zoom from closing idle connections.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/anthropics/setup-zoom-websockets/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip setup-zoom-websockets.zip -d .agents/skills
Documentation by Zoom
/setup-zoom-websockets
Background reference for persistent Zoom event streams. Prefer workflow routing first, then use this file when WebSockets are plausibly better than webhooks.
WebSockets vs Webhooks
| Aspect | WebSockets | Webhooks |
|---|---|---|
| Connection | Persistent, bidirectional | One-time HTTP POST |
| Latency | Lower (no HTTP overhead) | Higher (new connection per event) |
| Security | Direct connection, no exposed endpoint | Requires endpoint validation, IP whitelisting |
| Model | Pull (you connect to Zoom) | Push (Zoom connects to you) |
| State | Stateful (maintains connection) | Stateless (each event independent) |
| Setup | More complex (access token, connection) | Simpler (just endpoint URL) |
Choose WebSockets when:
Real-time, low-latency updates are critical
Security is paramount (banking, healthcare, finance)
You don't want to expose a public endpoint
You need bidirectional communication
Choose Webhooks when:
Simpler setup is preferred
Small number of event notifications
Existing HTTP infrastructure
Prerequisites
Server-to-Server OAuth app in Zoom Marketplace
Account ID, Client ID, and Client Secret
WebSocket subscription with events enabled
Need help with S2S OAuth? See the zoom-oauth skill for complete authentication flows.
Start troubleshooting fast: Use the 5-Minute Runbook before deep debugging.
Quick Start
1. Create Server-to-Server OAuth App
Go to Zoom Marketplace
Create a Server-to-Server OAuth app
Copy Account ID, Client ID, Client Secret
2. Enable WebSocket Subscription
In your app, go to Feature → Event Subscriptions
Add an Event Subscription
Select WebSockets as the method type
Select events to subscribe to (e.g.,
meeting.created,meeting.started)Save - an endpoint URL will be generated
3. Connect via WebSocket
const WebSocket = require('ws');
const axios = require('axios');
// Step 1: Get access token
async function getAccessToken() {
const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
const response = await axios.post(
'https://zoom.us/oauth/token',
new URLSearchParams({
grant_type: 'account_credentials',
account_id: ACCOUNT_ID
}),
{
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
return response.data.access_token;
}
// Step 2: Connect to WebSocket
async function connectWebSocket() {
const accessToken = await getAccessToken();
// WebSocket URL from your subscription settings
const wsUrl = `wss://ws.zoom.us/ws?subscriptionId=${SUBSCRIPTION_ID}&access_token=${accessToken}`;
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
console.log('WebSocket connection established');
});
ws.on('message', (data) => {
const event = JSON.parse(data);
console.log('Event received:', event.event);
// Handle different event types
switch (event.event) {
case 'meeting.started':
console.log(`Meeting started: ${event.payload.object.topic}`);
break;
case 'meeting.ended':
console.log(`Meeting ended: ${event.payload.object.uuid}`);
break;
case 'meeting.participant_joined':
console.log(`Participant joined: ${event.payload.object.participant.user_name}`);
break;
}
});
ws.on('close', (code, reason) => {
console.log(`Connection closed: ${code} - ${reason}`);
// Implement reconnection logic
});
ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
return ws;
}
connectWebSocket();Event Format
Events received via WebSocket have the same format as webhook events:
{
"event": "meeting.started",
"event_ts": 1706123456789,
"payload": {
"account_id": "abcD3ojkdbjfg",
"object": {
"id": 1234567890,
"uuid": "abcdefgh-1234-5678-abcd-1234567890ab",
"host_id": "xyz789",
"topic": "Team Standup",
"type": 2,
"start_time": "2024-01-25T10:00:00Z",
"timezone": "America/Los_Angeles"
}
}
}Common Events
| Event | Description |
|---|---|
meeting.created | Meeting scheduled |
meeting.updated | Meeting settings changed |
meeting.deleted | Meeting deleted |
meeting.started | Meeting begins |
meeting.ended | Meeting ends |
meeting.participant_joined | Participant joins meeting |
meeting.participant_left | Participant leaves meeting |
recording.completed | Cloud recording ready |
user.created | New user added |
user.updated | User details changed |
Connection Management
Keep-Alive
WebSocket connections require periodic heartbeats. Zoom will close idle connections.
// Send ping every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
}, 30000);Reconnection
Implement automatic reconnection for reliability:
function connectWithReconnect() {
const ws = connectWebSocket();
ws.on('close', () => {
console.log('Connection lost. Reconnecting in 5 seconds...');
setTimeout(connectWithReconnect, 5000);
});
return ws;
}Single Connection Limit
Important: Only ONE WebSocket connection can be open per subscription at a time. Opening a new connection will close the existing one.
Detailed References
references/connection.md - Connection lifecycle, authentication, error handling
references/events.md - Complete event types reference
Troubleshooting
troubleshooting/common-issues.md - Subscription URL confusion, disconnects, no-events debugging
Sample Repositories
Official / Community
| Type | Repository | Description |
|---|---|---|
| Node.js | just-zoomit/zoom-websockets | WebSocket sample with S2S OAuth |
WebSockets vs RTMS
Don't confuse WebSockets with RTMS (Realtime Media Streams):
| Feature | WebSockets | RTMS |
|---|---|---|
| Purpose | Event notifications | Media streams |
| Data | Meeting events, user events | Audio, video, transcripts |
| Use case | React to Zoom events | AI/ML, live transcription |
| Skill | This skill | rtms |
For real-time audio/video/transcript data, use the rtms skill instead.
Resources
WebSockets docs: https://developers.zoom.us/docs/api/websockets/
Webhooks comparison: https://www.zoom.com/en/blog/a-guide-to-webhooks-and-websockets/
Developer forum: https://devforum.zoom.us/
Environment Variables
See references/environment-variables.md for standardized
.envkeys and where to find each value.
Files
- ATTRIBUTION.mdAdded by AutoGineer987 B
- LICENSELicence file added by AutoGineer1.1 KiB
- RUNBOOK.md2.9 KiB
- SKILL.md7.4 KiB
- references/connection.md10.4 KiB
- references/environment-variables.md827 B
- references/events.md10.5 KiB
- troubleshooting/common-issues.md1.1 KiB
LICENSE
MIT License Copyright (c) 2025 Zoom Video Communications, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Requirements and compatibility
Written for: Claude Code, Claude apps
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Zoom
- Publisher
- Anthropic (Official)
- Distributed by
- Anthropic
- Source
- anthropics/knowledge-work-plugins · partner-built/zoom-plugin/skills/websockets · commit e050c2e
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from partner-built/zoom-plugin/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Zoom or Anthropic.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download setup-zoom-websockets.zip