setup-zoom-websockets
Reference skill for Zoom WebSockets. Use after routing to a low-latency event workflow when persistent connections, faster event delivery, or security constraints make WebSockets preferable to webhooks.
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o setup-zoom-websockets.zip https://jpskill.com/download/22724.zip && unzip -o setup-zoom-websockets.zip && rm setup-zoom-websockets.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/22724.zip -OutFile "$d\setup-zoom-websockets.zip"; Expand-Archive "$d\setup-zoom-websockets.zip" -DestinationPath $d -Force; ri "$d\setup-zoom-websockets.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
setup-zoom-websockets.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
setup-zoom-websocketsフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 4
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
/setup-zoom-websockets
永続的な Zoom イベントストリームに関する背景情報です。まずワークフロールーティングを優先し、WebSockets が Webhook よりも明らかに優れている場合にこのファイルを使用してください。
WebSockets と Webhook
| 側面 | WebSockets | Webhook |
|---|---|---|
| 接続 | 永続的、双方向 | 1回限りの HTTP POST |
| レイテンシ | 低い(HTTPオーバーヘッドなし) | 高い(イベントごとに新しい接続) |
| セキュリティ | 直接接続、公開エンドポイントなし | エンドポイント検証、IPホワイトリストが必要 |
| モデル | プル(あなたがZoomに接続) | プッシュ(Zoomがあなたに接続) |
| 状態 | ステートフル(接続を維持) | ステートレス(各イベントは独立) |
| セットアップ | より複雑(アクセストークン、接続) | よりシンプル(エンドポイントURLのみ) |
WebSockets を選択する場合:
- リアルタイムで低レイテンシの更新が不可欠な場合
- セキュリティが最重要視される場合(銀行、医療、金融)
- 公開エンドポイントを公開したくない場合
- 双方向通信が必要な場合
Webhook を選択する場合:
- よりシンプルなセットアップが好ましい場合
- イベント通知の数が少ない場合
- 既存の HTTP インフラストラクチャがある場合
前提条件
- Zoom Marketplace の Server-to-Server OAuth アプリ
- アカウント ID、クライアント ID、およびクライアントシークレット
- イベントが有効な WebSocket サブスクリプション
S2S OAuth でお困りですか? 完全な認証フローについては、zoom-oauth スキルをご覧ください。
迅速なトラブルシューティングを開始するには: 詳細なデバッグの前に、5-Minute Runbook を使用してください。
クイックスタート
1. Server-to-Server OAuth アプリを作成する
- Zoom Marketplace にアクセスします
- Server-to-Server OAuth アプリを作成します
- アカウント ID、クライアント ID、クライアントシークレットをコピーします
2. WebSocket サブスクリプションを有効にする
- アプリ内で、Feature → Event Subscriptions に移動します
- イベントサブスクリプションを追加します
- メソッドタイプとして WebSockets を選択します
- サブスクライブするイベントを選択します(例:
meeting.created、meeting.started) - 保存すると、エンドポイント URL が生成されます
3. 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();
イベント形式
WebSocket 経由で受信されるイベントは、Webhook イベントと同じ形式です。
{
"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"
}
}
}
一般的なイベント
| イベント | 説明 |
|---|---|
meeting.created |
ミーティングがスケジュールされました |
meeting.updated |
ミーティング設定が変更されました |
meeting.deleted |
ミーティングが削除されました |
meeting.started |
ミーティングが開始されました |
meeting.ended |
ミーティングが終了しました |
meeting.participant_joined |
参加者がミーティングに参加しました |
meeting.participant_left |
参加者がミーティングを退出しました |
recording.completed |
クラウド録画の準備ができました |
user.created |
新しいユーザーが追加されました |
user.updated |
ユーザーの詳細が変更されました |
接続管理
キープアライブ
WebSocket 接続には定期的なハートビートが必要です。Zoom はアイドル状態の接続を閉じます。
// Send ping every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
}, 30000);
再接続
信頼性のために自動再接続を実装してください。
function connectWithReconnect() {
const ws = connectWebSocket();
ws.on('close', () => {
console.log('Connection lost. Reconnecting in 5 seconds...');
setTimeout(connectWithReconnect, 5000);
});
return ws;
}
単一接続の制限
重要: 1つのサブスクリプションにつき、同時に開ける WebSocket 接続は1つだけです。新しい接続を開くと、既存の接続は閉じられます。
詳細なリファレンス
- references/connection.md - 接続ライフサイクル、認証、エラー処理
- references/events.md - 完全なイベントタイプのリファレンス
トラブルシューティング
- troubleshooting/common-issues.md - サブスクリプション URL の競合
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
/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.
同梱ファイル
※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。
- 📄 SKILL.md (7,553 bytes)
- 📎 references/connection.md (10,632 bytes)
- 📎 references/environment-variables.md (827 bytes)
- 📎 references/events.md (10,793 bytes)