build-zoom-video-sdk-app

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

/build-zoom-video-sdk-app

/build-zoom-video-sdk-app

Background reference for fully custom video-session products. Prefer
plan-zoom-product
first when the boundary between Meeting SDK and Video SDK is still unclear.
Build custom video experiences powered by Zoom's infrastructure.
完全自定义视频会话产品的背景参考文档。当Meeting SDK与Video SDK的边界仍不明确时,优先使用
plan-zoom-product
基于Zoom基础设施构建自定义视频体验。

Hard Routing Guardrail (Read First)

硬路由规则(必读)

  • If the user asks for custom real-time video app behavior (topic/session join, custom rendering, attach/detach), route to Video SDK.
  • Do not switch to REST meeting endpoints for Video SDK join flows.
  • Video SDK does not use Meeting IDs,
    join_url
    , or Meeting SDK join payload fields (
    meetingNumber
    ,
    passWord
    ).
  • 如果用户要求自定义实时视频应用行为(主题/会话加入、自定义渲染、附加/分离),则路由到Video SDK。
  • 不要为Video SDK加入流程切换到REST会议端点。
  • Video SDK不使用会议ID、
    join_url
    或Meeting SDK加入负载字段(
    meetingNumber
    passWord
    )。

Meeting SDK vs Video SDK

Meeting SDK与Video SDK对比

FeatureMeeting SDKVideo SDK
UIDefault Zoom UI or Custom UIFully custom UI (you build it)
ExperienceZoom meetingsVideo sessions
BrandingLimited customizationFull branding control
FeaturesFull Zoom featuresCore video features
功能Meeting SDKVideo SDK
UI界面默认Zoom UI或自定义UI完全自定义UI(由您自行构建)
体验Zoom会议视频会话
品牌定制有限定制完全品牌控制权
功能完整Zoom功能核心视频功能

UI Options (Web)

Web端UI选项

Video SDK gives you full control over the UI:
OptionDescription
UI ToolkitPre-built React components (low-code)
Custom UIBuild your own UI using the SDK APIs
Video SDK让您完全控制UI界面
选项描述
UI Toolkit预构建React组件(低代码)
自定义UI使用SDK API构建自有UI

Prerequisites

前置条件

  • Zoom Video SDK credentials from Marketplace
  • SDK Key and Secret
  • Web development environment
Need help with OAuth or signatures? See the zoom-oauth skill for authentication flows.
Need pre-join diagnostics on web? Use probe-sdk before Video SDK
join()
to reduce first-minute failures.
Start troubleshooting fast: Use the 5-Minute Runbook before deep debugging.
  • 来自Zoom Marketplace的Zoom Video SDK凭证
  • SDK密钥与密钥密码
  • Web开发环境
需要OAuth或签名相关帮助? 查看**zoom-oauth**技能获取认证流程说明。
需要Web端加入前诊断? 在调用Video SDK
join()
前使用**probe-sdk**以减少初始阶段的失败。
快速启动故障排查: 在深度调试前先查看**5-Minute Runbook**。

Quick Start (Web)

Web端快速开始

NPM Usage (Bundler like Vite/Webpack)

NPM使用(适用于Vite/Webpack等打包工具)

javascript
import ZoomVideo from '@zoom/videosdk';

const client = ZoomVideo.createClient();
await client.init('en-US', 'Global', { patchJsMedia: true });
await client.join(topic, signature, userName, password);

// IMPORTANT: getMediaStream() ONLY works AFTER join()
const stream = client.getMediaStream();
await stream.startVideo();
await stream.startAudio();
javascript
import ZoomVideo from '@zoom/videosdk';

const client = ZoomVideo.createClient();
await client.init('en-US', 'Global', { patchJsMedia: true });
await client.join(topic, signature, userName, password);

// 重要提示:getMediaStream()仅在join()后可用
const stream = client.getMediaStream();
await stream.startVideo();
await stream.startAudio();

CDN Usage (No Bundler)

CDN使用(无需打包工具)

WARNING: Ad blockers block
source.zoom.us
. Self-host the SDK to avoid issues.
bash
undefined
警告:广告拦截器会阻止
source.zoom.us
。建议自行托管SDK以避免问题。
bash
undefined

Download SDK locally

本地下载SDK


```html
<script src="js/zoom-video-sdk.min.js"></script>
javascript
// CDN exports as WebVideoSDK, NOT ZoomVideo
// Must use .default property
const ZoomVideo = WebVideoSDK.default;
const client = ZoomVideo.createClient();

await client.init('en-US', 'Global', { patchJsMedia: true });
await client.join(topic, signature, userName, password);

// IMPORTANT: getMediaStream() ONLY works AFTER join()
const stream = client.getMediaStream();
await stream.startVideo();
await stream.startAudio();

```html
<script src="js/zoom-video-sdk.min.js"></script>
javascript
// CDN导出的是WebVideoSDK,而非ZoomVideo
// 必须使用.default属性
const ZoomVideo = WebVideoSDK.default;
const client = ZoomVideo.createClient();

await client.init('en-US', 'Global', { patchJsMedia: true });
await client.join(topic, signature, userName, password);

// 重要提示:getMediaStream()仅在join()后可用
const stream = client.getMediaStream();
await stream.startVideo();
await stream.startAudio();

ES Module with CDN (Race Condition Fix)

结合CDN使用ES模块(解决竞态条件)

When using
<script type="module">
with CDN, SDK may not be loaded yet:
javascript
// Wait for SDK to load before using
function waitForSDK(timeout = 10000) {
  return new Promise((resolve, reject) => {
    if (typeof WebVideoSDK !== 'undefined') {
      resolve();
      return;
    }
    const start = Date.now();
    const check = setInterval(() => {
      if (typeof WebVideoSDK !== 'undefined') {
        clearInterval(check);
        resolve();
      } else if (Date.now() - start > timeout) {
        clearInterval(check);
        reject(new Error('SDK failed to load'));
      }
    }, 100);
  });
}

// Usage
await waitForSDK();
const ZoomVideo = WebVideoSDK.default;
const client = ZoomVideo.createClient();
当使用
<script type="module">
结合CDN时,SDK可能尚未加载完成:
javascript
// 使用前等待SDK加载完成
function waitForSDK(timeout = 10000) {
  return new Promise((resolve, reject) => {
    if (typeof WebVideoSDK !== 'undefined') {
      resolve();
      return;
    }
    const start = Date.now();
    const check = setInterval(() => {
      if (typeof WebVideoSDK !== 'undefined') {
        clearInterval(check);
        resolve();
      } else if (Date.now() - start > timeout) {
        clearInterval(check);
        reject(new Error('SDK加载失败'));
      }
    }, 100);
  });
}

// 使用示例
await waitForSDK();
const ZoomVideo = WebVideoSDK.default;
const client = ZoomVideo.createClient();

SDK Lifecycle (CRITICAL ORDER)

SDK生命周期(严格顺序)

The SDK has a strict lifecycle. Violating it causes silent failures.
1. Create client:     client = ZoomVideo.createClient()
2. Initialize:        await client.init('en-US', 'Global', options)
3. Join session:      await client.join(topic, signature, userName, password)
4. Get stream:        stream = client.getMediaStream()  ← ONLY AFTER JOIN
5. Start media:       await stream.startVideo() / await stream.startAudio()
Common Mistake (Silent Failure):
javascript
// ❌ WRONG: Getting stream before joining
const client = ZoomVideo.createClient();
await client.init('en-US', 'Global');
const stream = client.getMediaStream();  // Returns undefined!
await client.join(...);

// ✅ CORRECT: Get stream after joining
const client = ZoomVideo.createClient();
await client.init('en-US', 'Global');
await client.join(...);
const stream = client.getMediaStream();  // Works!
SDK有严格的生命周期,违反顺序会导致静默失败。
1. 创建客户端:     client = ZoomVideo.createClient()
2. 初始化:        await client.init('en-US', 'Global', options)
3. 加入会话:      await client.join(topic, signature, userName, password)
4. 获取媒体流:        stream = client.getMediaStream()  ← 仅在加入后可用
5. 启动媒体:       await stream.startVideo() / await stream.startAudio()
常见错误(静默失败):
javascript
// ❌ 错误:在加入前获取媒体流
const client = ZoomVideo.createClient();
await client.init('en-US', 'Global');
const stream = client.getMediaStream();  // 返回undefined!
await client.join(...);

// ✅ 正确:在加入后获取媒体流
const client = ZoomVideo.createClient();
await client.init('en-US', 'Global');
await client.join(...);
const stream = client.getMediaStream();  // 正常工作!

Video Rendering (Event-Driven)

视频渲染(事件驱动)

The SDK is event-driven. You must listen for events and render videos accordingly.
SDK采用事件驱动模式。您必须监听事件并相应地渲染视频。

Use
attachVideo()
NOT
renderVideo()

使用
attachVideo()
而非
renderVideo()

javascript
import { VideoQuality } from '@zoom/videosdk';

// Start your camera
await stream.startVideo();

// Attach video - returns element to append to DOM
const element = await stream.attachVideo(userId, VideoQuality.Video_360P);
container.appendChild(element);

// Detach when done
await stream.detachVideo(userId);
javascript
import { VideoQuality } from '@zoom/videosdk';

// 启动摄像头
await stream.startVideo();

// 附加视频 - 返回要添加到DOM的元素
const element = await stream.attachVideo(userId, VideoQuality.Video_360P);
container.appendChild(element);

// 完成后分离
await stream.detachVideo(userId);

Required Events

必备事件

javascript
// When other participant's video turns on/off
client.on('peer-video-state-change', async (payload) => {
  const { action, userId } = payload;
  if (action === 'Start') {
    const el = await stream.attachVideo(userId, VideoQuality.Video_360P);
    container.appendChild(el);
  } else {
    await stream.detachVideo(userId);
  }
});

// When participants join/leave
client.on('user-added', (payload) => { /* check bVideoOn */ });
client.on('user-removed', (payload) => { stream.detachVideo(payload.userId); });
See web/references/web.md for complete event handling patterns.
javascript
// 当其他参与者的视频开启/关闭时
client.on('peer-video-state-change', async (payload) => {
  const { action, userId } = payload;
  if (action === 'Start') {
    const el = await stream.attachVideo(userId, VideoQuality.Video_360P);
    container.appendChild(el);
  } else {
    await stream.detachVideo(userId);
  }
});

// 当参与者加入/离开时
client.on('user-added', (payload) => { /* 检查bVideoOn状态 */ });
client.on('user-removed', (payload) => { stream.detachVideo(payload.userId); });
查看web/references/web.md获取完整的事件处理模式。

Key Concepts

核心概念

ConceptDescription
SessionVideo session (not a meeting)
TopicSession identifier (any string you choose)
SignatureJWT for authorization
MediaStreamAudio/video stream control
概念描述
会话视频会话(非会议)
Topic会话标识符(可自定义任意字符串)
Signature用于授权的JWT
MediaStream音视频流控制

Session Creation Model

会话创建模型

Important: Video SDK sessions are created just-in-time, not in advance.
AspectVideo SDKMeeting SDK
Pre-creationNOT requiredCreate meeting via API first
Session startFirst participant joins with topicJoin existing meeting ID
TopicAny string (you define it)Meeting ID from API
SchedulingN/A - sessions are ad-hocMeetings can be scheduled
重要提示: Video SDK会话是即时创建的,无需提前创建。
方面Video SDKMeeting SDK
提前创建不需要需先通过API创建会议
会话启动第一个参与者使用Topic加入时创建加入已存在的会议ID
Topic任意自定义字符串来自API的会议ID
日程安排不支持 - 会话为临时创建可安排会议

How Sessions Work

会话工作原理

  1. No pre-creation needed: Sessions don't exist until someone joins
  2. Topic = Session ID: Any participants joining with the same
    topic
    string join the same session
  3. First join creates it: The session is created when the first participant joins
  4. No meeting ID: There's no numeric meeting ID like in Zoom Meetings
javascript
// Session is created on-the-fly when first user joins
// Any string can be the topic - it becomes the session identifier
await client.join('my-custom-session-123', signature, 'User Name');

// Other participants join the SAME session by using the SAME topic
await client.join('my-custom-session-123', signature, 'Another User');
  1. 无需提前创建:会话在有人加入前不存在
  2. Topic = 会话ID:使用相同
    topic
    字符串的参与者会加入同一个会话
  3. 首次加入创建会话:当第一个参与者加入时会话被创建
  4. 无会议ID:不像Zoom Meetings那样有数字会议ID
javascript
// 当第一个用户加入时,会话会即时创建
// Topic可以是任意字符串 - 它将作为会话标识符
await client.join('my-custom-session-123', signature, 'User Name');

// 其他参与者使用相同的Topic即可加入同一个会话
await client.join('my-custom-session-123', signature, 'Another User');

Signature Endpoint Setup

签名端点设置

The signature endpoint must be accessible from your frontend without CORS issues.
Option 1: Same-Origin Proxy (Recommended)
nginx
undefined
签名端点必须能被前端访问且无CORS问题。
选项1:同源代理(推荐)
nginx
undefined

Nginx config

Nginx配置

location /api/ { proxy_pass http://YOUR_BACKEND_HOST:3005/api/; proxy_http_version 1.1; proxy_set_header Host $host; }

```javascript
// Frontend uses relative URL (same origin)
const response = await fetch('/api/signature', { ... });
Option 2: CORS Configuration
javascript
// Express.js backend
const cors = require('cors');
app.use(cors({
  origin: ['https://your-domain.com'],
  credentials: true
}));
WARNING: Mixed content (HTTPS page → HTTP API) will be blocked by browsers.
location /api/ { proxy_pass http://YOUR_BACKEND_HOST:3005/api/; proxy_http_version 1.1; proxy_set_header Host $host; }

```javascript
// 前端使用相对URL(同源)
const response = await fetch('/api/signature', { ... });
选项2:CORS配置
javascript
// Express.js后端
const cors = require('cors');
app.use(cors({
  origin: ['https://your-domain.com'],
  credentials: true
}));
警告: 混合内容(HTTPS页面 → HTTP API)会被浏览器阻止。

Use Cases

使用场景

Use CaseDescription
Video SDK BYOS (Bring Your Own Storage)Save recordings directly to your S3 bucket
使用场景描述
Video SDK BYOS(自带存储)将录制内容直接保存到您的S3存储桶

BYOS (Bring Your Own Storage)

BYOS(自带存储)

Video SDK feature - Zoom saves cloud recordings directly to your Amazon S3 bucket. No downloading required.
Prerequisites:
  • Video SDK account with Cloud Recording add-on (Universal Credit includes this)
  • AWS S3 bucket
Authentication options:
  1. AWS Access Key - simpler setup
  2. Cross Account Access - more secure (IAM role assumption)
S3 path structure:
Buckets/{bucketName}/cmr/byos/{YYYY}/{MM}/{DD}/{GUID}/cmr_byos/
Key benefits:
  • Zero download bandwidth costs
  • Direct storage during recording
  • Config-only setup (no webhook/download code needed)
Setup location: Developer Portal → Account Settings → General → Communications Content Storage Location
See ../general/use-cases/video-sdk-bring-your-own-storage.md for complete setup guide.
Video SDK功能 - Zoom将云录制内容直接保存到您的Amazon S3存储桶,无需下载。
前置条件:
  • 带有云录制附加组件的Video SDK账户(通用信用包含此功能)
  • AWS S3存储桶
认证选项:
  1. AWS访问密钥 - 设置更简单
  2. 跨账户访问 - 更安全(IAM角色假设)
S3路径结构:
Buckets/{bucketName}/cmr/byos/{YYYY}/{MM}/{DD}/{GUID}/cmr_byos/
核心优势:
  • 零下载带宽成本
  • 录制时直接存储
  • 仅需配置(无需Webhook或下载代码)
设置位置: 开发者门户 → 账户设置 → 常规 → 通信内容存储位置
查看**../general/use-cases/video-sdk-bring-your-own-storage.md**获取完整设置指南。

Detailed References

详细参考文档

UI & Components

UI与组件

  • references/ui-toolkit.md - Pre-built UI components (Web)
  • references/triage-intake.md - What to ask first (turn vague reports into answers)
  • references/session-lifecycle.md - Correct API ordering + event-driven rendering
  • references/licensing-and-entitlements.md - License/admin prerequisites
  • references/token-contract-test-spec.md - Shared backend token contract and cross-platform smoke test
  • references/ui-toolkit.md - 预构建UI组件(Web端)
  • references/triage-intake.md - 首次沟通要点(将模糊需求转化为明确问题)
  • references/session-lifecycle.md - 正确的API调用顺序 + 事件驱动渲染
  • references/licensing-and-entitlements.md - 许可证/管理员前置条件
  • references/token-contract-test-spec.md - 共享后端令牌契约与跨平台冒烟测试

Platform Guides

平台指南

  • references/authorization.md - Video SDK JWT generation
  • web/SKILL.md - Web Video SDK (JavaScript/TypeScript)
    • web/SKILL.md - Complete documentation navigation
    • web/examples/react-hooks.md - Official React hooks library
    • web/examples/framework-integrations.md - Next.js, Vue/Nuxt patterns
  • react-native/SKILL.md - React Native Video SDK (mobile wrapper, helper/event architecture)
    • react-native/SKILL.md - React Native documentation navigation
    • react-native/examples/session-join-pattern.md - Tokenized session join flow
  • flutter/SKILL.md - Flutter Video SDK (mobile wrapper, event-driven architecture)
    • flutter/SKILL.md - Flutter documentation navigation
    • flutter/examples/session-join-pattern.md - Tokenized session join flow
  • android/SKILL.md - Android Video SDK (native mobile custom UI, tokenized sessions)
  • ios/SKILL.md - iOS Video SDK (native mobile custom UI, delegate-driven lifecycle)
  • macos/SKILL.md - macOS Video SDK (desktop native apps, custom session windows)
  • unity/SKILL.md - Unity Video SDK wrapper (game-engine integration, scene-driven UX)
  • linux/SKILL.md - Linux Video SDK overview (C++ headless bots)
  • linux/linux.md - Linux C++ SDK (headless bots, raw media capture/injection)
  • linux/references/linux-reference.md - Linux API Reference
  • windows/SKILL.md - Windows C++ SDK (desktop applications, raw media capture/injection)
  • windows/references/windows-reference.md - Windows API Reference
  • references/troubleshooting.md - Common issues and solutions
  • references/forum-top-questions.md - Common forum question patterns (what to cover)
  • references/authorization.md - Video SDK JWT生成
  • web/SKILL.md - Web端Video SDK(JavaScript/TypeScript)
    • web/SKILL.md - 完整文档导航
    • web/examples/react-hooks.md - 官方React Hooks库
    • web/examples/framework-integrations.md - Next.js、Vue/Nuxt集成模式
  • react-native/SKILL.md - React Native Video SDK(移动端封装,辅助/事件架构)
    • react-native/SKILL.md - React Native文档导航
    • react-native/examples/session-join-pattern.md - 令牌化会话加入流程
  • flutter/SKILL.md - Flutter Video SDK(移动端封装,事件驱动架构)
    • flutter/SKILL.md - Flutter文档导航
    • flutter/examples/session-join-pattern.md - 令牌化会话加入流程
  • android/SKILL.md - Android Video SDK(原生移动端自定义UI,令牌化会话)
  • ios/SKILL.md - iOS Video SDK(原生移动端自定义UI,委托驱动生命周期)
  • macos/SKILL.md - macOS Video SDK(桌面原生应用,自定义会话窗口)
  • unity/SKILL.md - Unity Video SDK封装(游戏引擎集成,场景驱动用户体验)
  • linux/SKILL.md - Linux Video SDK概述(C++无头机器人)
  • linux/linux.md - Linux C++ SDK(无头机器人,原始媒体捕获/注入)
  • linux/references/linux-reference.md - Linux API参考
  • windows/SKILL.md - Windows C++ SDK(桌面应用,原始媒体捕获/注入)
  • windows/references/windows-reference.md - Windows API参考
  • references/troubleshooting.md - 常见问题与解决方案
  • references/forum-top-questions.md - 论坛常见问题模式(需覆盖的要点)

Sample Repositories

示例代码仓库

Official (by Zoom)

Zoom官方仓库

Full list: See general/references/community-repos.md
完整列表: 查看general/references/community-repos.md

Resources

资源

Environment Variables

环境变量

  • See references/environment-variables.md for standardized
    .env
    keys and where to find each value.
  • 查看references/environment-variables.md获取标准化的
    .env
    密钥及各值的获取位置。

Linux Operations

Linux操作指南

  • linux/RUNBOOK.md - Linux platform preflight and debugging checklist.
  • linux/RUNBOOK.md - Linux平台预检与故障排查清单。