Zoom Meeting SDK Web — Client View
Client View renders a full-page Zoom meeting experience identical to the Zoom Web Client.
It uses the ZoomMtg global singleton with a callback-based API — minimal customization,
familiar Zoom UI, fast integration.
| Aspect | Details |
|---|---|
| API Object | ZoomMtg (global singleton) |
| API Style | Callback-based (success / error) |
| UI | Full-page takeover (occupies entire viewport) |
| Password param | passWord — capital W |
| Events | ZoomMtg.inMeetingServiceListener() |
| Best For | Quick integration, standard Zoom UI, minimal branding needs |
When to Use
- You need to embed a complete Zoom meeting in a web app with the standard Zoom interface.
- You want minimal customization — Client View gives you Zoom's own UI, not a custom layout.
- You are integrating via NPM or CDN and need the callback-based
ZoomMtgAPI. - You are debugging blank screen, black overlay, join payload, or SPA z-index issues.
- You need to wire up event listeners (user join/leave, chat, recording, breakout rooms, etc.).
Do NOT use Client View if you need pixel-level control over the meeting UI layout — use Component View instead (see Related Skills).
Prerequisites
- Zoom Meeting SDK credentials — SDK Key and SDK Secret (or Server-to-Server OAuth app credentials) from the Zoom App Marketplace.
- Backend endpoint to generate the SDK JWT signature. Never expose SDK secrets in the
browser. Example placeholder:
YOUR_SDK_SECRET. - HTTPS — required for media (WebRTC) and SharedArrayBuffer (gallery view).
- Supported browser — call
ZoomMtg.checkSystemRequirements()to verify. - Node.js 18+ if using the NPM package.
- Windows host (PowerShell) is the primary development environment. All path examples use
Windows-style paths (e.g.
~\agent-skills\library\client-view\).
Reference Files
Load these reference files at the indicated points:
| File | When to Load |
|---|---|
references/index.md |
At the start — lists all available reference docs and their purposes. |
../troubleshooting/error-codes.md |
When debugging join failures, init errors, or unexpected SDK errors. |
../troubleshooting/common-issues.md |
When encountering black screen, audio issues, or CORS errors. |
../concepts/sharedarraybuffer.md |
When enabling gallery view or multi-speaker view (requires SharedArrayBuffer + COOP/COEP headers). |
RUNBOOK.md |
Before deploying or debugging — 5-minute preflight and debugging checklist. |
Procedure
Step 1 — Install the SDK
NPM (recommended for bundlers):
npm install @zoom/meetingsdk --save
import { ZoomMtg } from '@zoom/meetingsdk';
CDN (script tags — replace {VERSION} with your target SDK version):
<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>
<script src="https://source.zoom.us/zoom-meeting-{VERSION}.min.js"></script>
Step 2 — Complete Initialization Flow
This is the canonical 7-step flow. Follow it in order — skipping steps causes black screens and join failures.
// Step 1: Check browser compatibility
console.log('Requirements:', ZoomMtg.checkSystemRequirements());
// Step 2: Set CDN path (optional — for China region or custom hosting)
// ZoomMtg.setZoomJSLib('https://source.zoom.us/{VERSION}/lib', '/av');
// Step 3: Preload WebAssembly modules
ZoomMtg.preLoadWasm();
ZoomMtg.prepareWebSDK();
// Step 4: Load language resources
ZoomMtg.i18n.load('en-US');
ZoomMtg.i18n.onLoad(() => {
// Step 5: Initialize SDK
ZoomMtg.init({
leaveUrl: '/meeting-ended',
patchJsMedia: true,
disableCORP: !window.crossOriginIsolated,
success: () => {
console.log('SDK initialized');
// Step 6: Join meeting
const joinPayload = {
signature: signature,
meetingNumber: meetingNumber,
userName: userName,
passWord: passWord,
success: (res) => {
console.log('Joined meeting');
// Step 7: Post-join operations
ZoomMtg.getAttendeeslist({});
ZoomMtg.getCurrentUser({
success: (res) => console.log('Current user:', res.result.currentUser)
});
},
error: (err) => console.error('Join failed:', err)
};
// CRITICAL: only include optional fields when they have real values.
// Passing undefined for optional fields can cause runtime join errors.
if (userEmail) joinPayload.userEmail = userEmail;
if (tk) joinPayload.tk = tk;
if (zak) joinPayload.zak = zak;
ZoomMtg.join(joinPayload);
},
error: (err) => console.error('Init failed:', err)
});
});
Step 3 — Configure ZoomMtg.init() Options
Required
| Parameter | Type | Description |
|---|---|---|
leaveUrl |
string |
URL to redirect to after leaving the meeting |
UI Customization
| Parameter | Type | Default | Description |
|---|---|---|---|
showMeetingHeader |
boolean |
true |
Show meeting number and topic |
disableInvite |
boolean |
false |
Hide invite button |
disableCallOut |
boolean |
false |
Hide call out option |
disableRecord |
boolean |
false |
Hide record button |
disableJoinAudio |
boolean |
false |
Hide join audio option |
disablePreview |
boolean |
false |
Skip audio/video preview |
audioPanelAlwaysOpen |
boolean |
false |
Keep audio panel open |
showPureSharingContent |
boolean |
false |
Prevent overlays on shared content |
videoHeader |
boolean |
true |
Show video tile header |
isLockBottom |
boolean |
true |
Show/hide footer |
videoDrag |
boolean |
true |
Enable dragging video tiles |
sharingMode |
string |
'both' |
'both' or 'fit' |
screenShare |
boolean |
true |
Enable browser URL sharing |
hideShareAudioOption |
boolean |
false |
Hide "Share tab audio" checkbox |
disablePictureInPicture |
boolean |
false |
Disable PiP mode |
disableZoomLogo |
boolean |
false |
Remove Zoom logo (deprecated) |
defaultView |
string |
'speaker' |
'gallery', 'speaker', or 'multiSpeaker' |
Feature Toggles
| Parameter | Type | Default | Description |
|---|---|---|---|
isSupportAV |
boolean |
true |
Enable audio/video |
isSupportChat |
boolean |
true |
Enable in-meeting chat |
isSupportQA |
boolean |
true |
Enable webinar Q&A |
isSupportCC |
boolean |
true |
Enable closed captions |
isSupportPolling |
boolean |
true |
Enable polling |
isSupportBreakout |
boolean |
true |
Enable breakout rooms |
isSupportNonverbal |
boolean |
true |
Enable nonverbal feedback |
isSupportSimulive |
boolean |
false |
Enable Simulive |
disableVoIP |
boolean |
false |
Disable VoIP |
disableReport |
boolean |
false |
Disable report feature |
Video Quality
| Parameter | Type | Default | Description |
|---|---|---|---|
enableHD |
boolean |
true (≥2.8.0) |
Enable 720p video |
enableFullHD |
boolean |
false |
Enable 1080p for webinar attendees |
Advanced
| Parameter | Type | Default | Description |
|---|---|---|---|
debug |
boolean |
false |
Enable debug logging |
patchJsMedia |
boolean |
false |
Auto-apply media fixes |
disableCORP |
boolean |
false |
Disable web isolation |
helper |
string |
'' |
Path to helper.html |
externalLinkPage |
string |
— | Page for external links |
webEndpoint |
string |
— | For ZFG environments |
leaveOnPageUnload |
boolean |
false |
Auto cleanup on page close |
isShowJoiningErrorDialog |
boolean |
true |
Show error dialog on join failure |
meetingInfo |
Array<string> |
[...] |
Meeting info fields to display |
inviteUrlFormat |
string |
'' |
Custom invite URL format |
loginWindow |
object |
{width: 400, height: 380} |
Login popup size |
Callbacks
| Parameter | Type | Description |
|---|---|---|
success |
Function |
Called on successful init |
error |
Function |
Called on init failure |
Step 4 — Configure ZoomMtg.join() Options
Required
| Parameter | Type | Description |
|---|---|---|
signature |
string |
SDK JWT from backend (v5.0+: must include appKey prefix) |
meetingNumber |
string | number |
Meeting or webinar number |
userName |
string |
Display name |
passWord |
string |
Meeting password (capital W) |
Authentication (conditional)
| Parameter | Type | When Required | Description |
|---|---|---|---|
zak |
string |
Starting as host | Host's Zoom Access Key |
tk |
string |
Registration required | Registrant token |
userEmail |
string |
Webinars | User email |
obfToken |
string |
March 2026+ | App Privilege Token |
Optional
| Parameter | Type | Description |
|---|---|---|
customerKey |
string |
Custom ID (max 36 chars) |
recordingToken |
string |
Local recording permission |
Callbacks
| Parameter | Type | Description |
|---|---|---|
success |
Function |
Called on successful join |
error |
Function |
Called on join failure |
Step 5 — Wire Event Listeners
Register listeners after ZoomMtg.init() success, before or inside join() success.
User Events
ZoomMtg.inMeetingServiceListener('onUserJoin', (data) => {
console.log('User joined:', data);
// { userId, userName, ... }
});
ZoomMtg.inMeetingServiceListener('onUserLeave', (data) => {
console.log('User left:', data);
// Reason codes:
// 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);
});
ZoomMtg.inMeetingServiceListener('onUserIsInWaitingRoom', (data) => {
console.log('User in waiting room:', data);
});
Meeting Status
ZoomMtg.inMeetingServiceListener('onMeetingStatus', (data) => {
// status: 1=connecting, 2=connected, 3=disconnected, 4=reconnecting
console.log('Status:', data.status);
});
Audio/Video Events
ZoomMtg.inMeetingServiceListener('onActiveSpeaker', (data) => {
// [{userId, userName}]
console.log('Active speaker:', data);
});
ZoomMtg.inMeetingServiceListener('onNetworkQualityChange', (data) => {
// {level: 0-5, userId, type: 'uplink'}
// 0-1=bad, 2=normal, 3-5=good
console.log('Network quality:', data);
});
ZoomMtg.inMeetingServiceListener('onAudioQos', (data) => {
console.log('Audio QoS:', data);
});
ZoomMtg.inMeetingServiceListener('onVideoQos', (data) => {
console.log('Video QoS:', data);
});
Chat & Communication
ZoomMtg.inMeetingServiceListener('onReceiveChatMsg', (data) => {
console.log('Chat message:', data);
});
ZoomMtg.inMeetingServiceListener('onReceiveTranscriptionMsg', (data) => {
console.log('Transcription:', data);
});
ZoomMtg.inMeetingServiceListener('onReceiveTranslateMsg', (data) => {
console.log('Translation:', data);
});
Recording & Sharing
ZoomMtg.inMeetingServiceListener('onRecordingChange', (data) => {
console.log('Recording status:', data);
});
ZoomMtg.inMeetingServiceListener('onShareContentChange', (data) => {
console.log('Share content:', data);
});
ZoomMtg.inMeetingServiceListener('receiveSharingChannelReady', (data) => {
console.log('Sharing channel ready:', data);
});
Breakout Rooms
ZoomMtg.inMeetingServiceListener('onRoomStatusChange', (data) => {
// status: 2=InProgress, 3=Closing, 4=Closed
console.log('Breakout room status:', data);
});
Other Events
ZoomMtg.inMeetingServiceListener('onJoinSpeed', (data) => {
console.log('Join metrics:', data);
});
ZoomMtg.inMeetingServiceListener('onVbStatusChange', (data) => {
console.log('Virtual background status:', data);
});
ZoomMtg.inMeetingServiceListener('onFocusModeStatusChange', (data) => {
console.log('Focus mode:', data);
});
ZoomMtg.inMeetingServiceListener('onPictureInPicture', (data) => {
console.log('PiP status:', data);
});
ZoomMtg.inMeetingServiceListener('onClaimStatus', (data) => {
console.log('Host claim status:', data);
});
Step 6 — Use Common Methods (as needed)
Meeting Info
ZoomMtg.getCurrentUser({
success: (res) => console.log(res.result.currentUser)
});
ZoomMtg.getAttendeeslist({});
ZoomMtg.getCurrentMeetingInfo({
success: (res) => console.log(res)
});
ZoomMtg.getWebSDKVersion({
success: (version) => console.log(version)
});
Audio/Video Control
ZoomMtg.mute({ userId, mute: true });
ZoomMtg.muteAll({ muteAll: true });
ZoomMtg.stopIncomingAudio({ stop: true });
ZoomMtg.mirrorVideo({ mirror: true });
Chat
ZoomMtg.sendChat({
message: 'Hello!',
userId: 0 // 0 = everyone
});
Meeting Control
ZoomMtg.leaveMeeting({});
ZoomMtg.endMeeting({}); // host only
ZoomMtg.lockMeeting({ lock: true });
Host Controls
ZoomMtg.makeHost({ userId });
ZoomMtg.makeCoHost({ userId });
ZoomMtg.withdrawCoHost({ userId });
ZoomMtg.expel({ userId });
ZoomMtg.putOnHold({ userId, bHold: true });
ZoomMtg.claimHostWithHostKey({ hostKey: '123456' });
ZoomMtg.reclaimHost({});
ZoomMtg.admitAll({});
Raise Hand
ZoomMtg.raiseHand({ userId });
ZoomMtg.lowerHand({ oderId });
ZoomMtg.lowerAllHands({});
Spotlight & Pin
ZoomMtg.operateSpotlight({ oderId, action: 'add' }); // or 'remove'
ZoomMtg.operatePin({ oderId, action: 'add' }); // or 'remove'
ZoomMtg.allowMultiPin({ allow: true });
Screen Share
ZoomMtg.startScreenShare({});
ZoomMtg.shareSource({ source }); // Electron only
Recording
ZoomMtg.record({ record: true }); // or false
ZoomMtg.showRecordFunction({ show: true });
Breakout Rooms
ZoomMtg.createBreakoutRoom({
rooms: [{ name: 'Room 1' }, { name: 'Room 2' }]
});
ZoomMtg.openBreakoutRooms({});
ZoomMtg.closeBreakoutRooms({});
ZoomMtg.joinBreakoutRoom({ roomId });
ZoomMtg.leaveBreakoutRoom({});
ZoomMtg.moveUserToBreakoutRoom({ oderId, roomId });
ZoomMtg.getBreakoutRoomStatus({
success: (res) => console.log(res)
});
Virtual Background
ZoomMtg.isSupportVirtualBackground({
success: (data) => console.log(data.result.isSupport)
});
ZoomMtg.setVirtualBackground({ imageUrl: '...' });
ZoomMtg.getVirtualBackgroundStatus({
success: (data) => console.log(data)
});
ZoomMtg.lockVirtualBackground({ lock: true });
UI Control
ZoomMtg.showMeetingHeader({ show: true });
ZoomMtg.showInviteFunction({ show: true });
ZoomMtg.showJoinAudioFunction({ show: true });
ZoomMtg.showCalloutFunction({ show: true });
ZoomMtg.reRender({ lang: 'de-DE' });
Language
ZoomMtg.i18n.load('de-DE');
ZoomMtg.i18n.reload('de-DE');
ZoomMtg.i18n.getCurrentLang();
ZoomMtg.i18n.getAll();
Pitfalls
HARD RULES (do not violate)
passWord— capital W. The join parameter ispassWord, notpassword. Using the wrong casing silently fails the join.Never pass
undefinedfor optional join fields. IfuserEmail,tk,zak, or other optional fields areundefined, the SDK can throwCannot read properties of undefined (reading 'toString')and the screen turns black. Only attach keys when they are non-empty strings.Never expose SDK credentials in the browser. The
signature(SDK JWT) must be generated on a backend. Use placeholderYOUR_SDK_SECRETin all example code — never commit real secrets.Do NOT manually create or remove
#zmmtg-rootor#aria-notify-area. The SDK creates these DOM elements automatically. Manual manipulation breaks rendering.Rate limits are enforced — do not exceed:
Method Limit join()10 seconds between calls callOut()10 seconds between calls mute()1 second between calls muteAll()5 seconds between calls defaultView: 'gallery'requires SharedArrayBuffer. Without COOP/COEP headers andcrossOriginIsolated === true, gallery view fails silently. UsedefaultView: 'speaker'unless you have fully configured SharedArrayBuffer. Load../concepts/sharedarraybuffer.mdbefore attempting gallery or multi-speaker view.disableCORPmust reflectcrossOriginIsolatedstatus. Always setdisableCORP: !window.crossOriginIsolated— hardcodingfalsewithout cross-origin isolation breaks media.
SPA (React/Next) Overlay Gotcha
If you call join() but see a blank or black area instead of the meeting UI, the Zoom
UI is likely rendering behind your app shell. Ensure #zmmtg-root occupies the viewport
and sits above all other fixed elements:
#zmmtg-root {
position: fixed !important;
inset: 0 !important;
z-index: 9999 !important;
}
Join Payload Sanitization Gotcha
If ZoomMtg.join() appears to succeed but the screen turns black and the console shows
Cannot read properties of undefined (reading 'toString'), you are passing undefined for
an optional field. Build the payload object with only required fields first, then
conditionally add optional fields:
const joinPayload = {
signature,
meetingNumber,
userName,
passWord,
success: (res) => { /* ... */ },
error: (err) => { /* ... */ }
};
if (userEmail) joinPayload.userEmail = userEmail;
if (tk) joinPayload.tk = tk;
if (zak) joinPayload.zak = zak;
ZoomMtg.join(joinPayload);
CDN Version Mismatch
All CDN script tags must use the same {VERSION}. Mixing versions of React, Redux, or
the Zoom SDK causes silent failures. Verify version consistency across all <script> tags.
i18n.load Must Complete Before init
ZoomMtg.init() must be called inside the i18n.onLoad() callback. Calling init()
before language resources finish loading causes rendering issues.
Verification
1. Check System Requirements
console.log('Requirements:', ZoomMtg.checkSystemRequirements());
Confirm the output lists your browser as supported.
2. Verify SDK Initialization
After ZoomMtg.init() success callback fires, check the console for SDK initialized.
If the error callback fires, load ../troubleshooting/error-codes.md and match the error code.
3. Verify Join Success
After ZoomMtg.join() success callback fires, check the console for Joined meeting.
Then verify post-join calls return data:
ZoomMtg.getCurrentUser({
success: (res) => {
console.log('Current user:', res.result.currentUser);
// Should print a user object with userId, userName, etc.
}
});
ZoomMtg.getAttendeeslist({});
// Should return the attendees list object
4. Verify DOM Elements Exist
Open browser DevTools → Elements and confirm these elements exist (created by the SDK):
#zmmtg-root— main meeting container#aria-notify-area— accessibility announcements
5. Verify Event Listeners Fire
ZoomMtg.inMeetingServiceListener('onMeetingStatus', (data) => {
console.log('Status:', data.status);
// Expect: 1 (connecting) → 2 (connected)
});
6. Verify SDK Version
ZoomMtg.getWebSDKVersion({
success: (version) => console.log('SDK version:', version)
});
Confirm the version matches your installed NPM package or CDN script version.
7. Run the Preflight Checklist
Load RUNBOOK.md and follow the 5-minute preflight checklist before deploying to production.
Related Skills
- Main Web SDK Skill —
../SKILL.md— overview of all Web SDK views and shared concepts. - Component View —
../component-view/SKILL.md— for custom UI layouts with embedded Zoom video tiles instead of full-page takeover. - Reference Index —
references/index.md— complete list of reference docs. - Error Codes —
../troubleshooting/error-codes.md— SDK error code lookup. - Common Issues —
../troubleshooting/common-issues.md— black screen, audio, CORS fixes. - SharedArrayBuffer Setup —
../concepts/sharedarraybuffer.md— COOP/COEP configuration for gallery view. - Official API Reference — marketplacefront.zoom.us/sdk/meeting/web/index.html