Import the SDK
Import the Meeting SDK for web into your project via npm or the Meeting SDK CDN. Component view is designed specifically for desktop browser use cases, not mobile environments. For mobile use cases, use client view.
Import via npm
If you installed the Meeting SDK via npm, import ZoomMtgEmbedded in the component file where you want to use the Meeting SDK.
import ZoomMtgEmbedded from "@zoom/meetingsdk/embedded";
Import via CDN
If you installed the Meeting SDK via the CDN, ZoomMtgEmbedded should already be available in the window.
Initialize the Meeting SDK
After you've imported the Meeting SDK component view, add an HTML element where you want to render the Meeting SDK and give it an id.
<!-- Meeting SDK renders here when a user starts or joins a Zoom meeting -->
In your component file, create the client, init the Meeting SDK, and pass in the HTML element from above.
const client = ZoomMtgEmbedded.createClient();
let meetingSDKElement = document.getElementById("meetingSDKElement");
client.init({ zoomAppRoot: meetingSDKElement, language: "en-US" });
Dependent assets
The assetPath property in the init function object determines where to find the Meeting SDK WebAssembly assets.
- If blank, the default is to use the Zoom hosted assets.
- To self-host these assets, pass in your own URL where you are hosting the assets. Find the assets here. Be sure to update these assets each time you upgrade the SDK. Each version includes updated assets in the SDK package.
Set patchJsMedia to true in the init function object to point to the latest branch of the dependent assets, instead of a specific version. This allows you to receive hot fixes within the dependent assets automatically. By default, patchJsMedia is false.
For the full set of client.init() properties, see InitOptions in the SDK reference.
Using Angular
When using the SDK with Angular, you must run the SDK outside the Angular zone and set up a zone-flags.ts file to disable unnecessary change detection and avoid performance issues.
In the src directory, create a zone-flags.ts file and add the following code:
// disable patching requestAnimationFrame
(window as any).__Zone_disable_requestAnimationFrame = true;
// disable patching specified eventNames
(window as any).__zone_symbol__UNPATCHED_EVENTS = ['message'];
Then, in your angular.json file in the polyfills array, add "src/zone-flags.ts" before zone.js.
"polyfills": [
"src/zone-flags.ts",
"zone.js"
]
Also add it to your tsconfig.app.json file in the include array:
"include": [
"src/**/*.d.ts",
"src/zone-flags.ts"
]
Finally, in your file where you are calling the init and join functions, run them outside the Angular zone. See the example for details.
Meeting SDK for web component view Angular example
import { Component, NgZone } from '@angular/core';
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
client = ZoomMtgEmbedded.createClient();
// ...
constructor(private ngZone: NgZone) {
}
join() {
let meetingSDKElement = document.getElementById('meetingSDKElement');
this.ngZone.runOutsideAngular(() => {
this.client.init({ zoomAppRoot: meetingSDKElement, language: 'en-US' }).then(() => {
this.client.join({
signature: signature, // role in SDK signature needs to be 1
meetingNumber: meetingNumber,
password: password,
userName: userName,
zak: zakToken // the host's zak token
})
})
})
}
// ...
}
Troubleshooting RequireJS
If you use RequireJS in your implementation and receive the error ReferenceError: JsMediaSDK_Instance is not defined, try this workaround (be sure to use the latest version).
// Config the external lib
requirejs.config({
paths: {
WebMeetingSDK:
"https://source.zoom.us/#.#.#/zoomus-websdk-embedded.umd.min",
JsMediaSDK_Instance: "https://source.zoom.us/#.#.#/lib/av/js_media.min",
"disk-file-writer": "https://source.zoom.us/#.#.#/lib/av/js_media.min",
},
});
// Convert the callback approach of requirejs into a promise-based approach.
async function loadZoomVideo() {
return new Promise((resolve, reject) => {
requirejs(
["disk-file-writer", "ZoomMtgEmbedded"],
(_, ZoomMtgEmbedded) => {
return new Promise((resolve, reject) => {
requirejs(
["JsMediaSDK_Instance"],
(JsMediaSDK_Instance) => {
window.JsMediaSDK_Instance = JsMediaSDK_Instance;
resolve();
},
);
}).then(() => {
resolve(ZoomMtgEmbedded);
});
},
);
});
}
Avoid CSS conflicts in host applications
Component view renders the meeting UI inside the container you pass to client.init({ zoomAppRoot }) and loads its global stylesheet (based on Bootstrap and React Select) into the host document and injects #aria-notify-area and overlay nodes directly into <body>.
Conflicts can occur when the host uses a CSS reset, a utility-first framework such as Tailwind CSS, or a component library such as Bootstrap or MUI, which redefine base selectors (body, *, headings, button) that the SDK also relies on.
Mitigate this using one of the following options, listed by isolation strength, strongest first.
Option 1 - Dedicated route or subdomain (recommended)
Mount component view on a dedicated route (for example, /meeting) or subdomain (for example, meeting.example.com) that does not load your application's global CSS framework or reset. Because the SDK and your host UI never coexist on the same page, conflicts cannot occur.
Option 2 - iFrame embed
Embed component view in an <iframe> so the SDK stylesheet and your embed container live in a separate document from your host application. See Best practices using the Meeting SDK in an iFrame for setup details, including the required allow attributes for camera, microphone, and screen sharing.
Option 3 - Scope host styles away from the SDK roots
Wrap your host application's global rules in a :not() selector that excludes your embed container and the SDK's accessibility overlay. Replace #meetingSDKElement with the ID of the element you pass to zoomAppRoot:
body > *:not(#meetingSDKElement):not(#aria-notify-area) {
/* host application's global styles */
}
If your embed container is not a direct child of <body>, the body > * combinator will not match it. In that case, scope host rules under a wrapper class instead. Future SDK releases may also add new top-level elements that you would need to add to the :not() chain manually.
Comparison
| Option | Isolation | Effort | Stability |
|---|---|---|---|
| Dedicated route or subdomain | Strongest | Medium, routing and code split | Highest |
| iFrame embed | Strong | Higher, cross-frame messaging | High |
:not() scoping | Weakest | Low, CSS-only change | Low, fragile to SDK updates |