zoom-apps-sdk
在 Zoom client 裡跑的 web app 開發參考
中文翻譯
---
name: zoom-apps-sdk
description: Zoom Apps SDK 的參考 skill。在已經導向 in-client app 工作流之後使用,適用於開發在 Zoom 會議、webinar、主 client 或 Zoom Phone 裡面跑的 web app。
user-invocable: false
triggers:
- "zoom app"
- "in-meeting app"
- "app inside zoom"
- "zoom client app"
- "layers api"
- "immersive mode"
- "camera mode"
- "collaborate mode"
- "appssdk"
- "in-client oauth"
- "zoom mail"
- "domain allowlist"
- "domain whitelist"
- "url whitelisting"
- "blank panel"
- "runningContext"
- "zoomSdk"
---
# Zoom Apps SDK
這是在 Zoom client 裡面跑的 web app 的背景參考資料。建議先走 `choose-zoom-approach`,再回到這裡查 Layers API、Collaborate Mode、in-client OAuth 和執行環境的限制。
# Zoom Apps SDK
開發在 Zoom client 裡面跑的 web app,包含會議、webinar、主 client 和 Zoom Phone。
**官方文件**:https://developers.zoom.us/docs/zoom-apps/
**SDK 參考**:https://appssdk.zoom.us/
**NPM 套件**:https://www.npmjs.com/package/@zoom/appssdk
## Quick Links
**第一次接觸 Zoom Apps?照這個順序走:**
1. **[Architecture](concepts/architecture.md)** - 前後端模式、內嵌瀏覽器、deep linking
2. **[Quick Start](examples/quick-start.md)** - 完整可跑的 Express + SDK app
3. **[Running Contexts](concepts/running-contexts.md)** - app 會在哪裡執行(inMeeting、inMainClient 等)
4. **[Zoom Apps vs Meeting SDK](concepts/meeting-sdk-vs-zoom-apps.md)** - 別再把兩種 app 類型搞混
4. **[In-Client OAuth](examples/in-client-oauth.md)** - 搭配 PKCE 的無縫授權
5. **[API Reference](references/apis.md)** - 100 多個 SDK 方法
6. **Integrated Index** - 見本檔下方的章節
7. **[5-Minute Runbook](RUNBOOK.md)** - 深入除錯之前的 preflight 檢查
**參考資料:**
- **[API Reference](references/apis.md)** - 依類別整理的所有 SDK 方法
- **[Events Reference](references/events.md)** - 所有 SDK 事件監聽器
- **[Layers API](references/layers-api.md)** - Immersive 和 camera mode 的繪製
- **[OAuth Reference](references/oauth.md)** - Zoom Apps 的 OAuth 流程
- **[Zoom Mail](references/zmail-sdk.md)** - Mail plugin 整合
**遇到問題?**
- App 在 Zoom 裡載不出來 → 看下面的 [Domain Allowlist](#url-whitelisting-required)
- SDK 錯誤 → [Common Issues](troubleshooting/common-issues.md)
- 本機開發環境設定 → [Debugging Guide](troubleshooting/debugging.md)
- 版本升級 → [Migration Guide](troubleshooting/migration.md)
- 從論壇整理出來的 FAQ → [Forum Top Questions](troubleshooting/forum-top-questions.md)
**想做 immersive 體驗?**
- [Layers Immersive Mode](examples/layers-immersive.md) - 自訂視訊版面
- [Camera Mode](examples/layers-camera.md) - 虛擬鏡頭覆蓋層
> **OAuth 需要協助?** 驗證流程請看 **[zoom-oauth](../oauth/SKILL.md)** skill。
## SDK Overview
Zoom Apps SDK(`@zoom/appssdk`)提供 JavaScript API,給在 Zoom 內嵌瀏覽器裡執行的 web app 使用:
- **Context APIs** - 取得會議、使用者和參與者資訊
- **Meeting Actions** - 分享 app、邀請參與者、開啟 URL
- **Authorization** - 搭配 PKCE 的 In-Client OAuth(不用瀏覽器 redirect)
- **Layers API** - Immersive 視訊版面和 camera mode 覆蓋層
- **Collaborate Mode** - 參與者之間共用 app 狀態
- **App Communication** - app 實例之間傳訊(主 client <-> 會議)
- **Media Controls** - 虛擬背景、列出鏡頭、錄影控制
- **UI Controls** - 展開 app、通知、popout
- **Events** - 回應會議狀態、參與者、分享等變化
## Prerequisites
- 在 [Marketplace](https://marketplace.zoom.us/) 把 Zoom app 設成 **"Zoom App"** 類型
- 有 Zoom Apps scope 的 OAuth 憑證(Client ID + Secret)
- Web 應用程式(建議用 Node.js + Express)
- **你的網域已加入** Marketplace 的 domain allowlist
- 本機開發用 ngrok 或 HTTPS tunnel
- Node.js 18+(後端 server 用)
## Quick Start
### Option A: NPM(框架專案建議用這個)
```bash
npm install @zoom/appssdk
```
```javascript
import zoomSdk from '@zoom/appssdk';
async function init() {
try {
const configResponse = await zoomSdk.config({
capabilities: [
'shareApp',
'getMeetingContext',
'getUserContext',
'openUrl'
],
version: '0.16'
});
console.log('Running context:', configResponse.runningContext);
// 'inMeeting' | 'inMainClient' | 'inWebinar' | 'inImmersive' | ...
const context = await zoomSdk.getMeetingContext();
console.log('Meeting ID:', context.meetingID);
} catch (error) {
console.error('Not running inside Zoom:', error.message);
showDemoMode();
}
}
```
### Option B: CDN(Vanilla JS)
```html
<script src="https://appssdk.zoom.us/sdk.js"></script>
<script>
// CRITICAL:不要宣告 "let zoomSdk",SDK 已經在全域定義了 window.zoomSdk
// 用 "let zoomSdk = ..." 會造成:SyntaxError: redeclaration of non-configurable global property
let sdk = window.zoomSdk; // 換一個變數名稱
async function init() {
try {
const configResponse = await sdk.config({
capabilities: ['shareApp', 'getMeetingContext', 'getUserContext'],
version: '0.16'
});
console.log('Running context:', configResponse.runningContext);
} catch (error) {
console.error('Not running inside Zoom:', error.message);
showDemoMode();
}
}
function showDemoMode() {
document.body.innerHTML = '<h1>Preview Mode</h1><p>Open this app inside Zoom to use.</p>';
}
document.addEventListener('DOMContentLoaded', () => {
init();
setTimeout(() => { if (!sdk) showDemoMode(); }, 3000);
});
</script>
```
## Critical: Global Variable Conflict
CDN script 會在全域定義 `window.zoomSdk`。**不要重新宣告它:**
```javascript
// WRONG - 在 Zoom 的內嵌瀏覽器裡會造成 SyntaxError
let zoomSdk = null;
zoomSdk = window.zoomSdk;
// CORRECT - 用不同的變數名稱
let sdk = window.zoomSdk;
// ALSO CORRECT - NPM import(不會衝突)
import zoomSdk from '@zoom/appssdk';
```
這只會發生在 CDN 的做法。NPM import 建立的是 module 範圍的變數,不會衝突。
## Browser Preview / Demo Mode
SDK 只有在 Zoom client 裡面才能運作。用一般瀏覽器開啟時:
- `window.zoomSdk` 存在,但 `sdk.config()` 會丟出錯誤
- 一定要用 try/catch 搭配 fallback UI
- 加上 timeout(3 秒),避免 SDK 卡住
## URL Whitelisting (Required)
**網域沒有加入白名單,你的 app 就不會在 Zoom 裡載入。**
1. 前往 [Zoom Marketplace](https://marketplace.zoom.us/)
2. 打開你的 app -> **Feature** 分頁
3. 在 **Zoom App** 底下找到 **Add Allow List**
4. 加入你的網域(例如正式環境用 `yourdomain.com`,開發用 `xxxxx.ngrok.io`)
沒做這步,Zoom client 會顯示空白面板,而且沒有任何錯誤訊息。
## OAuth Scopes (Required)
Capability 需要在 Marketplace 啟用對應的 OAuth scope:
| Capability | Required Scope |
|------------|----------------|
| `getMeetingContext` | `zoomapp:inmeeting` |
| `getUserContext` | `zoomapp:inmeeting` |
| `shareApp` | `zoomapp:inmeeting` |
| `openUrl` | `zoomapp:inmeeting` |
| `sendAppInvitation` | `zoomapp:inmeeting` |
| `runRenderingContext` | `zoomapp:inmeeting` |
| `authorize` | `zoomapp:inmeeting` |
| `getMeetingParticipants` | `zoomapp:inmeeting` |
**加 scope 的方法:** Marketplace -> 你的 App -> **Scopes** 分頁 -> 加入需要的 scope。
少了 scope,capability 會無聲失敗或丟出錯誤。新增 scope 之後,使用者必須重新授權。
## Running Contexts
你的 app 會在 Zoom 裡的不同介面執行。`configResponse.runningContext` 會告訴你現在在哪:
| Context | Surface | Description |
|---------|---------|-------------|
| `inMeeting` | 會議側邊欄 | 最常見。可使用完整的會議 API |
| `inMainClient` | 主 client 面板 | 首頁分頁。沒有會議 context API |
| `inWebinar` | Webinar 側邊欄 | 主持人/panelist。有會議 + webinar API |
| `inImmersive` | Layers API | 全螢幕自訂渲染 |
| `inCamera` | Camera mode | 虛擬鏡頭覆蓋層 |
| `inCollaborate` | Collaborate mode | 共用狀態的 context |
| `inPhone` | Zoom Phone | 電話通話 app |
| `inChat` | Team Chat | 聊天側邊欄 |
各 context 的行為和可用 API,請看 **[Running Contexts](concepts/running-contexts.md)**。
## SDK Initialization Pattern
每個 Zoom App 都從 `config()` 開始:
```javascript
import zoomSdk from '@zoom/appssdk';
const configResponse = await zoomSdk.config({
capabilities: [
// 列出你會用到的「所有」API
'getMeetingContext',
'getUserContext',
'shareApp',
'openUrl',
'authorize',
'onAuthorized'
],
version: '0.16'
});
// configResponse 包含:
// {
// runningContext: 'inMeeting',
// clientVersion: '5.x.x',
// unsupportedApis: [] // 這個 client 版本不支援的 API
// }
```
**規則:**
1. 呼叫任何其他 SDK 方法之前,**一定要**先呼叫 `config()`
2. 只有列在 `config()` 裡的 capability 才能用
3. Capability 必須對應 Marketplace 裡的 OAuth scope
4. 檢查 `unsupportedApis`,讓功能可以優雅降級
## In-Client OAuth (Summary)
授權的最佳 UX,不用瀏覽器 redirect:
```javascript
// 1. 從你的後端取得 code challenge
const { codeChallenge, state } = await fetch('/api/auth/challenge').then(r => r.json());
// 2. 觸發 in-client 授權
await zoomSdk.authorize({ codeChallenge, state });
// 3. 監聽授權結果
zoomSdk.addEventListener('onAuthorized', async (event) => {
const { code, state } = event;
// 4. 把 code 送到後端換 token
await fetch('/api/auth/token', {
method: 'POST',
body: JSON.stringify({ code, state })
});
});
```
完整實作請看 **[In-Client OAuth Guide](examples/in-client-oauth.md)**。
## Layers API (Summary)
建立 immersive 視訊版面和鏡頭覆蓋層:
```javascript
// 啟動 immersive mode,取代 gallery view
await zoomSdk.runRenderingContext({ view: 'immersive' });
// 擺放參與者的視訊畫面
await zoomSdk.drawParticipant({
participantUUID: 'user-uuid',
x: 0, y: 0, width: 640, height: 480, zIndex: 1
});
// 加上覆蓋用的圖片
await zoomSdk.drawImage({
imageData: canvas.toDataURL(),
x: 0, y: 0, width: 1280, height: 720, zIndex: 0
});
// 離開 immersive mode
await zoomSdk.closeRenderingContext();
```
請看 **[Layers Immersive](examples/layers-immersive.md)** 和 **[Camera Mode](examples/layers-camera.md)**。
## Environment Variables
| Variable | Description | Where to Find |
|----------|-------------|---------------|
| `ZOOM_APP_CLIENT_ID` | App client ID | Marketplace -> App -> App Credentials |
| `ZOOM_APP_CLIENT_SECRET` | App client secret | Marketplace -> App -> App Credentials |
| `ZOOM_APP_REDIRECT_URI` | OAuth redirect URL | 你的 server URL + `/auth` |
| `SESSION_SECRET` | Cookie 簽章用的 secret | 產生一個隨機字串 |
| `ZOOM_HOST` | Zoom host URL | `https://zoom.us`(或 `https://zoomgov.com`) |
## Common APIs
| API | Description |
|-----|-------------|
| `config()` | 初始化 SDK,申請 capability |
| `getMeetingContext()` | 取得會議 ID、主題、狀態 |
| `getUserContext()` | 取得使用者名稱、角色、參與者 ID |
| `getRunningContext()` | 取得目前的 running context |
| `getMeetingParticipants()` | 列出參與者 |
| `shareApp()` | 把 app 畫面分享給參與者 |
| `openUrl({ url })` | 在外部瀏覽器開啟 URL |
| `sendAppInvitation()` | 邀請使用者開啟你的 app |
| `authorize()` | 觸發 In-Client OAuth |
| `connect()` | 連接到其他 app 實例 |
| `postMessage()` | 傳訊息給已連接的實例 |
| `runRenderingContext()` | 啟動 Layers API(immersive/camera) |
| `expandApp({ action })` | 展開/收合 app 面板 |
| `showNotification()` | 在 Zoom 裡顯示通知 |
## Complete Documentation Library
### Core Concepts
- **[Architecture](concepts/architecture.md)** - 前後端模式、內嵌瀏覽器、deep linking、X-Zoom-App-Context
- **[Running Contexts](concepts/running-contexts.md)** - 所有 context、各 context 專屬的 API、多實例通訊
- **[Security](concepts/security.md)** - OWASP headers、CSP、cookie 安全、PKCE、token 儲存
### Complete Examples
- **[Quick Start](examples/quick-start.md)** - Hello World 的 Express + SDK app
- **[In-Client OAuth](examples/in-client-oauth.md)** - PKCE 授權流程
- **[Layers Immersive](examples/layers-immersive.md)** - 自訂視訊版面
- **[Camera Mode](examples/layers-camera.md)** - 虛擬鏡頭覆蓋層
- **[Collaborate Mode](examples/collaborate-mode.md)** - 參與者之間共用狀態
- **[Guest Mode](examples/guest-mode.md)** - 未驗證/已驗證/已授權的狀態
- **[Breakout Rooms](examples/breakout-rooms.md)** - 分組討論室偵測與跨房間狀態
- **[App Communication](examples/app-communication.md)** - 實例之間用 connect + postMessage 溝通
### Troubleshooting
- **[Common Issues](troubleshooting/common-issues.md)** - 快速診斷與錯誤碼
- **[Debugging](troubleshooting/debugging.md)** - 本機開發、ngrok、瀏覽器預覽
- **[Migration](troubleshooting/migration.md)** - SDK 版本升級筆記
### References
- **[API Reference](references/apis.md)** - 所有 100 多個 SDK 方法
- **[Events Reference](references/events.md)** - 所有 SDK 事件監聽器
- **[Layers API Reference](references/layers-api.md)** - 繪製與渲染方法
- **[OAuth Reference](references/oauth.md)** - Zoom Apps 的 OAuth 流程
- **[Zoom Mail](references/zmail-sdk.md)** - Mail plugin 整合
## Sample Repositories
### Official (by Zoom)
| Repository | Type | Last Updated | Status | SDK Version |
|-----------|------|-------------|--------|-------------|
| [zoomapps-sample-js](https://github.com/zoom/zoomapps-sample-js) | Hello World (Vanilla JS) | Dec 2025 | Active | ^0.16.26 |
| [zoomapps-advancedsample-react](https://github.com/zoom/zoomapps-advancedsample-react) | Advanced (React + Redis) | Oct 2025 | Active | 0.16.0 |
| [zoomapps-customlayout-js](https://github.com/zoom/zoomapps-customlayout-js) | Layers API | Nov 2023 | Stale | ^0.16.8 |
| [zoomapps-texteditor-vuejs](https://github.com/zoom/zoomapps-texteditor-vuejs) | Collaborate (Vue + Y.js) | Oct 2023 | Stale | ^0.16.7 |
| [zoomapps-serverless-vuejs](https://github.com/zoom/zoomapps-serverless-vuejs) | Serverless (Firebase) | Aug 2024 | Stale | ^0.16.21 |
| [zoomapps-cameramode-vuejs](https://github.com/zoom/zoomapps-cameramode-vuejs) | Camera Mode | - | - | - |
| [zoomapps-workshop-sample](https://github.com/zoom/zoomapps-workshop-sample) | Workshop | - | - | - |
**新專案建議:** 使用 `@zoom/appssdk` 版本 `^0.16.26`。
### Community
| Type | Repository | Description |
|------|------------|-------------|
| Library | [harvard-edtech/zaccl](https://github.com/harvard-edtech/zaccl) | Zoom App Complete Connection Library |
**完整清單**:請看 [general/references/community-repos.md](../general/references/community-repos.md)
### Learning Path
1. **起步**:`zoomapps-sample-js` - 最簡單、也最新
2. **進階**:`zoomapps-advancedsample-react` - 內容最完整(In-Client OAuth、Guest Mode、Collaborate)
3. **專項**:依功能挑選(Layers、Serverless、Camera Mode)
## Critical Gotchas (From Real Development)
### 1. Global Variable Conflict
CDN script 會定義 `window.zoomSdk`。在你的程式碼裡宣告 `let zoomSdk` 會造成 `SyntaxError: redeclaration of non-configurable global property`。請用 `let sdk = window.zoomSdk` 或 NPM import。
### 2. Domain Allowlist
你的 app URL **一定要**在 Marketplace 的 domain allowlist 裡。沒有的話,Zoom 會顯示空白面板,而且不會有任何錯誤。另外也要加入 `appssdk.zoom.us` 和你用到的任何 CDN 網域。
### 3. Capabilities Must Be Listed
只有列在 `config({ capabilities: [...] })` 裡的 API 才能用。呼叫沒列出的 API 會丟出錯誤。事件監聽器也一樣。
### 4. SDK Only Works Inside Zoom
在 Zoom client 外面呼叫 `zoomSdk.config()` 會丟出錯誤。一定要用 try/catch 包起來,並準備瀏覽器 fallback:
```javascript
try { await zoomSdk.config({...}); } catch { showBrowserPreview(); }
```
### 5. ngrok URL Changes
免費版 ngrok 的 URL 每次重啟都會變。你必須在 Marketplace 更新 4 個地方:Home URL、Redirect URL、OAuth Allow List、Domain Allow List。可以考慮買 ngrok 付費方案,拿固定的子網域。
### 6. In-Client OAuth vs Web OAuth
使用 `zoomSdk.authorize()`(In-Client)可以得到最好的 UX,不用瀏覽器 redirect。只有從 Marketplace 初次安裝時才改用 web redirect。
### 7. Camera Mode CEF Race Condition
Camera mode 使用 CEF,初始化需要時間。太早呼叫 `drawImage`/`drawWebView` 可能會失敗。請實作 exponential backoff 的重試。
### 8. Cookie Configuration
Zoom 的內嵌瀏覽器要求 cookie 設成 `SameSite=None` 和 `Secure=true`。沒設的話,session 會無聲壞掉。
### 9. State Validation
一定要驗證 OAuth 的 `state` 參數,防止 CSRF 攻擊。要產生密碼學等級的隨機 state、存起來,並在 callback 時比對。
## Resources
- **官方文件**:https://developers.zoom.us/docs/zoom-apps/
- **SDK 參考**:https://appssdk.zoom.us/
- **NPM 套件**:https://www.npmjs.com/package/@zoom/appssdk
- **開發者論壇**:https://devforum.zoom.us/
- **GitHub SDK 原始碼**:https://github.com/zoom/appssdk
---
**需要協助?** 先看下方的 Integrated Index 章節,裡面有完整的導覽。
---
## Integrated Index
_這個章節是從 `SKILL.md` 搬過來的。_
## Quick Start Path
**如果你是 Zoom Apps 新手,照這個順序:**
1. **先跑 preflight 檢查** -> [RUNBOOK.md](RUNBOOK.md)
2. **讀架構** -> [concepts/architecture.md](concepts/architecture.md)
- 前後端模式、內嵌瀏覽器、deep linking
- 了解 Zoom 怎麼載入你的 app、怎麼跟它溝通
3. **做出第一個 app** -> [examples/quick-start.md](examples/quick-start.md)
- 完整的 Express + SDK Hello World
- 本機開發的 ngrok 設定
4. **搞懂 running context** -> [concepts/running-contexts.md](concepts/running-contexts.md)
- app 會在哪裡執行(inMeeting、inMainClient、inWebinar 等)
- 各 context 專屬的 API 和限制
5. **實作 OAuth** -> [examples/in-client-oauth.md](examples/in-client-oauth.md)
- 搭配 PKCE 的 In-Client OAuth(UX 最好)
- Token 交換與儲存
6. **加功能** -> [references/apis.md](references/apis.md)
- 依類別整理的 100 多個 SDK 方法
- 每個都有程式碼範例
7. **排查問題** -> [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
- 常見問題的快速診斷
---
## Documentation Structure
```
zoom-apps-sdk/
├── SKILL.md # 主要 skill 總覽
├── SKILL.md # 就是這份檔案,導覽指南
│
├── concepts/ # 核心架構模式
│ ├── architecture.md # 前後端、內嵌瀏覽器、OAuth 流程
│ ├── running-contexts.md # app 在哪裡執行 + 各 context 專屬的 API
│ └── security.md # OWASP headers、CSP、資料存取層
│
├── examples/ # 完整可跑的程式碼
│ ├── quick-start.md # Hello World,最小的 Express + SDK app
│ ├── in-client-oauth.md # 搭配 PKCE 的 In-Client OAuth
│ ├── layers-immersive.md # Layers API,immersive mode(自訂版面)
│ ├── layers-camera.md # Layers API,camera mode(虛擬鏡頭)
│ ├── collaborate-mode.md # Collaborate mode(共用狀態)
│ ├── guest-mode.md # Guest mode(未驗證 -> 已授權)
│ ├── breakout-rooms.md # 分組討論室整合
│ └── app-communication.md # 實例之間用 connect + postMessage
│
├── troubleshooting/ # 問題排解指南
│ ├── common-issues.md # 快速診斷、錯誤碼
│ ├── debugging.md # 本機開發設定、ngrok、瀏覽器預覽
│ └── migration.md # SDK 版本遷移筆記
│
└── references/ # 參考文件
├── apis.md # 完整 API 參考(100 多個方法)
├── events.md # 所有 SDK 事件
├── layers-api.md # Layers API 詳細參考
├── oauth.md # Zoom Apps 的 OAuth 流程
└── zmail-sdk.md # Zoom Mail 整合
```
---
## By Use Case
### I want to build a basic Zoom App
1. [Architecture](concepts/architecture.md) - 了解整體模式
2. [Quick Start](examples/quick-start.md) - 做出 Hello World
3. [In-Client OAuth](examples/in-client-oauth.md) - 加上授權
4. [Security](concepts/security.md) - 必要的 headers
### I want immersive video layouts (Layers API)
1. [Layers Immersive](examples/layers-immersive.md) - 自訂視訊位置
2. [Layers API Reference](references/layers-api.md) - 所有繪製方法
3. [App Communication](examples/app-communication.md) - 在參與者之間同步版面
### I want a virtual camera overlay
1. [Camera Mode](examples/layers-camera.md) - Camera mode 渲染
2. [Layers API Reference](references/layers-api.md) - 繪製方法
### I want real-time collaboration
1. [Collaborate Mode](examples/collaborate-mode.md) - 共用狀態 API
2. [App Communication](examples/app-communication.md) - 實例之間傳訊
### I want guest/anonymous access
1. [Guest Mode](examples/guest-mode.md) - 三種授權狀態
2. [In-Client OAuth](examples/in-client-oauth.md) - promptAuthorize 流程
### I want breakout room support
1. [Breakout Rooms](examples/breakout-rooms.md) - 討論室偵測與狀態同步
### I want to sync between main client and meeting
1. [App Communication](examples/app-communication.md) - connect + postMessage
2. [Running Contexts](concepts/running-contexts.md) - 多實例的行為
### I want serverless deployment
1. [Quick Start](examples/quick-start.md) - 先了解基本模式
2. 範例:[zoomapps-serverless-vuejs](https://github.com/zoom/zoomapps-serverless-vuejs) - Firebase 做法
### I want to add Zoom Mail integration
1. [Zoom Mail Reference](references/zmail-sdk.md) - REST API + mail plugin
### I'm getting errors
1. [Common Issues](troubleshooting/common-issues.md) - 快速診斷表
2. [Debugging](troubleshooting/debugging.md) - 本機開發設定、DevTools
3. [Migration](troubleshooting/migration.md) - 版本相容性
---
## Most Critical Documents
### 1. Architecture (FOUNDATION)
**[concepts/architecture.md](concepts/architecture.md)**
搞懂 Zoom Apps 怎麼運作:前端在內嵌瀏覽器裡跑,後端處理 OAuth/API,SDK 是中間的橋。沒搞懂這個,其他東西都看不懂。
### 2. Quick Start (FIRST APP)
**[examples/quick-start.md](examples/quick-start.md)**
完整可跑的程式碼。先讓東西跑起來,再去看進階功能。
### 3. Common Issues (MOST COMMON PROBLEMS)
**[troubleshooting/common-issues.md](troubleshooting/common-issues.md)**
九成的 Zoom Apps 問題都是這三種:domain allowlist、全域變數衝突,或缺少 capability。
---
## Key Learnings
### Critical Discoveries:
1. **Global Variable Conflict is the #1 Gotcha**
- CDN script 會在全域定義 `window.zoomSdk`
- `let zoomSdk = ...` 會在 Zoom 的瀏覽器裡造成 SyntaxError
- 用 `let sdk = window.zoomSdk` 或 NPM import
2. **Domain Allowlist is Non-Negotiable**
- 網域沒進白名單,app 會顯示空白面板,完全沒有錯誤
- 必須包含你的網域、`appssdk.zoom.us`,以及任何 CDN 網域
- ngrok URL 重啟就會變,每次都要去 Marketplace 更新
3. **config() Gates Everything**
- 一定要最先呼叫,而且要列出所有 capability
- 沒列出的 capability 會丟出錯誤
- 檢查 `unsupportedApis` 確認 client 版本相容
4. **In-Client OAuth > Web OAuth for UX**
- `authorize()` 讓使用者留在 Zoom 裡(沒有瀏覽器 redirect)
- 只有從 Marketplace 初次安裝才需要 web redirect
- 一定要實作 PKCE(code_verifier + code_challenge)
5. **Two App Instances Can Run Simultaneously**
- 主 client 實例 + 會議實例
- 用 `connect()` + `postMessage()` 讓兩邊同步
- 會前設定在主 client 做,會議中使用
6. **Camera Mode Has CEF Quirks**
- CEF 初始化需要時間
- 太早呼叫 draw 可能會失敗
- 用 exponential backoff 重試
7. **Cookie Settings Matter**
- 必須設定 `SameSite=None` + `Secure=true`
- 沒設的話,session 在內嵌瀏覽器裡會無聲失敗
---
## Quick Reference
### "App shows blank panel"
-> [Domain Allowlist](troubleshooting/common-issues.md) - 把網域加到 Marketplace
### "SyntaxError: redeclaration"
-> [Global Variable](troubleshooting/common-issues.md) - 用 `let sdk = window.zoomSdk`
### "config() throws error"
-> [Browser Preview](troubleshooting/debugging.md) - SDK 只能在 Zoom 裡面運作
### "API call fails silently"
-> [OAuth Scopes](troubleshooting/common-issues.md) - 在 Marketplace 加入需要的 scope
### "How do I implement [feature]?"
-> [API Reference](references/apis.md) - 找到對應的方法,確認需要的 capability
### "How do I test locally?"
-> [Debugging Guide](troubleshooting/debugging.md) - ngrok + Marketplace 設定
---
## Document Version
基於 **@zoom/appssdk v0.16.x**(最新:0.16.26+)
---
**Happy coding!**
先看 [Architecture](concepts/architecture.md) 搞懂整體模式,再看 [Quick Start](examples/quick-start.md) 做出第一個 app。英文原文
---
name: zoom-apps-sdk
description: Reference skill for Zoom Apps SDK. Use after routing to an in-client app workflow when building web apps that run inside Zoom meetings, webinars, the main client, or Zoom Phone.
user-invocable: false
triggers:
- "zoom app"
- "in-meeting app"
- "app inside zoom"
- "zoom client app"
- "layers api"
- "immersive mode"
- "camera mode"
- "collaborate mode"
- "appssdk"
- "in-client oauth"
- "zoom mail"
- "domain allowlist"
- "domain whitelist"
- "url whitelisting"
- "blank panel"
- "runningContext"
- "zoomSdk"
---
# Zoom Apps SDK
Background reference for web apps that run inside the Zoom client. Prefer `choose-zoom-approach` first, then route here for Layers API, Collaborate Mode, in-client OAuth, and runtime constraints.
# Zoom Apps SDK
Build web apps that run inside the Zoom client - meetings, webinars, main client, and Zoom Phone.
**Official Documentation**: https://developers.zoom.us/docs/zoom-apps/
**SDK Reference**: https://appssdk.zoom.us/
**NPM Package**: https://www.npmjs.com/package/@zoom/appssdk
## Quick Links
**New to Zoom Apps? Follow this path:**
1. **[Architecture](concepts/architecture.md)** - Frontend/backend pattern, embedded browser, deep linking
2. **[Quick Start](examples/quick-start.md)** - Complete working Express + SDK app
3. **[Running Contexts](concepts/running-contexts.md)** - Where your app runs (inMeeting, inMainClient, etc.)
4. **[Zoom Apps vs Meeting SDK](concepts/meeting-sdk-vs-zoom-apps.md)** - Stop mixing app types
4. **[In-Client OAuth](examples/in-client-oauth.md)** - Seamless authorization with PKCE
5. **[API Reference](references/apis.md)** - 100+ SDK methods
6. **Integrated Index** - see the section below in this file
7. **[5-Minute Runbook](RUNBOOK.md)** - Preflight checks before deep debugging
**Reference:**
- **[API Reference](references/apis.md)** - All SDK methods by category
- **[Events Reference](references/events.md)** - All SDK event listeners
- **[Layers API](references/layers-api.md)** - Immersive and camera mode rendering
- **[OAuth Reference](references/oauth.md)** - OAuth flows for Zoom Apps
- **[Zoom Mail](references/zmail-sdk.md)** - Mail plugin integration
**Having issues?**
- App won't load in Zoom → Check [Domain Allowlist](#url-whitelisting-required) below
- SDK errors → [Common Issues](troubleshooting/common-issues.md)
- Local dev setup → [Debugging Guide](troubleshooting/debugging.md)
- Version upgrade → [Migration Guide](troubleshooting/migration.md)
- Forum-derived FAQs → [Forum Top Questions](troubleshooting/forum-top-questions.md)
**Building immersive experiences?**
- [Layers Immersive Mode](examples/layers-immersive.md) - Custom video layouts
- [Camera Mode](examples/layers-camera.md) - Virtual camera overlays
> **Need help with OAuth?** See the **[zoom-oauth](../oauth/SKILL.md)** skill for authentication flows.
## SDK Overview
The Zoom Apps SDK (`@zoom/appssdk`) provides JavaScript APIs for web apps running in Zoom's embedded browser:
- **Context APIs** - Get meeting, user, and participant info
- **Meeting Actions** - Share app, invite participants, open URLs
- **Authorization** - In-Client OAuth with PKCE (no browser redirect)
- **Layers API** - Immersive video layouts and camera mode overlays
- **Collaborate Mode** - Shared app state across participants
- **App Communication** - Message passing between app instances (main client <-> meeting)
- **Media Controls** - Virtual backgrounds, camera listing, recording control
- **UI Controls** - Expand app, notifications, popout
- **Events** - React to meeting state, participants, sharing, and more
## Prerequisites
- Zoom app configured as **"Zoom App"** type in [Marketplace](https://marketplace.zoom.us/)
- OAuth credentials (Client ID + Secret) with Zoom Apps scopes
- Web application (Node.js + Express recommended)
- **Your domain whitelisted** in Marketplace domain allowlist
- ngrok or HTTPS tunnel for local development
- Node.js 18+ (for the backend server)
## Quick Start
### Option A: NPM (Recommended for frameworks)
```bash
npm install @zoom/appssdk
```
```javascript
import zoomSdk from '@zoom/appssdk';
async function init() {
try {
const configResponse = await zoomSdk.config({
capabilities: [
'shareApp',
'getMeetingContext',
'getUserContext',
'openUrl'
],
version: '0.16'
});
console.log('Running context:', configResponse.runningContext);
// 'inMeeting' | 'inMainClient' | 'inWebinar' | 'inImmersive' | ...
const context = await zoomSdk.getMeetingContext();
console.log('Meeting ID:', context.meetingID);
} catch (error) {
console.error('Not running inside Zoom:', error.message);
showDemoMode();
}
}
```
### Option B: CDN (Vanilla JS)
```html
<script src="https://appssdk.zoom.us/sdk.js"></script>
<script>
// CRITICAL: Do NOT declare "let zoomSdk" - the SDK defines window.zoomSdk globally
// Using "let zoomSdk = ..." causes: SyntaxError: redeclaration of non-configurable global property
let sdk = window.zoomSdk; // Use a different variable name
async function init() {
try {
const configResponse = await sdk.config({
capabilities: ['shareApp', 'getMeetingContext', 'getUserContext'],
version: '0.16'
});
console.log('Running context:', configResponse.runningContext);
} catch (error) {
console.error('Not running inside Zoom:', error.message);
showDemoMode();
}
}
function showDemoMode() {
document.body.innerHTML = '<h1>Preview Mode</h1><p>Open this app inside Zoom to use.</p>';
}
document.addEventListener('DOMContentLoaded', () => {
init();
setTimeout(() => { if (!sdk) showDemoMode(); }, 3000);
});
</script>
```
## Critical: Global Variable Conflict
The CDN script defines `window.zoomSdk` globally. **Do NOT redeclare it:**
```javascript
// WRONG - causes SyntaxError in Zoom's embedded browser
let zoomSdk = null;
zoomSdk = window.zoomSdk;
// CORRECT - use different variable name
let sdk = window.zoomSdk;
// ALSO CORRECT - NPM import (no conflict)
import zoomSdk from '@zoom/appssdk';
```
This only applies to the CDN approach. The NPM import creates a module-scoped variable, no conflict.
## Browser Preview / Demo Mode
The SDK only functions inside the Zoom client. When accessed in a regular browser:
- `window.zoomSdk` exists but `sdk.config()` throws an error
- Always implement try/catch with fallback UI
- Add timeout (3 seconds) in case SDK hangs
## URL Whitelisting (Required)
**Your app will NOT load in Zoom unless the domain is whitelisted.**
1. Go to [Zoom Marketplace](https://marketplace.zoom.us/)
2. Open your app -> **Feature** tab
3. Under **Zoom App**, find **Add Allow List**
4. Add your domain (e.g., `yourdomain.com` for production, `xxxxx.ngrok.io` for dev)
Without this, the Zoom client shows a blank panel with no error message.
## OAuth Scopes (Required)
Capabilities require matching OAuth scopes enabled in Marketplace:
| Capability | Required Scope |
|------------|----------------|
| `getMeetingContext` | `zoomapp:inmeeting` |
| `getUserContext` | `zoomapp:inmeeting` |
| `shareApp` | `zoomapp:inmeeting` |
| `openUrl` | `zoomapp:inmeeting` |
| `sendAppInvitation` | `zoomapp:inmeeting` |
| `runRenderingContext` | `zoomapp:inmeeting` |
| `authorize` | `zoomapp:inmeeting` |
| `getMeetingParticipants` | `zoomapp:inmeeting` |
**To add scopes:** Marketplace -> Your App -> **Scopes** tab -> Add required scopes.
Missing scopes = capability fails silently or throws error. Users must re-authorize if you add new scopes.
## Running Contexts
Your app runs in different surfaces within Zoom. The `configResponse.runningContext` tells you where:
| Context | Surface | Description |
|---------|---------|-------------|
| `inMeeting` | Meeting sidebar | Most common. Full meeting APIs available |
| `inMainClient` | Main client panel | Home tab. No meeting context APIs |
| `inWebinar` | Webinar sidebar | Host/panelist. Meeting + webinar APIs |
| `inImmersive` | Layers API | Full-screen custom rendering |
| `inCamera` | Camera mode | Virtual camera overlay |
| `inCollaborate` | Collaborate mode | Shared state context |
| `inPhone` | Zoom Phone | Phone call app |
| `inChat` | Team Chat | Chat sidebar |
See **[Running Contexts](concepts/running-contexts.md)** for context-specific behavior and APIs.
## SDK Initialization Pattern
Every Zoom App starts with `config()`:
```javascript
import zoomSdk from '@zoom/appssdk';
const configResponse = await zoomSdk.config({
capabilities: [
// List ALL APIs you will use
'getMeetingContext',
'getUserContext',
'shareApp',
'openUrl',
'authorize',
'onAuthorized'
],
version: '0.16'
});
// configResponse contains:
// {
// runningContext: 'inMeeting',
// clientVersion: '5.x.x',
// unsupportedApis: [] // APIs not supported in this client version
// }
```
**Rules:**
1. `config()` MUST be called before any other SDK method
2. Only capabilities listed in `config()` are available
3. Capabilities must match OAuth scopes in Marketplace
4. Check `unsupportedApis` for graceful degradation
## In-Client OAuth (Summary)
Best UX for authorization - no browser redirect:
```javascript
// 1. Get code challenge from your backend
const { codeChallenge, state } = await fetch('/api/auth/challenge').then(r => r.json());
// 2. Trigger in-client authorization
await zoomSdk.authorize({ codeChallenge, state });
// 3. Listen for authorization result
zoomSdk.addEventListener('onAuthorized', async (event) => {
const { code, state } = event;
// 4. Send code to backend for token exchange
await fetch('/api/auth/token', {
method: 'POST',
body: JSON.stringify({ code, state })
});
});
```
See **[In-Client OAuth Guide](examples/in-client-oauth.md)** for complete implementation.
## Layers API (Summary)
Build immersive video layouts and camera overlays:
```javascript
// Start immersive mode - replaces gallery view
await zoomSdk.runRenderingContext({ view: 'immersive' });
// Position participant video feeds
await zoomSdk.drawParticipant({
participantUUID: 'user-uuid',
x: 0, y: 0, width: 640, height: 480, zIndex: 1
});
// Add overlay images
await zoomSdk.drawImage({
imageData: canvas.toDataURL(),
x: 0, y: 0, width: 1280, height: 720, zIndex: 0
});
// Exit immersive mode
await zoomSdk.closeRenderingContext();
```
See **[Layers Immersive](examples/layers-immersive.md)** and **[Camera Mode](examples/layers-camera.md)**.
## Environment Variables
| Variable | Description | Where to Find |
|----------|-------------|---------------|
| `ZOOM_APP_CLIENT_ID` | App client ID | Marketplace -> App -> App Credentials |
| `ZOOM_APP_CLIENT_SECRET` | App client secret | Marketplace -> App -> App Credentials |
| `ZOOM_APP_REDIRECT_URI` | OAuth redirect URL | Your server URL + `/auth` |
| `SESSION_SECRET` | Cookie signing secret | Generate random string |
| `ZOOM_HOST` | Zoom host URL | `https://zoom.us` (or `https://zoomgov.com`) |
## Common APIs
| API | Description |
|-----|-------------|
| `config()` | Initialize SDK, request capabilities |
| `getMeetingContext()` | Get meeting ID, topic, status |
| `getUserContext()` | Get user name, role, participant ID |
| `getRunningContext()` | Get current running context |
| `getMeetingParticipants()` | List participants |
| `shareApp()` | Share app screen with participants |
| `openUrl({ url })` | Open URL in external browser |
| `sendAppInvitation()` | Invite users to open your app |
| `authorize()` | Trigger In-Client OAuth |
| `connect()` | Connect to other app instances |
| `postMessage()` | Send message to connected instances |
| `runRenderingContext()` | Start Layers API (immersive/camera) |
| `expandApp({ action })` | Expand/collapse app panel |
| `showNotification()` | Show notification in Zoom |
## Complete Documentation Library
### Core Concepts
- **[Architecture](concepts/architecture.md)** - Frontend/backend pattern, embedded browser, deep linking, X-Zoom-App-Context
- **[Running Contexts](concepts/running-contexts.md)** - All contexts, context-specific APIs, multi-instance communication
- **[Security](concepts/security.md)** - OWASP headers, CSP, cookie security, PKCE, token storage
### Complete Examples
- **[Quick Start](examples/quick-start.md)** - Hello World Express + SDK app
- **[In-Client OAuth](examples/in-client-oauth.md)** - PKCE authorization flow
- **[Layers Immersive](examples/layers-immersive.md)** - Custom video layouts
- **[Camera Mode](examples/layers-camera.md)** - Virtual camera overlays
- **[Collaborate Mode](examples/collaborate-mode.md)** - Shared state across participants
- **[Guest Mode](examples/guest-mode.md)** - Unauthenticated/authenticated/authorized states
- **[Breakout Rooms](examples/breakout-rooms.md)** - Room detection and cross-room state
- **[App Communication](examples/app-communication.md)** - connect + postMessage between instances
### Troubleshooting
- **[Common Issues](troubleshooting/common-issues.md)** - Quick diagnostics and error codes
- **[Debugging](troubleshooting/debugging.md)** - Local dev, ngrok, browser preview
- **[Migration](troubleshooting/migration.md)** - SDK version upgrade notes
### References
- **[API Reference](references/apis.md)** - All 100+ SDK methods
- **[Events Reference](references/events.md)** - All SDK event listeners
- **[Layers API Reference](references/layers-api.md)** - Drawing and rendering methods
- **[OAuth Reference](references/oauth.md)** - OAuth flows for Zoom Apps
- **[Zoom Mail](references/zmail-sdk.md)** - Mail plugin integration
## Sample Repositories
### Official (by Zoom)
| Repository | Type | Last Updated | Status | SDK Version |
|-----------|------|-------------|--------|-------------|
| [zoomapps-sample-js](https://github.com/zoom/zoomapps-sample-js) | Hello World (Vanilla JS) | Dec 2025 | Active | ^0.16.26 |
| [zoomapps-advancedsample-react](https://github.com/zoom/zoomapps-advancedsample-react) | Advanced (React + Redis) | Oct 2025 | Active | 0.16.0 |
| [zoomapps-customlayout-js](https://github.com/zoom/zoomapps-customlayout-js) | Layers API | Nov 2023 | Stale | ^0.16.8 |
| [zoomapps-texteditor-vuejs](https://github.com/zoom/zoomapps-texteditor-vuejs) | Collaborate (Vue + Y.js) | Oct 2023 | Stale | ^0.16.7 |
| [zoomapps-serverless-vuejs](https://github.com/zoom/zoomapps-serverless-vuejs) | Serverless (Firebase) | Aug 2024 | Stale | ^0.16.21 |
| [zoomapps-cameramode-vuejs](https://github.com/zoom/zoomapps-cameramode-vuejs) | Camera Mode | - | - | - |
| [zoomapps-workshop-sample](https://github.com/zoom/zoomapps-workshop-sample) | Workshop | - | - | - |
**Recommended for new projects:** Use `@zoom/appssdk` version `^0.16.26`.
### Community
| Type | Repository | Description |
|------|------------|-------------|
| Library | [harvard-edtech/zaccl](https://github.com/harvard-edtech/zaccl) | Zoom App Complete Connection Library |
**Full list**: See [general/references/community-repos.md](../general/references/community-repos.md)
### Learning Path
1. **Start**: `zoomapps-sample-js` - Simplest, most up-to-date
2. **Advanced**: `zoomapps-advancedsample-react` - Comprehensive (In-Client OAuth, Guest Mode, Collaborate)
3. **Specialized**: Pick based on feature (Layers, Serverless, Camera Mode)
## Critical Gotchas (From Real Development)
### 1. Global Variable Conflict
The CDN script defines `window.zoomSdk`. Declaring `let zoomSdk` in your code causes `SyntaxError: redeclaration of non-configurable global property`. Use `let sdk = window.zoomSdk` or the NPM import.
### 2. Domain Allowlist
Your app URL **must** be in the Marketplace domain allowlist. Without it, Zoom shows a blank panel with no error. Also add `appssdk.zoom.us` and any CDN domains you use.
### 3. Capabilities Must Be Listed
Only APIs listed in `config({ capabilities: [...] })` are available. Calling an unlisted API throws an error. This is also true for event listeners.
### 4. SDK Only Works Inside Zoom
`zoomSdk.config()` throws outside the Zoom client. Always wrap in try/catch with browser fallback:
```javascript
try { await zoomSdk.config({...}); } catch { showBrowserPreview(); }
```
### 5. ngrok URL Changes
Free ngrok URLs change on restart. You must update 4 places in Marketplace: Home URL, Redirect URL, OAuth Allow List, Domain Allow List. Consider ngrok paid plan for stable subdomain.
### 6. In-Client OAuth vs Web OAuth
Use `zoomSdk.authorize()` (In-Client) for best UX - no browser redirect. Only fall back to web redirect for initial install from Marketplace.
### 7. Camera Mode CEF Race Condition
Camera mode uses CEF which takes time to initialize. `drawImage`/`drawWebView` may fail if called too early. Implement retry with exponential backoff.
### 8. Cookie Configuration
Zoom's embedded browser requires cookies with `SameSite=None` and `Secure=true`. Without this, sessions break silently.
### 9. State Validation
Always validate the OAuth `state` parameter to prevent CSRF attacks. Generate cryptographically random state, store it, and verify on callback.
## Resources
- **Official docs**: https://developers.zoom.us/docs/zoom-apps/
- **SDK reference**: https://appssdk.zoom.us/
- **NPM package**: https://www.npmjs.com/package/@zoom/appssdk
- **Developer forum**: https://devforum.zoom.us/
- **GitHub SDK source**: https://github.com/zoom/appssdk
---
**Need help?** Start with Integrated Index section below for complete navigation.
---
## Integrated Index
_This section was migrated from `SKILL.md`._
## Quick Start Path
**If you're new to Zoom Apps, follow this order:**
1. **Run preflight checks first** -> [RUNBOOK.md](RUNBOOK.md)
2. **Read the architecture** -> [concepts/architecture.md](concepts/architecture.md)
- Frontend/backend pattern, embedded browser, deep linking
- Understand how Zoom loads and communicates with your app
3. **Build your first app** -> [examples/quick-start.md](examples/quick-start.md)
- Complete Express + SDK Hello World
- ngrok setup for local development
4. **Understand running contexts** -> [concepts/running-contexts.md](concepts/running-contexts.md)
- Where your app runs (inMeeting, inMainClient, inWebinar, etc.)
- Context-specific APIs and limitations
5. **Implement OAuth** -> [examples/in-client-oauth.md](examples/in-client-oauth.md)
- In-Client OAuth with PKCE (best UX)
- Token exchange and storage
6. **Add features** -> [references/apis.md](references/apis.md)
- 100+ SDK methods organized by category
- Code examples for each
7. **Troubleshoot** -> [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
- Quick diagnostics for common problems
---
## Documentation Structure
```
zoom-apps-sdk/
├── SKILL.md # Main skill overview
├── SKILL.md # This file - navigation guide
│
├── concepts/ # Core architectural patterns
│ ├── architecture.md # Frontend/backend, embedded browser, OAuth flow
│ ├── running-contexts.md # Where your app runs + context-specific APIs
│ └── security.md # OWASP headers, CSP, data access layers
│
├── examples/ # Complete working code
│ ├── quick-start.md # Hello World - minimal Express + SDK app
│ ├── in-client-oauth.md # In-Client OAuth with PKCE
│ ├── layers-immersive.md # Layers API - immersive mode (custom layouts)
│ ├── layers-camera.md # Layers API - camera mode (virtual camera)
│ ├── collaborate-mode.md # Collaborate mode (shared state)
│ ├── guest-mode.md # Guest mode (unauthenticated -> authorized)
│ ├── breakout-rooms.md # Breakout room integration
│ └── app-communication.md # connect + postMessage between instances
│
├── troubleshooting/ # Problem solving guides
│ ├── common-issues.md # Quick diagnostics, error codes
│ ├── debugging.md # Local dev setup, ngrok, browser preview
│ └── migration.md # SDK version migration notes
│
└── references/ # Reference documentation
├── apis.md # Complete API reference (100+ methods)
├── events.md # All SDK events
├── layers-api.md # Layers API detailed reference
├── oauth.md # OAuth flows for Zoom Apps
└── zmail-sdk.md # Zoom Mail integration
```
---
## By Use Case
### I want to build a basic Zoom App
1. [Architecture](concepts/architecture.md) - Understand the pattern
2. [Quick Start](examples/quick-start.md) - Build Hello World
3. [In-Client OAuth](examples/in-client-oauth.md) - Add authorization
4. [Security](concepts/security.md) - Required headers
### I want immersive video layouts (Layers API)
1. [Layers Immersive](examples/layers-immersive.md) - Custom video positions
2. [Layers API Reference](references/layers-api.md) - All drawing methods
3. [App Communication](examples/app-communication.md) - Sync layout across participants
### I want a virtual camera overlay
1. [Camera Mode](examples/layers-camera.md) - Camera mode rendering
2. [Layers API Reference](references/layers-api.md) - Drawing methods
### I want real-time collaboration
1. [Collaborate Mode](examples/collaborate-mode.md) - Shared state APIs
2. [App Communication](examples/app-communication.md) - Instance messaging
### I want guest/anonymous access
1. [Guest Mode](examples/guest-mode.md) - Three authorization states
2. [In-Client OAuth](examples/in-client-oauth.md) - promptAuthorize flow
### I want breakout room support
1. [Breakout Rooms](examples/breakout-rooms.md) - Room detection and state sync
### I want to sync between main client and meeting
1. [App Communication](examples/app-communication.md) - connect + postMessage
2. [Running Contexts](concepts/running-contexts.md) - Multi-instance behavior
### I want serverless deployment
1. [Quick Start](examples/quick-start.md) - Understand the base pattern first
2. Sample: [zoomapps-serverless-vuejs](https://github.com/zoom/zoomapps-serverless-vuejs) - Firebase pattern
### I want to add Zoom Mail integration
1. [Zoom Mail Reference](references/zmail-sdk.md) - REST API + mail plugins
### I'm getting errors
1. [Common Issues](troubleshooting/common-issues.md) - Quick diagnostic table
2. [Debugging](troubleshooting/debugging.md) - Local dev setup, DevTools
3. [Migration](troubleshooting/migration.md) - Version compatibility
---
## Most Critical Documents
### 1. Architecture (FOUNDATION)
**[concepts/architecture.md](concepts/architecture.md)**
Understand how Zoom Apps work: Frontend in embedded browser, backend for OAuth/API, SDK as the bridge. Without this, nothing else makes sense.
### 2. Quick Start (FIRST APP)
**[examples/quick-start.md](examples/quick-start.md)**
Complete working code. Get something running before diving into advanced features.
### 3. Common Issues (MOST COMMON PROBLEMS)
**[troubleshooting/common-issues.md](troubleshooting/common-issues.md)**
90% of Zoom Apps issues are: domain allowlist, global variable conflict, or missing capabilities.
---
## Key Learnings
### Critical Discoveries:
1. **Global Variable Conflict is the #1 Gotcha**
- CDN script defines `window.zoomSdk` globally
- `let zoomSdk = ...` causes SyntaxError in Zoom's browser
- Use `let sdk = window.zoomSdk` or NPM import
2. **Domain Allowlist is Non-Negotiable**
- App shows blank panel with zero error if domain not whitelisted
- Must include your domain AND `appssdk.zoom.us` AND any CDN domains
- ngrok URLs change on restart - must update Marketplace each time
3. **config() Gates Everything**
- Must be called first, must list all capabilities
- Unlisted capabilities throw errors
- Check `unsupportedApis` for client version compatibility
4. **In-Client OAuth > Web OAuth for UX**
- `authorize()` keeps user in Zoom (no browser redirect)
- Web redirect only needed for initial Marketplace install
- Always implement PKCE (code_verifier + code_challenge)
5. **Two App Instances Can Run Simultaneously**
- Main client instance + meeting instance
- Use `connect()` + `postMessage()` to sync between them
- Pre-meeting setup in main client, use in meeting
6. **Camera Mode Has CEF Quirks**
- CEF initialization takes time
- Draw calls may fail if too early
- Use retry with exponential backoff
7. **Cookie Settings Matter**
- `SameSite=None` + `Secure=true` required
- Without this, sessions silently fail in embedded browser
---
## Quick Reference
### "App shows blank panel"
-> [Domain Allowlist](troubleshooting/common-issues.md) - add domain to Marketplace
### "SyntaxError: redeclaration"
-> [Global Variable](troubleshooting/common-issues.md) - use `let sdk = window.zoomSdk`
### "config() throws error"
-> [Browser Preview](troubleshooting/debugging.md) - SDK only works inside Zoom
### "API call fails silently"
-> [OAuth Scopes](troubleshooting/common-issues.md) - add required scopes in Marketplace
### "How do I implement [feature]?"
-> [API Reference](references/apis.md) - find the method, check capabilities needed
### "How do I test locally?"
-> [Debugging Guide](troubleshooting/debugging.md) - ngrok + Marketplace config
---
## Document Version
Based on **@zoom/appssdk v0.16.x** (latest: 0.16.26+)
---
**Happy coding!**
Start with [Architecture](concepts/architecture.md) to understand the pattern, then [Quick Start](examples/quick-start.md) to build your first app.