| name | component-view |
| description | Embeds live Zoom meetings in a custom web container via Meeting SDK Component View (ZoomMtgEmbedded.createClient, Promise init/join, lowercase password). Use when integrating real Zoom meetings into React/Vue/Angular layouts with embeddable UI. Not for Zoom Video SDK custom sessions (ui-toolkit) and not for full-page callback-based Client View (passWord / #zmmtg-root). |
| version | 1.0.1 |
When to Use
Use this skill when the user needs to embed a real Zoom meeting inside a custom web UI container with a Promise-based (async/await) API. This is the correct web skill for:
- Custom layouts around a live Zoom meeting
- React, Vue, Angular, or any framework-based integration
- Applications requiring embeddable meeting components (not full-page takeover)
- Promise-based async/await patterns instead of callbacks
Do NOT route here if: the user is building a non-meeting custom session product — that belongs to the Video SDK. If the user wants full-page Zoom UI with callback-based APIs, use the Client View skill instead.
Prerequisites
- Node.js and npm installed on the development machine
- A Zoom Meeting SDK app registered in the Zoom App Marketplace (yields SDK Key / Client ID and SDK Secret)
- A backend endpoint to generate SDK JWT signatures (never expose SDK Secret in frontend code)
- A container
HTMLElement in the DOM where the meeting UI will render
- For SharedArrayBuffer-dependent features (gallery view, virtual background, etc.): proper COOP/COEP headers must be set on the hosting page. See
references/index.md → SharedArrayBuffer Setup
Procedure
1. Install the SDK
NPM (recommended):
npm install @zoom/meetingsdk --save
Import in your application:
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
CDN (alternative):
<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-embedded-{VERSION}.min.js"></script>
Replace {VERSION} with the exact SDK version you are targeting (e.g., 3.9.2). Do not mix versions across vendor scripts and the main embedded script.
2. Create the Client Instance (Once)
Create the client once — not on every render cycle. In React, store it in a useRef.
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
const client = ZoomMtgEmbedded.createClient();
3. Initialize the Client
Call client.init() with the container element and options:
async function joinMeeting() {
try {
const meetingSDKElement = document.getElementById('meetingSDKElement');
await client.init({
zoomAppRoot: meetingSDKElement,
language: 'en-US',
debug: true,
patchJsMedia: true,
leaveOnPageUnload: true,
});
} catch (error) {
console.error('Init failed:', error);
}
}
Required init parameter:
| Parameter | Type | Description |
|---|
zoomAppRoot | HTMLElement | Container element for meeting UI |
Optional init parameters:
| Parameter | Type | Default | Description |
|---|
language | string | 'en-US' | UI language |
debug | boolean | false | Enable debug logging |
patchJsMedia | boolean | false | Auto-apply media fixes |
leaveOnPageUnload | boolean | false | Cleanup on page unload |
enableHD | boolean | true | Enable 720p video |
enableFullHD | boolean | false | Enable 1080p video |
customize | object | — | UI customization options |
webEndpoint | string | — | For ZFG: 'www.zoomgov.com' |
assetPath | string | — | Custom path for AV libraries |
4. Join the Meeting
await client.join({
signature: signature,
sdkKey: sdkKey,
meetingNumber: meetingNumber,
userName: userName,
password: password,
userEmail: userEmail,
});
console.log('Joined successfully!');
Required join parameters:
| Parameter | Type | Description |
|---|
signature | string | SDK JWT from backend |
sdkKey | string | SDK Key / Client ID |
meetingNumber | string | number | Meeting number |
userName | string | Display name |
Conditional join parameters:
| Parameter | Type | When Required | Description |
|---|
password | string | If meeting has a password | Lowercase password — not passWord |
zak | string | Starting as host | Host's ZAK token |
tk | string | Registration required | Registrant token |
userEmail | string | Webinars | User email |
5. Register Event Listeners
Use client.on() / client.off() for event subscriptions:
client.on('connection-change', (payload) => {
console.log('Connection state:', payload.state);
if (payload.state === 'Closed') {
console.log('Reason:', payload.reason);
}
});
client.on('user-added', (payload) => {
payload.forEach(user => {
console.log('User ID:', user.oderId);
console.log('Name:', user.displayName);
});
});
client.on('user-removed', (payload) => console.log('Users removed:', payload));
client.on('user-updated', (payload) => console.log('Users updated:', payload));
client.on(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .(, payload));
client.(, .());
Always unsubscribe in cleanup (especially in React useEffect return):
client.off('connection-change', handleConnectionChange);
6. Use Common Methods
const currentUser = client.getCurrentUser();
const participants = client.getParticipantsList();
const isHost = client.isHost();
await client.mute(true);
await client.mute(false);
await client.muteAudio(userId, true);
await client.muteAllAudio(true);
await client.startVideo();
await client.stopVideo();
await client.muteVideo(userId, true);
client.leaveMeeting();
client.endMeeting();
await client.startShareScreen();
await client.stopShareScreen();
await client.startCloudRecording();
await client.stopCloudRecording();
isSupported = client.();
client.(imageUrl);
client.();
client.(userId, );
7. Customize the UI (Optional)
await client.init({
zoomAppRoot: element,
customize: {
meetingInfo: [
'topic', 'host', 'mn', 'pwd', 'telPwd',
'invite', 'participant', 'dc', 'enctype'
],
video: {
isResizable: true,
viewSizes: {
default: { width: 1000, height: 600 },
ribbon: { width: 300, height: 700 }
},
popper: { disableDraggable: false }
},
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'custom-btn',
onClick: () => console.log('Custom button clicked')
}
]
},
activeSpaker: {
strokeColor: '#00FF00'
}
}
});
8. Position and Resize
The container element size determines the meeting UI size. To resize dynamically:
document.getElementById('meetingSDKElement').style.width = '1200px';
document.getElementById('meetingSDKElement').style.height = '800px';
Enable user-resizable video via customize.video.isResizable: true.
9. React Integration Pattern
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 [isJoined, setIsJoined] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!clientRef.current) {
clientRef.current = ZoomMtgEmbedded.createClient();
}
}, []);
useEffect(() => {
if (!clientRef.current) return;
const handleConnectionChange = (payload: ) => {
(payload. === ) ();
(payload. === ) ();
};
= () => {
.(, payload);
};
clientRef..(, handleConnectionChange);
clientRef..(, handleUserAdded);
{
clientRef.?.(, handleConnectionChange);
clientRef.?.(, handleUserAdded);
};
}, []);
joinMeeting = ( () => {
(!clientRef. || !containerRef.) ;
{
{ signature, sdkKey } = (meetingNumber);
clientRef..({
: containerRef.,
: ,
: ,
: ,
});
clientRef..({
signature,
sdkKey,
meetingNumber,
password,
userName,
});
();
} (err) {
(err ? err. : );
}
}, [meetingNumber, password, userName]);
(
);
}
10. Handle Errors
try {
await client.join({ });
} catch (error) {
switch (error.reason) {
case 'WRONG_MEETING_PASSWORD':
console.error('Incorrect password');
break;
case 'MEETING_NOT_START':
console.error('Meeting has not started');
break;
case 'INVALID_PARAMETERS':
console.error('Invalid join parameters');
break;
default:
console.error('Join failed:', error.message);
}
}
For a full list of error codes, load references/index.md and navigate to the error-codes reference.
Pitfalls
-
Password parameter name is lowercase password — Component View uses password, NOT passWord (which is Client View). Mixing these up silently fails to authenticate.
-
Creating the client on every render — In React, calling ZoomMtgEmbedded.createClient() inside a render function (not in a useRef or module scope) causes duplicate client instances and meeting UI corruption. Create once, reuse.
-
SDK Secret in frontend code — Never embed the SDK Secret in client-side code. Always generate the SDK JWT signature on a backend endpoint and fetch it from the frontend.
-
Missing COOP/COEP headers — Gallery view, virtual background, and other SharedArrayBuffer-dependent features silently fail without proper cross-origin isolation headers. See references/index.md → SharedArrayBuffer Setup.
-
Not unsubscribing events — In React, forgetting client.off() in the useEffect cleanup function causes duplicate event handlers after re-renders, leading to duplicate callbacks and memory leaks.
-
SDK property spelling quirks — The SDK uses oderId (not orderId) in user payloads and activeSpaker (not activeSpeaker) in the customize object. Use the exact SDK spellings.
-
Mixing CDN script versions — All vendor scripts and the main embedded script must use the same {VERSION}. Mismatched versions cause runtime errors.
-
Container element not in DOM at init time — zoomAppRoot must be a real HTMLElement when client.init() is called. In React, ensure the ref is populated before calling init (e.g., trigger join on user click, not on mount before paint).
-
Component View vs Client View feature gaps — Some features available in Client View may not be available in Component View. Check the supported features table below before committing to Component View.
Verification
Verify SDK Installation
npm ls @zoom/meetingsdk
Expected output: @zoom/meetingsdk@{VERSION} with no UNMET DEPENDENCY warnings.
Verify Client Creation
const client = ZoomMtgEmbedded.createClient();
console.log(typeof client.init);
console.log(typeof client.join);
console.log(typeof client.on);
Verify Init and Join
try {
await client.init({
zoomAppRoot: document.getElementById('meetingSDKElement'),
language: 'en-US',
});
console.log('Init OK');
await client.join({
signature: 'YOUR_SIGNATURE',
sdkKey: 'YOUR_SDK_KEY',
meetingNumber: '123456789',
userName: 'Test User',
});
console.log('Join OK');
} catch (error) {
console.error('Error reason:', error.reason);
console.error('Error message:', error.message);
}
Verify Connection Event
client.on('connection-change', (payload) => {
console.log('State:', payload.state);
});
Verify Supported Features
| Feature | Supported |
|---|
| Audio/Video | ✅ |
| Screen Share | ✅ |
| Chat | ✅ |
| Virtual Background | ✅ |
| Breakout Rooms | ✅ |
| Cloud Recording | ✅ |
| Closed Captions | ✅ |
| Live Transcription | ✅ |
| Waiting Room | ✅ |
| Gallery View | ✅ |
| Reactions | ✅ |
| Raise Hand | ✅ |
Contact Zoom Developer Support to request additional features not listed here.
Component View vs Client View Quick Reference
| Aspect | Component View | Client View |
|---|
| API Style | Promises (async/await) | Callbacks |
| Password param | password | passWord |
| Container | Custom element | Auto #zmmtg-root |
| UI | Embeddable | Full-page |
| Preloading | Not needed | preLoadWasm() |
| Language | Init option | i18n.load() |
| Events | on() / off() | inMeetingServiceListener() |
Related Skills
References
Load these reference files from the references/ directory when needed:
references/index.md — Load first for a full index of available reference documents, including error codes, common issues, and SharedArrayBuffer setup guides.
- Error Codes — Load when debugging
error.reason values from client.join() failures.
- Common Issues — Load when encountering unexpected SDK behavior or integration problems.
- SharedArrayBuffer Setup — Load when gallery view, virtual background, or other advanced media features are not working (COOP/COEP header configuration).
Operations
RUNBOOK.md — Load when performing a preflight check before deployment or when debugging a failed meeting join. Contains a 5-minute checklist.