jpskill.com
🛠️ 開発・MCP コミュニティ

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.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
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
🪟 Windows (PowerShell)
$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. 1. 下の青いボタンを押して setup-zoom-websockets.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → setup-zoom-websockets フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

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 アプリを作成する

  1. Zoom Marketplace にアクセスします
  2. Server-to-Server OAuth アプリを作成します
  3. アカウント ID、クライアント ID、クライアントシークレットをコピーします

2. WebSocket サブスクリプションを有効にする

  1. アプリ内で、FeatureEvent Subscriptions に移動します
  2. イベントサブスクリプションを追加します
  3. メソッドタイプとして WebSockets を選択します
  4. サブスクライブするイベントを選択します(例: meeting.createdmeeting.started
  5. 保存すると、エンドポイント 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つだけです。新しい接続を開くと、既存の接続は閉じられます。

詳細なリファレンス

トラブルシューティング

📜 原文 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

  1. Go to Zoom Marketplace
  2. Create a Server-to-Server OAuth app
  3. Copy Account ID, Client ID, Client Secret

2. Enable WebSocket Subscription

  1. In your app, go to FeatureEvent Subscriptions
  2. Add an Event Subscription
  3. Select WebSockets as the method type
  4. Select events to subscribe to (e.g., meeting.created, meeting.started)
  5. 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

Troubleshooting

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

Environment Variables

同梱ファイル

※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。