Встречи Zoom на сайте (Web SDK)
Помогает встроить встречу Zoom в сайт или веб-приложение: на всю страницу или в нужный блок, с подписью, HD-видео и примерами для React.
- Что делает
- Помогает встроить встречу Zoom в сайт или веб-приложение: на всю страницу или в нужный блок, с подписью, HD-видео и примерами для React.
- Когда брать
- Когда нужно встроить встречу Zoom в сайт или веб-приложение (React, Vue, Angular или обычный JavaScript) и настроить её внешний вид.
- Когда не брать
- Если нужны только ссылки на встречи и управление ими через REST или если вы делаете продукт с видеосеансами, не являющимися встречами Zoom.
- Пример запроса
- Встрой встречу Zoom на страницу нашего сайта на React, чтобы клиенты входили в неё, не покидая сайта.
- Нужно подключить
- терминал
- Работает лучше с
- сервер для создания подписи, probe-sdk
Входит в плагин zoom-plugin. В Cowork и Claude Code можно поставить плагин целиком.
Как включить
- Скачайте архив и распакуйте его.
- Положите папку
zoom-meeting-sdk-webв~/.claude/skills/. - Откройте Claude Code и опишите задачу своими словами: Claude подхватит скилл по описанию.
Текст
---
name: zoom-meeting-sdk-web
description: |
Zoom Meeting SDK для веба: встраивай возможности встреч Zoom в веб-приложения. Два варианта интеграции:
Client View (на всю страницу, привычный интерфейс Zoom) и Component View (встраиваемый, API на промисах).
Включает настройку SharedArrayBuffer для HD-видео, режима галереи и виртуальных фонов.
user-invocable: false
triggers:
- "embed meeting web"
- "meeting in react"
- "meeting in nextjs"
- "meeting in vue"
- "meeting in angular"
- "component view"
- "client view"
- "web meeting sdk"
- "javascript meeting"
- "sharedarraybuffer"
---
Zoom Meeting SDK (веб)
Встраивай возможности встреч Zoom в веб-приложения двумя способами: Client View (на всю страницу) или Component View (встраиваемый).
Как реализовать собственный видеоинтерфейс для встречи Zoom в веб-приложении
Используй Meeting SDK Web Component View.
Не используй для этого вопроса Video SDK, если только пользователь явно не создаёт продукт для сеансов, не являющихся встречами.
Минимальная архитектура:
Страница в браузере
-> получить подпись Meeting SDK с бэкенда
-> ZoomMtgEmbedded.createClient()
-> client.init({ zoomAppRoot })
-> client.join({ signature, sdkKey, meetingNumber, userName, password })
-> применить параметры раскладки, стиля и customize вокруг контейнера встроенной встречи
Минимальная реализация:
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
const client = ZoomMtgEmbedded.createClient();
export async function startEmbeddedMeeting(meetingNumber: string, userName: string, password: string) {
const sigRes = await fetch('/api/signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ meetingNumber, role: 0 }),
});
if (!sigRes.ok) throw new Error(`signature_fetch_failed:${sigRes.status}`);
const { signature, sdkKey } = await sigRes.json();
await client.init({
zoomAppRoot: document.getElementById('meetingSDKElement')!,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
customize: {
video: { isResizable: true, popper: { disableDraggable: false } },
},
});
await client.join({
signature,
sdkKey,
meetingNumber,
userName,
password,
});
}
Типичные места сбоев:
- неверный маршрут: Video SDK вместо Meeting SDK Component View
- нет эндпоинта подписи на бэкенде
- неверное поле пароля (здесь
password, а неpassWord) - нет требований OBF/ZAK для встреч вне аккаунта приложения
- нет заголовков для SharedArrayBuffer, когда ожидаются расширенные возможности встреч
Жёсткое правило маршрутизации
Если пользователь хочет собственный видеоинтерфейс для встречи Zoom в веб-приложении, направляй на Component View, а не на Video SDK.
- Meeting SDK Component View = собственный интерфейс для настоящей встречи Zoom
- Video SDK Web = собственный интерфейс для продукта с видеосеансами, не являющимися встречами
Для прямого пути к собственному интерфейсу встречи начни с [component-view/SKILL.md](component-view/SKILL.md).
Впервые с Web SDK? Начни здесь!
Самый быстрый способ освоить SDK:
- Выбери представление - [Client View и Component View](#client-view-vs-component-view) - пойми ключевые архитектурные различия
- Быстрый старт - [Client View](#quick-start-client-view) или [Component View](#quick-start-component-view) - получи работающую встречу за несколько минут
- SharedArrayBuffer - [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) - нужен для HD-видео, режима галереи и виртуальных фонов
- Необязательная предварительная диагностика - [../../probe-sdk/SKILL.md](../../probe-sdk/SKILL.md) - проверь браузер, устройство и сеть до входа
Создаёшь собственную интеграцию?
- Component View даёт API на промисах и встраиваемый интерфейс
- Client View даёт привычный интерфейс Zoom на всю страницу
- Для собственного интерфейса встречи сначала выбирай Component View
- Пример межпродуктовой маршрутизации: [../../general/use-cases/custom-meeting-ui-web.md](../../general/use-cases/custom-meeting-ui-web.md)
- [Поддержка браузеров](concepts/browser-support.md) - матрица возможностей по браузерам
- Точный путь для углублённого изучения: [component-view/SKILL.md](component-view/SKILL.md)
Проблемы?
- Ошибки входа → проверь создание подписи и написание пароля (
passWordилиpassword) - HD-видео не работает → включи заголовки SharedArrayBuffer
- Полная навигация → [SKILL.md](SKILL.md)
Предварительные требования
- Приложение Zoom с учётными данными Meeting SDK из Marketplace
- SDK Key (Client ID) и Secret
- Современный браузер (Chrome, Firefox, Safari, Edge)
- Эндпоинт аутентификации на бэкенде для создания подписи
Нужна помощь с аутентификацией? Создание JWT и подписи описано в скилле [zoom-oauth](../../oauth/SKILL.md). Нужна диагностика перед входом? Подключи [probe-sdk](../../probe-sdk/SKILL.md) перед
init()/join(), чтобы не пускать среды с низкой готовностью.
Необязательная проверка готовности перед входом (Probe SDK)
Для нестабильных сред при первом входе запусти проверки Probe SDK до вызова ZoomMtg.init() или client.join():
- Запусти диагностику разрешений, устройств и сети через Probe.
- Примени политику готовности (
allow,warn,block). - Переходи ко входу через Meeting SDK только при
allowили одобренномwarn.
См. [../../probe-sdk/SKILL.md](../../probe-sdk/SKILL.md) и [../../general/use-cases/probe-sdk-preflight-readiness-gate.md](../../general/use-cases/probe-sdk-preflight-readiness-gate.md).
Client View и Component View
КРИТИЧЕСКОЕ РАЗЛИЧИЕ: это два совершенно разных API с разными схемами работы!
| Аспект | Client View | Component View |
|---|---|---|
| Объект | ZoomMtg (глобальный синглтон) | ZoomMtgEmbedded.createClient() (экземпляр) |
| Стиль API | Колбэки | Промисы |
| Интерфейс | Занимает всю страницу | Встраивается в любой контейнер |
| Параметр пароля | passWord (заглавная W) | password (строчная) |
| События | inMeetingServiceListener() | on()/off() |
| Импорт (npm) | import { ZoomMtg } from '@zoom/meetingsdk' | import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded' |
| CDN | zoom-meeting-{VERSION}.min.js | zoom-meeting-embedded-{VERSION}.min.js |
| Лучше всего подходит для | Быстрой интеграции, стандартного интерфейса Zoom | Собственных раскладок, приложений на React/Vue |
Когда что использовать
Используй Client View, когда:
- Нужен привычный интерфейс встречи Zoom
- Быстрая интеграция важнее настройки
- Встреча на всю страницу вас устраивает
Используй Component View, когда:
- Встречу нужно встроить в определённую область страницы
- Вы создаёте приложения на React/Vue/Angular
- Вам нужен синтаксис async/await на промисах
- Нужно своё позиционирование и изменение размера
Установка
NPM (рекомендуется)
npm install @zoom/meetingsdk --save
CDN
<!-- Dependencies (required for both views) -->
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/lodash.min.js"></script>
<!-- Client View -->
<script src="https://source.zoom.us/zoom-meeting-{VERSION}.min.js"></script>
<!-- OR Component View -->
<script src="https://source.zoom.us/zoom-meeting-embedded-{VERSION}.min.js"></script>
Замени {VERSION} на последнюю версию (например, 3.11.0).
Быстрый старт (Client View)
import { ZoomMtg } from '@zoom/meetingsdk';
// Step 1: Check browser compatibility
console.log('System requirements:', ZoomMtg.checkSystemRequirements());
// Step 2: Preload WebAssembly for faster initialization
ZoomMtg.preLoadWasm();
ZoomMtg.prepareWebSDK();
// Step 3: Load language files (MUST complete before init)
ZoomMtg.i18n.load('en-US');
ZoomMtg.i18n.onLoad(() => {
// Step 4: Initialize SDK
ZoomMtg.init({
leaveUrl: 'https://yoursite.com/meeting-ended',
disableCORP: !window.crossOriginIsolated, // Auto-detect SharedArrayBuffer
patchJsMedia: true, // Auto-apply media dependency fixes
leaveOnPageUnload: true, // Clean up when page unloads
externalLinkPage: './external.html', // Page for external links
success: () => {
// Step 5: Join meeting (note: passWord with capital W!)
ZoomMtg.join({
signature: signature, // From your auth endpoint
meetingNumber: '1234567890',
userName: 'User Name',
passWord: 'meeting-password', // Capital W!
success: (res) => {
console.log('Joined meeting:', res);
// Post-join: Get meeting info
ZoomMtg.getAttendeeslist({});
ZoomMtg.getCurrentUser({
success: (res) => console.log('Current user:', res.result.currentUser)
});
},
error: (err) => {
console.error('Join error:', err);
}
});
},
error: (err) => {
console.error('Init error:', err);
}
});
});
Быстрый старт (Component View)
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
// Create client instance (do this ONCE, not on every render!)
const client = ZoomMtgEmbedded.createClient();
async function startMeeting() {
try {
// Initialize with container element
await client.init({
zoomAppRoot: document.getElementById('meetingSDKElement'),
language: 'en-US',
debug: true, // Enable debug logging
patchJsMedia: true, // Auto-apply media fixes
leaveOnPageUnload: true, // Clean up on page unload
});
// Join meeting (note: password lowercase!)
await client.join({
signature: signature, // From your auth endpoint
sdkKey: SDK_KEY,
meetingNumber: '1234567890',
userName: 'User Name',
password: 'meeting-password', // Lowercase!
});
console.log('Joined successfully!');
} catch (error) {
console.error('Failed to join:', error);
}
}
Эндпоинт аутентификации (обязателен)
Для обоих представлений нужна JWT-подпись с бэкенд-сервера. Никогда не выставляй SDK Secret во фронтенд-коде!
# Clone Zoom's official auth endpoint
git clone https://github.com/zoom/meetingsdk-auth-endpoint-sample --depth 1
cd meetingsdk-auth-endpoint-sample
cp .env.example .env
# Edit .env with your SDK Key and Secret
npm install && npm run start
Создание подписи
В подписи закодированы:
sdkKey(илиclientIdдля новых приложений)meetingNumberrole(0 = участник, 1 = ведущий)iat(метка времени выпуска)exp(метка времени истечения)tokenExp(срок действия токена)
ВАЖНО (март 2026): приложениям, которые входят во встречи вне своего аккаунта, потребуется App Privilege Token (OBF) или токен ZAK. См. [Требования к авторизации](#authorization-requirements-2026-update).
Основной процесс
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Получить подпись│───►│ init() │───►│ join() │
│ (с бэкенда) │ │ (настройка SDK) │ │ (вход) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
success/error success/error
обратный вызов обратный вызов
(или resolve промиса) (или resolve промиса)
Справочник по API Client View
ZoomMtg.init() — основные параметры
ZoomMtg.init({
// Required
leaveUrl: string, // URL to redirect after leaving
// Display Options
showMeetingHeader: boolean, // Show meeting number/topic (default: true)
disableInvite: boolean, // Hide invite button (default: false)
disableRecord: boolean, // Hide record button (default: false)
disableJoinAudio: boolean, // Hide join audio option (default: false)
disablePreview: boolean, // Skip A/V preview (default: false)
// HD Video (requires SharedArrayBuffer)
enableHD: boolean, // Enable 720p (default: true for >=2.8.0)
enableFullHD: boolean, // Enable 1080p for webinars (default: false)
// View Options
defaultView: 'gallery' | 'speaker' | 'multiSpeaker',
// Feature Toggles
isSupportChat: boolean, // Enable chat (default: true)
isSupportCC: boolean, // Enable closed captions (default: true)
isSupportBreakout: boolean, // Enable breakout rooms (default: true)
isSupportPolling: boolean, // Enable polling (default: true)
isSupportQA: boolean, // Enable Q&A for webinars (default: true)
// Cross-Origin
disableCORP: boolean, // For dev without COOP/COEP headers
// Callbacks
success: Function,
error: Function,
});
ZoomMtg.join() — основные параметры
ZoomMtg.join({
// Required
signature: string, // JWT signature from backend
meetingNumber: string | number,
userName: string,
// Authentication
passWord: string, // Meeting password (capital W!)
zak: string, // Host's ZAK token (required to start)
tk: string, // Registration token (if required)
obfToken: string, // App Privilege Token (for 2026 requirement)
// Optional
userEmail: string, // Required for webinars
customerKey: string, // Custom identifier (max 36 chars)
// Callbacks
success: Function,
error: Function,
});
Обработчики событий (Client View)
// User events
ZoomMtg.inMeetingServiceListener('onUserJoin', (data) => {
console.log('User joined:', data);
});
ZoomMtg.inMeetingServiceListener('onUserLeave', (data) => {
console.log('User left:', data);
// data.reasonCode values:
// 0: OTHER
// 1: HOST_ENDED_MEETING
// 2: SELF_LEAVE_FROM_IN_MEETING
// 3: SELF_LEAVE_FROM_WAITING_ROOM
// 4: SELF_LEAVE_FROM_WAITING_FOR_HOST_START
// 5: MEETING_TRANSFER
// 6: KICK_OUT_FROM_MEETING
// 7: KICK_OUT_FROM_WAITING_ROOM
// 8: LEAVE_FROM_DISCLAIMER
});
ZoomMtg.inMeetingServiceListener('onUserUpdate', (data) => {
console.log('User updated:', data);
});
// Meeting status
ZoomMtg.inMeetingServiceListener('onMeetingStatus', (data) => {
// status: 1=connecting, 2=connected, 3=disconnected, 4=reconnecting
console.log('Meeting status:', data.status);
});
// Waiting room
ZoomMtg.inMeetingServiceListener('onUserIsInWaitingRoom', (data) => {
console.log('User in waiting room:', data);
});
// Active speaker detection
ZoomMtg.inMeetingServiceListener('onActiveSpeaker', (data) => {
// [{userId: number, userName: string}]
console.log('Active speaker:', data);
});
// Network quality monitoring
ZoomMtg.inMeetingServiceListener('onNetworkQualityChange', (data) => {
// {level: 0-5, userId, type: 'uplink'}
// 0-1 = bad, 2 = normal, 3-5 = good
if (data.level <= 1) {
console.warn('Poor network quality');
}
});
// Join performance metrics
ZoomMtg.inMeetingServiceListener('onJoinSpeed', (data) => {
console.log('Join speed metrics:', data);
// Useful for performance monitoring dashboards
});
// Chat
ZoomMtg.inMeetingServiceListener('onReceiveChatMsg', (data) => {
console.log('Chat message:', data);
});
// Recording
ZoomMtg.inMeetingServiceListener('onRecordingChange', (data) => {
console.log('Recording status:', data);
});
// Screen sharing
ZoomMtg.inMeetingServiceListener('onShareContentChange', (data) => {
console.log('Share content changed:', data);
});
// Transcription (requires "save closed captions" enabled)
ZoomMtg.inMeetingServiceListener('onReceiveTranscriptionMsg', (data) => {
console.log('Transcription:', data);
});
// Breakout room status
ZoomMtg.inMeetingServiceListener('onRoomStatusChange', (data) => {
// status: 2=InProgress, 3=Closing, 4=Closed
console.log('Breakout room status:', data);
});
Часто используемые методы (Client View)
// Get current user info
ZoomMtg.getCurrentUser({
success: (res) => console.log(res.result.currentUser)
});
// Get all attendees
ZoomMtg.getAttendeeslist({});
// Audio/Video control
ZoomMtg.mute({ userId, mute: true });
ZoomMtg.muteAll({ muteAll: true });
// Chat
ZoomMtg.sendChat({ message: 'Hello!', userId: 0 }); // 0 = everyone
// Leave/End
ZoomMtg.leaveMeeting({});
ZoomMtg.endMeeting({});
// Host controls
ZoomMtg.makeHost({ userId });
ZoomMtg.makeCoHost({ oderId });
ZoomMtg.expel({ userId }); // Remove participant
ZoomMtg.putOnHold({ oderId, bHold: true });
// Breakout rooms
ZoomMtg.createBreakoutRoom({ rooms: [...] });
ZoomMtg.openBreakoutRooms({});
ZoomMtg.closeBreakoutRooms({});
// Virtual background
ZoomMtg.setVirtualBackground({ imageUrl: '...' });
Справочник по API Component View
client.init() — основные параметры
await client.init({
// Required
zoomAppRoot: HTMLElement, // Container element
// Display
language: string, // e.g., 'en-US'
debug: boolean, // Enable debug logging (default: false)
// Media
patchJsMedia: boolean, // Auto-apply media fixes (default: false)
leaveOnPageUnload: boolean, // Clean up on page unload (default: false)
// Video
enableHD: boolean, // Enable 720p
enableFullHD: boolean, // Enable 1080p
// Customization
customize: {
video: {
isResizable: boolean,
viewSizes: { default: { width, height } }
},
meetingInfo: ['topic', 'host', 'mn', 'pwd', 'telPwd', 'invite', 'participant', 'dc', 'enctype'],
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'custom-btn',
onClick: () => {
console.log('Custom button clicked');
}
}
]
}
},
// For ZFG
webEndpoint: string,
assetPath: string, // Custom path for AV libraries (self-hosting)
});
client.join() — основные параметры
await client.join({
// Required
signature: string,
sdkKey: string,
meetingNumber: string | number,
userName: string,
// Authentication
password: string, // Lowercase! (different from Client View)
zak: string, // Host's ZAK token
tk: string, // Registration token
// Optional
userEmail: string,
});
Обработчики событий (Component View)
// Connection state
client.on('connection-change', (payload) => {
// payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'
console.log('Connection:', payload.state);
});
// User events
client.on('user-added', (payload) => {
console.log('Users added:', payload);
});
client.on('user-removed', (payload) => {
console.log('Users removed:', payload);
});
client.on('user-updated', (payload) => {
console.log('Users updated:', payload);
});
// Active speaker
client.on('active-speaker', (payload) => {
console.log('Active speaker:', payload);
});
// Video state
client.on('video-active-change', (payload) => {
console.log('Video active:', payload);
});
// Unsubscribe
client.off('connection-change', handler);
Часто используемые методы (Component View)
// Get current user
const currentUser = client.getCurrentUser();
// Get all participants
const participants = client.getParticipantsList();
// Audio control
await client.mute(true);
await client.muteAudio(userId, true);
// Video control
await client.muteVideo(userId, true);
// Leave
client.leaveMeeting();
// End (host only)
client.endMeeting();
SharedArrayBuffer (КРИТИЧНО для HD)
SharedArrayBuffer включает расширенные возможности:
- видео 720p/1080p
- режим галереи
- виртуальные фоны
- подавление фонового шума
Включение через HTTP-заголовки
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Проверка в браузере
if (typeof SharedArrayBuffer === 'function') {
console.log('SharedArrayBuffer enabled!');
} else {
console.warn('HD features will be limited');
}
// Or check cross-origin isolation
console.log('Cross-origin isolated:', window.crossOriginIsolated);
Настройка под конкретные платформы
См. [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md):
- настройка Vercel, Netlify, AWS CloudFront
- настройка nginx/Apache
- запасной вариант через service worker для GitHub Pages
Настройка для разработки (схема с двумя серверами)
В официальных примерах для разработки используется схема с двумя серверами, потому что заголовки COOP/COEP могут ломать навигацию:
// Server 1: Main app (port 9999) - NO isolation headers
// Serves index.html, navigation works normally
// Server 2: Meeting page (port 9998) - WITH isolation headers
// Serves meeting.html with SharedArrayBuffer support
// Main server proxies to meeting server
proxy: [{
path: '/meeting.html',
target: 'http://YOUR_MEETING_SERVER_HOST:9998/'
}]
Конфигурация Vite с заголовками:
// vite.config.ts
export default defineConfig({
server: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
}
}
});
Частые проблемы и решения
| Проблема | Решение |
|---|---|
| Вход не удаётся из-за ошибки подписи | Проверь создание подписи, проверь формат sdkKey |
| Опечатка в «passWord» | В Client View — passWord (заглавная W), в Component View — password |
| Нет HD-видео | Включи заголовки SharedArrayBuffer, проверь поддержку браузера |
| Колбэки не срабатывают | Убедись, что inMeetingServiceListener вызывается после успешного init |
| Виртуальный фон не работает | Нужны SharedArrayBuffer и Chrome/Edge |
| Не работает показ экрана в Safari | Для client view нужен Safari 17+ на macOS 14+ |
Полное руководство по устранению неполадок: [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
Матрица поддержки браузеров
| Возможность | Chrome | Firefox | Safari | Edge | iOS | Android |
|---|---|---|---|---|---|---|
| 720p (приём) | Да | Да | Да | Да | Да | Да |
| 720p (отправка) | Да* | Да* | Да* | Да* | Да* | Да* |
| Виртуальный фон | Да | Да | Нет | Да | Нет | Нет |
| Показ экрана (отправка) | Да | Да | Safari 17+ | Да | Нет | Нет |
| Режим галереи | Да | Да | Да** | Да | Да | Да |
*Требуется SharedArrayBuffer **Safari 17+ с macOS Sonoma
Полную матрицу см. в [concepts/browser-support.md](concepts/browser-support.md).
Требования к авторизации (обновление 2026 года)
ВАЖНО: начиная со 2 марта 2026 года приложения, которые входят во встречи вне своего аккаунта, должны быть авторизованы.
Варианты
- App Privilege Token (OBF) - рекомендуется для ботов ``
javascript ZoomMtg.join({ ... obfToken: 'your-app-privilege-token' });``
- Токен ZAK - для операций ведущего ``
javascript ZoomMtg.join({ ... zak: 'host-zak-token' });``
Zoom for Government (ZFG)
Вариант 1: пакет NPM специально для ZFG
{
"dependencies": {
"@zoom/meetingsdk": "3.11.2-zfg"
}
}
Вариант 2: настройка эндпоинтов ZFG
Client View:
ZoomMtg.setZoomJSLib('https://source.zoomgov.com/{VERSION}/lib', '/av');
ZoomMtg.init({
webEndpoint: 'www.zoomgov.com',
...
});
Component View:
await client.init({
webEndpoint: 'www.zoomgov.com',
assetPath: 'https://source.zoomgov.com/{VERSION}/lib/av',
...
});
CDN для Китая
// Set before preLoadWasm()
ZoomMtg.setZoomJSLib('https://jssdk.zoomus.cn/{VERSION}/lib', '/av');
Интеграция с React
Официальная схема (из zoom/meetingsdk-react-sample)
В официальном примере на React используется императивная инициализация, а не хуки React:
import { ZoomMtg } from '@zoom/meetingsdk';
// Preload at module level (outside component)
ZoomMtg.preLoadWasm();
ZoomMtg.prepareWebSDK();
function App() {
const authEndpoint = import.meta.env.VITE_AUTH_ENDPOINT;
const meetingNumber = '';
const passWord = '';
const role = 0;
const userName = 'React User';
const getSignature = async () => {
const response = await fetch(authEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
meetingNumber,
role,
}),
});
const data = await response.json();
startMeeting(data.signature);
};
const startMeeting = (signature: string) => {
document.getElementById('zmmtg-root')!.style.display = 'block';
ZoomMtg.init({
leaveUrl: window.location.origin,
patchJsMedia: true,
leaveOnPageUnload: true,
success: () => {
ZoomMtg.join({
signature,
meetingNumber,
userName,
passWord,
success: (res) => console.log('Joined:', res),
error: (err) => console.error('Join error:', err),
});
},
error: (err) => console.error('Init error:', err),
});
};
return (
<button onClick={getSignature}>Join Meeting</button>
);
}
Подводные камни React (из официальных примеров)
| Проблема | В чём трудность | Решение |
|---|---|---|
| Повторное создание клиента | createClient() в теле компонента выполняется при каждом рендере | Используй useRef, чтобы сохранять клиент |
| Нет useEffect | Официальный пример не использует хуки жизненного цикла React | Очисткой занимается параметр SDK leaveOnPageUnload |
| Прямая работа с DOM | Пример использует getElementById | В продакшене используй useRef<HTMLDivElement> |
| Нет состояния ошибки | Тихие сбои | Добавь useState для обработки ошибок |
| Побочные эффекты на уровне модуля | preLoadWasm() на верхнем уровне | Может вызывать проблемы при SSR |
Готовая к продакшену схема для React
import { useEffect, useRef, useState, useCallback } from 'react';
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
type ZoomClient = ReturnType<typeof ZoomMtgEmbedded.createClient>;
function ZoomMeeting({ meetingNumber, password, userName }: Props) {
const clientRef = useRef<ZoomClient | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [isJoining, setIsJoining] = useState(false);
const [error, setError] = useState<string | null>(null);
// Create client once
useEffect(() => {
if (!clientRef.current) {
clientRef.current = ZoomMtgEmbedded.createClient();
}
}, []);
const joinMeeting = useCallback(async () => {
if (!clientRef.current || !containerRef.current) return;
setIsJoining(true);
setError(null);
try {
// Get signature from your backend
const response = await fetch('/api/signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ meetingNumber, role: 0 }),
});
const { signature, sdkKey } = await response.json();
await clientRef.current.init({
zoomAppRoot: containerRef.current,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
});
await clientRef.current.join({
signature,
sdkKey,
meetingNumber,
password,
userName,
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to join');
} finally {
setIsJoining(false);
}
}, [meetingNumber, password, userName]);
return (
<div>
<div ref={containerRef} style={{ width: '100%', height: '500px' }} />
<button onClick={joinMeeting} disabled={isJoining}>
{isJoining ? 'Joining...' : 'Join Meeting'}
</button>
{error && <div className="error">{error}</div>}
</div>
);
}
Переменные окружения (Vite)
# .env.local
VITE_AUTH_ENDPOINT=http://YOUR_AUTH_SERVER_HOST:4000
VITE_SDK_KEY=your_sdk_key
const authEndpoint = import.meta.env.VITE_AUTH_ENDPOINT;
const sdkKey = import.meta.env.VITE_SDK_KEY;
Подробные справочники
Основная документация
- [SKILL.md](SKILL.md) - полное руководство по навигации
- [client-view/SKILL.md](client-view/SKILL.md) - полный справочник по Client View
- [component-view/SKILL.md](component-view/SKILL.md) - полный справочник по Component View
Концепции
- [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) - требования к HD-видео
- [concepts/browser-support.md](concepts/browser-support.md) - матрица возможностей по браузерам
Устранение неполадок
- [troubleshooting/error-codes.md](troubleshooting/error-codes.md) - все коды ошибок SDK
- [troubleshooting/common-issues.md](troubleshooting/common-issues.md) - быстрая диагностика
Примеры
- [client-view/SKILL.md](client-view/SKILL.md) - полное руководство по Client View
- [component-view/SKILL.md](component-view/SKILL.md) - интеграция Component View с React
Вспомогательные утилиты
Извлечение номера встречи из ссылки-приглашения
// Users can paste full Zoom invite links
document.getElementById('meeting_number').addEventListener('input', (e) => {
// Extract meeting number (9-11 digits)
let meetingNumber = e.target.value.replace(/([^0-9])+/i, '');
if (meetingNumber.match(/([0-9]{9,11})/)) {
meetingNumber = meetingNumber.match(/([0-9]{9,11})/)[1];
}
// Auto-extract password from invite link
const pwdMatch = e.target.value.match(/pwd=([\d,\w]+)/);
if (pwdMatch) {
document.getElementById('password').value = pwdMatch[1];
}
});
Динамическое переключение языка
// Change language at runtime
document.getElementById('language').addEventListener('change', (e) => {
const lang = e.target.value;
ZoomMtg.i18n.load(lang);
ZoomMtg.i18n.reload(lang);
ZoomMtg.reRender({ lang });
});
Проверка системных требований
// Check browser compatibility before initializing
const requirements = ZoomMtg.checkSystemRequirements();
console.log('Browser info:', JSON.stringify(requirements));
if (!requirements.browserInfo.isChrome && !requirements.browserInfo.isFirefox) {
alert('For best experience, use Chrome or Firefox');
}
Примеры репозиториев
| Репозиторий | Описание |
|---|---|
| meetingsdk-web-sample | Официальные примеры (Client View и Component View) |
| meetingsdk-react-sample | Интеграция с React на TypeScript + Vite |
| meetingsdk-web | Исходный код SDK с helper.html |
| meetingsdk-auth-endpoint-sample | Бэкенд для создания подписи |
Официальные ресурсы
- Официальная документация: https://developers.zoom.us/docs/meeting-sdk/web/
- Справочник по API Client View: https://marketplacefront.zoom.us/sdk/meeting/web/index.html
- Справочник по API Component View: https://marketplacefront.zoom.us/sdk/meeting/web/components/index.html
- Форум разработчиков: https://devforum.zoom.us/
Версия документации: основана на Zoom Web Meeting SDK v3.11+
Нужна помощь? Начни с [SKILL.md](SKILL.md) для полной навигации.
Объединено из meeting-sdk/web/SKILL.md
Zoom Meeting SDK (веб) — указатель документации
Краткий навигатор по всей документации Web SDK.
С чего начать
| Документ | Описание |
|---|---|
| [SKILL.md](SKILL.md) | Главная точка входа: быстрые старты для Client View и Component View |
По типу представления
Client View (на всю страницу)
| Документ | Описание |
|---|---|
| [client-view/SKILL.md](client-view/SKILL.md) | Полный справочник по Client View |
Component View (встраиваемый)
| Документ | Описание |
|---|---|
| [component-view/SKILL.md](component-view/SKILL.md) | Полный справочник по Component View |
Концепции
| Документ | Описание |
|---|---|
| [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) | Требования к HD-видео, заголовки COOP/COEP |
| [concepts/browser-support.md](concepts/browser-support.md) | Матрица возможностей по браузерам |
Примеры
| Документ | Описание |
|---|---|
| [examples/client-view-basic.md](examples/client-view-basic.md) | Базовая интеграция Client View |
| [examples/component-view-react.md](examples/component-view-react.md) | Интеграция Component View с React |
Устранение неполадок
| Документ | Описание |
|---|---|
| [troubleshooting/error-codes.md](troubleshooting/error-codes.md) | Все коды ошибок SDK (диапазон 3000–10000) |
| [troubleshooting/common-issues.md](troubleshooting/common-issues.md) | Быстрая диагностика и исправления |
По темам
Аутентификация
- [SKILL.md#authentication-endpoint](SKILL.md#authentication-endpoint-required) - создание подписи
- [SKILL.md#authorization-requirements-2026-update](SKILL.md#authorization-requirements-2026-update) - токены OBF
HD-видео и производительность
- [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) - включение 720p/1080p
События и обратные вызовы
- [SKILL.md#event-listeners-client-view](SKILL.md#event-listeners-client-view) - события Client View
- [SKILL.md#event-listeners-component-view](SKILL.md#event-listeners-component-view) - события Component View
Правительственная версия (ZFG)
- [SKILL.md#zoom-for-government-zfg](SKILL.md#zoom-for-government-zfg) - настройка ZFG
CDN для Китая
- [SKILL.md#china-cdn](SKILL.md#china-cdn) - CDN для Китая
Краткий справочник
Client View и Component View
| Аспект | Client View | Component View |
|---|---|---|
| Объект | ZoomMtg | ZoomMtgEmbedded.createClient() |
| Стиль API | Колбэки | Промисы |
| Параметр пароля | passWord (заглавная W) | password (строчная) |
| События | inMeetingServiceListener() | on()/off() |
Главные подводные камни
- Написание пароля различается в разных представлениях!
- Client View:
passWord(заглавная W) - Component View:
password(строчная)
- Для HD-возможностей нужен SharedArrayBuffer
- видео 720p/1080p
- режим галереи (25 видео)
- виртуальные фоны
- Изменение авторизации с марта 2026 года
- Приложениям, которые входят во внешние встречи, нужны токены OBF или ZAK
Внешние ресурсы
- Официальная документация: https://developers.zoom.us/docs/meeting-sdk/web/
- Client View API: https://marketplacefront.zoom.us/sdk/meeting/web/index.html
- Component View API: https://marketplacefront.zoom.us/sdk/meeting/web/components/index.html
- Примеры на GitHub: https://github.com/zoom/meetingsdk-web-sample
Эксплуатация
- [RUNBOOK.md](RUNBOOK.md) - пятиминутная проверка перед запуском и чек-лист отладки.
Перевод: iiuniversitet. Оригинал: https://github.com/anthropics/knowledge-work-plugins/tree/main/partner-built/zoom-plugin/skills/meeting-sdk/web, лицензия MIT. Изменения: перевод на русский язык.
Оригинал на английском
---
name: zoom-meeting-sdk-web
description: |
Zoom Meeting SDK for Web - Embed Zoom meeting capabilities into web applications. Two integration
options: Client View (full-page, familiar Zoom UI) and Component View (embeddable, Promise-based API).
Includes SharedArrayBuffer setup for HD video, gallery view, and virtual backgrounds.
user-invocable: false
triggers:
- "embed meeting web"
- "meeting in react"
- "meeting in nextjs"
- "meeting in vue"
- "meeting in angular"
- "component view"
- "client view"
- "web meeting sdk"
- "javascript meeting"
- "sharedarraybuffer"
---
# Zoom Meeting SDK (Web)
Embed Zoom meeting capabilities into web applications with two integration options: **Client View** (full-page) or **Component View** (embeddable).
## How to Implement a Custom Video User Interface for a Zoom Meeting in a Web App
Use **Meeting SDK Web Component View**.
Do not use Video SDK for this question unless the user is explicitly building a non-meeting session
product.
Minimal architecture:
```text
Browser page
-> fetch Meeting SDK signature from backend
-> ZoomMtgEmbedded.createClient()
-> client.init({ zoomAppRoot })
-> client.join({ signature, sdkKey, meetingNumber, userName, password })
-> apply layout/style/customize options around the embedded meeting container
```
Minimal implementation:
```ts
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
const client = ZoomMtgEmbedded.createClient();
export async function startEmbeddedMeeting(meetingNumber: string, userName: string, password: string) {
const sigRes = await fetch('/api/signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ meetingNumber, role: 0 }),
});
if (!sigRes.ok) throw new Error(`signature_fetch_failed:${sigRes.status}`);
const { signature, sdkKey } = await sigRes.json();
await client.init({
zoomAppRoot: document.getElementById('meetingSDKElement')!,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
customize: {
video: { isResizable: true, popper: { disableDraggable: false } },
},
});
await client.join({
signature,
sdkKey,
meetingNumber,
userName,
password,
});
}
```
Common failure points:
- wrong route: Video SDK instead of Meeting SDK Component View
- missing backend signature endpoint
- wrong password field (`password` here, not `passWord`)
- missing OBF/ZAK requirements for meetings outside the app account
- missing SharedArrayBuffer headers when higher-end meeting features are expected
## Hard Routing Rule
If the user wants a **custom video user interface for a Zoom meeting in a web app**, route to
**Component View**, not Video SDK.
- **Meeting SDK Component View** = custom UI for a real Zoom meeting
- **Video SDK Web** = custom UI for a non-meeting video session product
For the direct custom-meeting-UI path, start with
[component-view/SKILL.md](component-view/SKILL.md).
## New to Web SDK? Start Here!
**The fastest way to master the SDK:**
1. **Choose Your View** - [Client View vs Component View](#client-view-vs-component-view) - Understand the key architectural differences
2. **Quick Start** - [Client View](#quick-start-client-view) or [Component View](#quick-start-component-view) - Get a working meeting in minutes
3. **SharedArrayBuffer** - [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) - Required for HD video, gallery view, virtual backgrounds
4. **Optional preflight diagnostics** - [../../probe-sdk/SKILL.md](../../probe-sdk/SKILL.md) - Validate browser/device/network before join
**Building a Custom Integration?**
- Component View gives you Promise-based API and embeddable UI
- Client View gives you the familiar full-page Zoom experience
- For a custom meeting UI, prefer **Component View** first
- Cross-product routing example: [../../general/use-cases/custom-meeting-ui-web.md](../../general/use-cases/custom-meeting-ui-web.md)
- [Browser Support](concepts/browser-support.md) - Feature matrix by browser
- Exact deep-dive path: [component-view/SKILL.md](component-view/SKILL.md)
**Having issues?**
- Join errors → Check signature generation and password spelling (`passWord` vs `password`)
- HD video not working → Enable SharedArrayBuffer headers
- Complete navigation → [SKILL.md](SKILL.md)
## Prerequisites
- Zoom app with Meeting SDK credentials from [Marketplace](https://marketplace.zoom.us/)
- SDK Key (Client ID) and Secret
- Modern browser (Chrome, Firefox, Safari, Edge)
- Backend auth endpoint for signature generation
> **Need help with authentication?** See the **[zoom-oauth](../../oauth/SKILL.md)** skill for JWT/signature generation.
>
> **Want pre-join diagnostics?** Chain **[probe-sdk](../../probe-sdk/SKILL.md)** before `init()`/`join()` to gate low-readiness environments.
## Optional Preflight Gate (Probe SDK)
For unstable first-join environments, run Probe SDK checks before calling `ZoomMtg.init()` or `client.join()`:
1. Run Probe permissions/device/network diagnostics.
2. Apply readiness policy (`allow`, `warn`, `block`).
3. Continue to Meeting SDK join only for `allow`/approved `warn`.
See [../../probe-sdk/SKILL.md](../../probe-sdk/SKILL.md) and [../../general/use-cases/probe-sdk-preflight-readiness-gate.md](../../general/use-cases/probe-sdk-preflight-readiness-gate.md).
## Client View vs Component View
**CRITICAL DIFFERENCE**: These are two completely different APIs with different patterns!
| Aspect | Client View | Component View |
|--------|-------------|----------------|
| **Object** | `ZoomMtg` (global singleton) | `ZoomMtgEmbedded.createClient()` (instance) |
| **API Style** | Callbacks | Promises |
| **UI** | Full-page takeover | Embeddable in any container |
| **Password param** | `passWord` (capital W) | `password` (lowercase) |
| **Events** | `inMeetingServiceListener()` | `on()`/`off()` |
| **Import (npm)** | `import { ZoomMtg } from '@zoom/meetingsdk'` | `import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded'` |
| **CDN** | `zoom-meeting-{VERSION}.min.js` | `zoom-meeting-embedded-{VERSION}.min.js` |
| **Best For** | Quick integration, standard Zoom UI | Custom layouts, React/Vue apps |
### When to Use Which
**Use Client View when:**
- You want the familiar Zoom meeting interface
- Quick integration is priority over customization
- Full-page meeting experience is acceptable
**Use Component View when:**
- You need to embed meetings in a specific area of your page
- Building React/Vue/Angular applications
- You want Promise-based async/await syntax
- Custom positioning and resizing is required
## Installation
### NPM (Recommended)
```bash
npm install @zoom/meetingsdk --save
```
### CDN
```html
<!-- Dependencies (required for both views) -->
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/{VERSION}/lib/vendor/lodash.min.js"></script>
<!-- Client View -->
<script src="https://source.zoom.us/zoom-meeting-{VERSION}.min.js"></script>
<!-- OR Component View -->
<script src="https://source.zoom.us/zoom-meeting-embedded-{VERSION}.min.js"></script>
```
Replace `{VERSION}` with the [latest version](https://www.npmjs.com/package/@zoom/meetingsdk) (e.g., `3.11.0`).
## Quick Start (Client View)
```javascript
import { ZoomMtg } from '@zoom/meetingsdk';
// Step 1: Check browser compatibility
console.log('System requirements:', ZoomMtg.checkSystemRequirements());
// Step 2: Preload WebAssembly for faster initialization
ZoomMtg.preLoadWasm();
ZoomMtg.prepareWebSDK();
// Step 3: Load language files (MUST complete before init)
ZoomMtg.i18n.load('en-US');
ZoomMtg.i18n.onLoad(() => {
// Step 4: Initialize SDK
ZoomMtg.init({
leaveUrl: 'https://yoursite.com/meeting-ended',
disableCORP: !window.crossOriginIsolated, // Auto-detect SharedArrayBuffer
patchJsMedia: true, // Auto-apply media dependency fixes
leaveOnPageUnload: true, // Clean up when page unloads
externalLinkPage: './external.html', // Page for external links
success: () => {
// Step 5: Join meeting (note: passWord with capital W!)
ZoomMtg.join({
signature: signature, // From your auth endpoint
meetingNumber: '1234567890',
userName: 'User Name',
passWord: 'meeting-password', // Capital W!
success: (res) => {
console.log('Joined meeting:', res);
// Post-join: Get meeting info
ZoomMtg.getAttendeeslist({});
ZoomMtg.getCurrentUser({
success: (res) => console.log('Current user:', res.result.currentUser)
});
},
error: (err) => {
console.error('Join error:', err);
}
});
},
error: (err) => {
console.error('Init error:', err);
}
});
});
```
## Quick Start (Component View)
```javascript
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
// Create client instance (do this ONCE, not on every render!)
const client = ZoomMtgEmbedded.createClient();
async function startMeeting() {
try {
// Initialize with container element
await client.init({
zoomAppRoot: document.getElementById('meetingSDKElement'),
language: 'en-US',
debug: true, // Enable debug logging
patchJsMedia: true, // Auto-apply media fixes
leaveOnPageUnload: true, // Clean up on page unload
});
// Join meeting (note: password lowercase!)
await client.join({
signature: signature, // From your auth endpoint
sdkKey: SDK_KEY,
meetingNumber: '1234567890',
userName: 'User Name',
password: 'meeting-password', // Lowercase!
});
console.log('Joined successfully!');
} catch (error) {
console.error('Failed to join:', error);
}
}
```
## Authentication Endpoint (Required)
Both views require a JWT signature from a backend server. **Never expose your SDK Secret in frontend code!**
```bash
# Clone Zoom's official auth endpoint
git clone https://github.com/zoom/meetingsdk-auth-endpoint-sample --depth 1
cd meetingsdk-auth-endpoint-sample
cp .env.example .env
# Edit .env with your SDK Key and Secret
npm install && npm run start
```
### Signature Generation
The signature encodes:
- `sdkKey` (or `clientId` for newer apps)
- `meetingNumber`
- `role` (0 = participant, 1 = host)
- `iat` (issued at timestamp)
- `exp` (expiration timestamp)
- `tokenExp` (token expiration)
> **IMPORTANT (March 2026)**: Apps joining meetings outside their account will require an App Privilege Token (OBF) or ZAK token. See [Authorization Requirements](#authorization-requirements-2026-update).
## Core Workflow
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Get Signature │───►│ init() │───►│ join() │
│ (from backend)│ │ (SDK setup) │ │ (enter mtg) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
success/error success/error
callback callback
(or Promise resolve) (or Promise resolve)
```
## Client View API Reference
### ZoomMtg.init() - Key Options
```javascript
ZoomMtg.init({
// Required
leaveUrl: string, // URL to redirect after leaving
// Display Options
showMeetingHeader: boolean, // Show meeting number/topic (default: true)
disableInvite: boolean, // Hide invite button (default: false)
disableRecord: boolean, // Hide record button (default: false)
disableJoinAudio: boolean, // Hide join audio option (default: false)
disablePreview: boolean, // Skip A/V preview (default: false)
// HD Video (requires SharedArrayBuffer)
enableHD: boolean, // Enable 720p (default: true for >=2.8.0)
enableFullHD: boolean, // Enable 1080p for webinars (default: false)
// View Options
defaultView: 'gallery' | 'speaker' | 'multiSpeaker',
// Feature Toggles
isSupportChat: boolean, // Enable chat (default: true)
isSupportCC: boolean, // Enable closed captions (default: true)
isSupportBreakout: boolean, // Enable breakout rooms (default: true)
isSupportPolling: boolean, // Enable polling (default: true)
isSupportQA: boolean, // Enable Q&A for webinars (default: true)
// Cross-Origin
disableCORP: boolean, // For dev without COOP/COEP headers
// Callbacks
success: Function,
error: Function,
});
```
### ZoomMtg.join() - Key Options
```javascript
ZoomMtg.join({
// Required
signature: string, // JWT signature from backend
meetingNumber: string | number,
userName: string,
// Authentication
passWord: string, // Meeting password (capital W!)
zak: string, // Host's ZAK token (required to start)
tk: string, // Registration token (if required)
obfToken: string, // App Privilege Token (for 2026 requirement)
// Optional
userEmail: string, // Required for webinars
customerKey: string, // Custom identifier (max 36 chars)
// Callbacks
success: Function,
error: Function,
});
```
### Event Listeners (Client View)
```javascript
// User events
ZoomMtg.inMeetingServiceListener('onUserJoin', (data) => {
console.log('User joined:', data);
});
ZoomMtg.inMeetingServiceListener('onUserLeave', (data) => {
console.log('User left:', data);
// data.reasonCode values:
// 0: OTHER
// 1: HOST_ENDED_MEETING
// 2: SELF_LEAVE_FROM_IN_MEETING
// 3: SELF_LEAVE_FROM_WAITING_ROOM
// 4: SELF_LEAVE_FROM_WAITING_FOR_HOST_START
// 5: MEETING_TRANSFER
// 6: KICK_OUT_FROM_MEETING
// 7: KICK_OUT_FROM_WAITING_ROOM
// 8: LEAVE_FROM_DISCLAIMER
});
ZoomMtg.inMeetingServiceListener('onUserUpdate', (data) => {
console.log('User updated:', data);
});
// Meeting status
ZoomMtg.inMeetingServiceListener('onMeetingStatus', (data) => {
// status: 1=connecting, 2=connected, 3=disconnected, 4=reconnecting
console.log('Meeting status:', data.status);
});
// Waiting room
ZoomMtg.inMeetingServiceListener('onUserIsInWaitingRoom', (data) => {
console.log('User in waiting room:', data);
});
// Active speaker detection
ZoomMtg.inMeetingServiceListener('onActiveSpeaker', (data) => {
// [{userId: number, userName: string}]
console.log('Active speaker:', data);
});
// Network quality monitoring
ZoomMtg.inMeetingServiceListener('onNetworkQualityChange', (data) => {
// {level: 0-5, userId, type: 'uplink'}
// 0-1 = bad, 2 = normal, 3-5 = good
if (data.level <= 1) {
console.warn('Poor network quality');
}
});
// Join performance metrics
ZoomMtg.inMeetingServiceListener('onJoinSpeed', (data) => {
console.log('Join speed metrics:', data);
// Useful for performance monitoring dashboards
});
// Chat
ZoomMtg.inMeetingServiceListener('onReceiveChatMsg', (data) => {
console.log('Chat message:', data);
});
// Recording
ZoomMtg.inMeetingServiceListener('onRecordingChange', (data) => {
console.log('Recording status:', data);
});
// Screen sharing
ZoomMtg.inMeetingServiceListener('onShareContentChange', (data) => {
console.log('Share content changed:', data);
});
// Transcription (requires "save closed captions" enabled)
ZoomMtg.inMeetingServiceListener('onReceiveTranscriptionMsg', (data) => {
console.log('Transcription:', data);
});
// Breakout room status
ZoomMtg.inMeetingServiceListener('onRoomStatusChange', (data) => {
// status: 2=InProgress, 3=Closing, 4=Closed
console.log('Breakout room status:', data);
});
```
### Common Methods (Client View)
```javascript
// Get current user info
ZoomMtg.getCurrentUser({
success: (res) => console.log(res.result.currentUser)
});
// Get all attendees
ZoomMtg.getAttendeeslist({});
// Audio/Video control
ZoomMtg.mute({ userId, mute: true });
ZoomMtg.muteAll({ muteAll: true });
// Chat
ZoomMtg.sendChat({ message: 'Hello!', userId: 0 }); // 0 = everyone
// Leave/End
ZoomMtg.leaveMeeting({});
ZoomMtg.endMeeting({});
// Host controls
ZoomMtg.makeHost({ userId });
ZoomMtg.makeCoHost({ oderId });
ZoomMtg.expel({ userId }); // Remove participant
ZoomMtg.putOnHold({ oderId, bHold: true });
// Breakout rooms
ZoomMtg.createBreakoutRoom({ rooms: [...] });
ZoomMtg.openBreakoutRooms({});
ZoomMtg.closeBreakoutRooms({});
// Virtual background
ZoomMtg.setVirtualBackground({ imageUrl: '...' });
```
## Component View API Reference
### client.init() - Key Options
```javascript
await client.init({
// Required
zoomAppRoot: HTMLElement, // Container element
// Display
language: string, // e.g., 'en-US'
debug: boolean, // Enable debug logging (default: false)
// Media
patchJsMedia: boolean, // Auto-apply media fixes (default: false)
leaveOnPageUnload: boolean, // Clean up on page unload (default: false)
// Video
enableHD: boolean, // Enable 720p
enableFullHD: boolean, // Enable 1080p
// Customization
customize: {
video: {
isResizable: boolean,
viewSizes: { default: { width, height } }
},
meetingInfo: ['topic', 'host', 'mn', 'pwd', 'telPwd', 'invite', 'participant', 'dc', 'enctype'],
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'custom-btn',
onClick: () => {
console.log('Custom button clicked');
}
}
]
}
},
// For ZFG
webEndpoint: string,
assetPath: string, // Custom path for AV libraries (self-hosting)
});
```
### client.join() - Key Options
```javascript
await client.join({
// Required
signature: string,
sdkKey: string,
meetingNumber: string | number,
userName: string,
// Authentication
password: string, // Lowercase! (different from Client View)
zak: string, // Host's ZAK token
tk: string, // Registration token
// Optional
userEmail: string,
});
```
### Event Listeners (Component View)
```javascript
// Connection state
client.on('connection-change', (payload) => {
// payload.state: 'Connecting', 'Connected', 'Reconnecting', 'Closed'
console.log('Connection:', payload.state);
});
// User events
client.on('user-added', (payload) => {
console.log('Users added:', payload);
});
client.on('user-removed', (payload) => {
console.log('Users removed:', payload);
});
client.on('user-updated', (payload) => {
console.log('Users updated:', payload);
});
// Active speaker
client.on('active-speaker', (payload) => {
console.log('Active speaker:', payload);
});
// Video state
client.on('video-active-change', (payload) => {
console.log('Video active:', payload);
});
// Unsubscribe
client.off('connection-change', handler);
```
### Common Methods (Component View)
```javascript
// Get current user
const currentUser = client.getCurrentUser();
// Get all participants
const participants = client.getParticipantsList();
// Audio control
await client.mute(true);
await client.muteAudio(userId, true);
// Video control
await client.muteVideo(userId, true);
// Leave
client.leaveMeeting();
// End (host only)
client.endMeeting();
```
## SharedArrayBuffer (CRITICAL for HD)
SharedArrayBuffer enables advanced features:
- 720p/1080p video
- Gallery view
- Virtual backgrounds
- Background noise suppression
### Enable with HTTP Headers
```
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```
### Verify in Browser
```javascript
if (typeof SharedArrayBuffer === 'function') {
console.log('SharedArrayBuffer enabled!');
} else {
console.warn('HD features will be limited');
}
// Or check cross-origin isolation
console.log('Cross-origin isolated:', window.crossOriginIsolated);
```
### Platform-Specific Setup
See [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) for:
- Vercel, Netlify, AWS CloudFront configuration
- nginx/Apache configuration
- Service worker fallback for GitHub Pages
### Development Setup (Two-Server Pattern)
The official samples use a **two-server pattern** for development because COOP/COEP headers can break navigation:
```javascript
// Server 1: Main app (port 9999) - NO isolation headers
// Serves index.html, navigation works normally
// Server 2: Meeting page (port 9998) - WITH isolation headers
// Serves meeting.html with SharedArrayBuffer support
// Main server proxies to meeting server
proxy: [{
path: '/meeting.html',
target: 'http://YOUR_MEETING_SERVER_HOST:9998/'
}]
```
**Vite config with headers:**
```typescript
// vite.config.ts
export default defineConfig({
server: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
}
}
});
```
## Common Issues & Solutions
| Issue | Solution |
|-------|----------|
| **Join fails with signature error** | Verify signature generation, check sdkKey format |
| **"passWord" typo** | Client View uses `passWord` (capital W), Component View uses `password` |
| **No HD video** | Enable SharedArrayBuffer headers, check browser support |
| **Callbacks not firing** | Ensure `inMeetingServiceListener` called after init success |
| **Virtual background not working** | Requires SharedArrayBuffer + Chrome/Edge |
| **Screen share fails on Safari** | Safari 17+ with macOS 14+ required for client view |
**Complete troubleshooting**: [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
## Browser Support Matrix
| Feature | Chrome | Firefox | Safari | Edge | iOS | Android |
|---------|--------|---------|--------|------|-----|---------|
| 720p (receive) | Yes | Yes | Yes | Yes | Yes | Yes |
| 720p (send) | Yes* | Yes* | Yes* | Yes* | Yes* | Yes* |
| Virtual background | Yes | Yes | No | Yes | No | No |
| Screen share (send) | Yes | Yes | Safari 17+ | Yes | No | No |
| Gallery view | Yes | Yes | Yes** | Yes | Yes | Yes |
*Requires SharedArrayBuffer
**Safari 17+ with macOS Sonoma
See [concepts/browser-support.md](concepts/browser-support.md) for complete matrix.
## Authorization Requirements (2026 Update)
> **IMPORTANT**: Beginning **March 2, 2026**, apps joining meetings outside their account must be authorized.
### Options
1. **App Privilege Token (OBF)** - Recommended for bots
```javascript
ZoomMtg.join({
...
obfToken: 'your-app-privilege-token'
});
```
2. **ZAK Token** - For host operations
```javascript
ZoomMtg.join({
...
zak: 'host-zak-token'
});
```
## Zoom for Government (ZFG)
### Option 1: ZFG-specific NPM Package
```json
{
"dependencies": {
"@zoom/meetingsdk": "3.11.2-zfg"
}
}
```
### Option 2: Configure ZFG Endpoints
**Client View:**
```javascript
ZoomMtg.setZoomJSLib('https://source.zoomgov.com/{VERSION}/lib', '/av');
ZoomMtg.init({
webEndpoint: 'www.zoomgov.com',
...
});
```
**Component View:**
```javascript
await client.init({
webEndpoint: 'www.zoomgov.com',
assetPath: 'https://source.zoomgov.com/{VERSION}/lib/av',
...
});
```
## China CDN
```javascript
// Set before preLoadWasm()
ZoomMtg.setZoomJSLib('https://jssdk.zoomus.cn/{VERSION}/lib', '/av');
```
## React Integration
### Official Pattern (from zoom/meetingsdk-react-sample)
The official React sample uses **imperative initialization** rather than React hooks:
```tsx
import { ZoomMtg } from '@zoom/meetingsdk';
// Preload at module level (outside component)
ZoomMtg.preLoadWasm();
ZoomMtg.prepareWebSDK();
function App() {
const authEndpoint = import.meta.env.VITE_AUTH_ENDPOINT;
const meetingNumber = '';
const passWord = '';
const role = 0;
const userName = 'React User';
const getSignature = async () => {
const response = await fetch(authEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
meetingNumber,
role,
}),
});
const data = await response.json();
startMeeting(data.signature);
};
const startMeeting = (signature: string) => {
document.getElementById('zmmtg-root')!.style.display = 'block';
ZoomMtg.init({
leaveUrl: window.location.origin,
patchJsMedia: true,
leaveOnPageUnload: true,
success: () => {
ZoomMtg.join({
signature,
meetingNumber,
userName,
passWord,
success: (res) => console.log('Joined:', res),
error: (err) => console.error('Join error:', err),
});
},
error: (err) => console.error('Init error:', err),
});
};
return (
<button onClick={getSignature}>Join Meeting</button>
);
}
```
### React Gotchas (from official samples)
| Issue | Problem | Solution |
|-------|---------|----------|
| **Client Recreation** | `createClient()` in component body runs every render | Use `useRef` to persist client |
| **No useEffect** | Official sample doesn't use React lifecycle hooks | SDK's `leaveOnPageUnload` handles cleanup |
| **Direct DOM** | Sample uses `getElementById` | Use `useRef<HTMLDivElement>` in production |
| **No Error State** | Silent failures | Add `useState` for error handling |
| **Module-Scope Side Effects** | `preLoadWasm()` at top level | May cause issues with SSR |
### Production-Ready React Pattern
```tsx
import { useEffect, useRef, useState, useCallback } from 'react';
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
type ZoomClient = ReturnType<typeof ZoomMtgEmbedded.createClient>;
function ZoomMeeting({ meetingNumber, password, userName }: Props) {
const clientRef = useRef<ZoomClient | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [isJoining, setIsJoining] = useState(false);
const [error, setError] = useState<string | null>(null);
// Create client once
useEffect(() => {
if (!clientRef.current) {
clientRef.current = ZoomMtgEmbedded.createClient();
}
}, []);
const joinMeeting = useCallback(async () => {
if (!clientRef.current || !containerRef.current) return;
setIsJoining(true);
setError(null);
try {
// Get signature from your backend
const response = await fetch('/api/signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ meetingNumber, role: 0 }),
});
const { signature, sdkKey } = await response.json();
await clientRef.current.init({
zoomAppRoot: containerRef.current,
language: 'en-US',
patchJsMedia: true,
leaveOnPageUnload: true,
});
await clientRef.current.join({
signature,
sdkKey,
meetingNumber,
password,
userName,
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to join');
} finally {
setIsJoining(false);
}
}, [meetingNumber, password, userName]);
return (
<div>
<div ref={containerRef} style={{ width: '100%', height: '500px' }} />
<button onClick={joinMeeting} disabled={isJoining}>
{isJoining ? 'Joining...' : 'Join Meeting'}
</button>
{error && <div className="error">{error}</div>}
</div>
);
}
```
### Environment Variables (Vite)
```bash
# .env.local
VITE_AUTH_ENDPOINT=http://YOUR_AUTH_SERVER_HOST:4000
VITE_SDK_KEY=your_sdk_key
```
```tsx
const authEndpoint = import.meta.env.VITE_AUTH_ENDPOINT;
const sdkKey = import.meta.env.VITE_SDK_KEY;
```
## Detailed References
### Core Documentation
- **[SKILL.md](SKILL.md)** - Complete navigation guide
- **[client-view/SKILL.md](client-view/SKILL.md)** - Full Client View reference
- **[component-view/SKILL.md](component-view/SKILL.md)** - Full Component View reference
### Concepts
- **[concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md)** - HD video requirements
- **[concepts/browser-support.md](concepts/browser-support.md)** - Feature matrix by browser
### Troubleshooting
- **[troubleshooting/error-codes.md](troubleshooting/error-codes.md)** - All SDK error codes
- **[troubleshooting/common-issues.md](troubleshooting/common-issues.md)** - Quick diagnostics
### Examples
- **[client-view/SKILL.md](client-view/SKILL.md)** - Complete Client View guide
- **[component-view/SKILL.md](component-view/SKILL.md)** - Component View React integration
## Helper Utilities
### Extract Meeting Number from Invite Link
```javascript
// Users can paste full Zoom invite links
document.getElementById('meeting_number').addEventListener('input', (e) => {
// Extract meeting number (9-11 digits)
let meetingNumber = e.target.value.replace(/([^0-9])+/i, '');
if (meetingNumber.match(/([0-9]{9,11})/)) {
meetingNumber = meetingNumber.match(/([0-9]{9,11})/)[1];
}
// Auto-extract password from invite link
const pwdMatch = e.target.value.match(/pwd=([\d,\w]+)/);
if (pwdMatch) {
document.getElementById('password').value = pwdMatch[1];
}
});
```
### Dynamic Language Switching
```javascript
// Change language at runtime
document.getElementById('language').addEventListener('change', (e) => {
const lang = e.target.value;
ZoomMtg.i18n.load(lang);
ZoomMtg.i18n.reload(lang);
ZoomMtg.reRender({ lang });
});
```
### Check System Requirements
```javascript
// Check browser compatibility before initializing
const requirements = ZoomMtg.checkSystemRequirements();
console.log('Browser info:', JSON.stringify(requirements));
if (!requirements.browserInfo.isChrome && !requirements.browserInfo.isFirefox) {
alert('For best experience, use Chrome or Firefox');
}
```
## Sample Repositories
| Repository | Description |
|------------|-------------|
| [meetingsdk-web-sample](https://github.com/zoom/meetingsdk-web-sample) | Official samples (Client View & Component View) |
| [meetingsdk-react-sample](https://github.com/zoom/meetingsdk-react-sample) | React integration with TypeScript + Vite |
| [meetingsdk-web](https://github.com/zoom/meetingsdk-web) | SDK source with helper.html |
| [meetingsdk-auth-endpoint-sample](https://github.com/zoom/meetingsdk-auth-endpoint-sample) | Signature generation backend |
## Official Resources
- **Official docs**: https://developers.zoom.us/docs/meeting-sdk/web/
- **Client View API Reference**: https://marketplacefront.zoom.us/sdk/meeting/web/index.html
- **Component View API Reference**: https://marketplacefront.zoom.us/sdk/meeting/web/components/index.html
- **Developer forum**: https://devforum.zoom.us/
---
**Documentation Version**: Based on Zoom Web Meeting SDK v3.11+
**Need help?** Start with [SKILL.md](SKILL.md) for complete navigation.
## Merged from meeting-sdk/web/SKILL.md
# Zoom Meeting SDK (Web) - Documentation Index
Quick navigation guide for all Web SDK documentation.
## Start Here
| Document | Description |
|----------|-------------|
| **[SKILL.md](SKILL.md)** | Main entry point - Quick starts for both Client View and Component View |
## By View Type
### Client View (Full-Page)
| Document | Description |
|----------|-------------|
| **[client-view/SKILL.md](client-view/SKILL.md)** | Complete Client View reference |
### Component View (Embeddable)
| Document | Description |
|----------|-------------|
| **[component-view/SKILL.md](component-view/SKILL.md)** | Complete Component View reference |
## Concepts
| Document | Description |
|----------|-------------|
| **[concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md)** | HD video requirements, COOP/COEP headers |
| **[concepts/browser-support.md](concepts/browser-support.md)** | Feature matrix by browser |
## Examples
| Document | Description |
|----------|-------------|
| [examples/client-view-basic.md](examples/client-view-basic.md) | Basic Client View integration |
| [examples/component-view-react.md](examples/component-view-react.md) | React integration with Component View |
## Troubleshooting
| Document | Description |
|----------|-------------|
| **[troubleshooting/error-codes.md](troubleshooting/error-codes.md)** | All SDK error codes (3000-10000 range) |
| **[troubleshooting/common-issues.md](troubleshooting/common-issues.md)** | Quick diagnostics and fixes |
## By Topic
### Authentication
- [SKILL.md#authentication-endpoint](SKILL.md#authentication-endpoint-required) - Signature generation
- [SKILL.md#authorization-requirements-2026-update](SKILL.md#authorization-requirements-2026-update) - OBF tokens
### HD Video & Performance
- [concepts/sharedarraybuffer.md](concepts/sharedarraybuffer.md) - Enable 720p/1080p
### Events & Callbacks
- [SKILL.md#event-listeners-client-view](SKILL.md#event-listeners-client-view) - Client View events
- [SKILL.md#event-listeners-component-view](SKILL.md#event-listeners-component-view) - Component View events
### Government (ZFG)
- [SKILL.md#zoom-for-government-zfg](SKILL.md#zoom-for-government-zfg) - ZFG configuration
### China CDN
- [SKILL.md#china-cdn](SKILL.md#china-cdn) - China-specific CDN
## Quick Reference
### Client View vs Component View
| Aspect | Client View | Component View |
|--------|-------------|----------------|
| **Object** | `ZoomMtg` | `ZoomMtgEmbedded.createClient()` |
| **API Style** | Callbacks | Promises |
| **Password param** | `passWord` (capital W) | `password` (lowercase) |
| **Events** | `inMeetingServiceListener()` | `on()`/`off()` |
### Key Gotchas
1. **Password spelling differs between views!**
- Client View: `passWord` (capital W)
- Component View: `password` (lowercase)
2. **SharedArrayBuffer required for HD features**
- 720p/1080p video
- Gallery view (25 videos)
- Virtual backgrounds
3. **March 2026 Authorization Change**
- Apps joining external meetings need OBF or ZAK tokens
## External Resources
- **Official docs**: https://developers.zoom.us/docs/meeting-sdk/web/
- **Client View API**: https://marketplacefront.zoom.us/sdk/meeting/web/index.html
- **Component View API**: https://marketplacefront.zoom.us/sdk/meeting/web/components/index.html
- **GitHub samples**: https://github.com/zoom/meetingsdk-web-sample
## Operations
- [RUNBOOK.md](RUNBOOK.md) - 5-minute preflight and debugging checklist.
Источник: anthropics/knowledge-work-plugins / zoom-plugin / zoom-meeting-sdk-web ↗. Ссылка проверена 2026-10-10.