partner-built/zoom-plugin/skills/ui-toolkit/SKILL.md
Reference skill for Zoom Video SDK UI Toolkit. Use after routing to a web video workflow when you want prebuilt React UI instead of building a fully custom Video SDK interface.
npx skillsauth add anthropics/knowledge-work-plugins ui-toolkit/webInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Background reference for the prebuilt Zoom Video SDK UI Toolkit on web. Prefer choose-zoom-approach first when the user might still need Meeting SDK instead.
Official Documentation: https://developers.zoom.us/docs/video-sdk/web/ui-toolkit/ API Reference: https://marketplacefront.zoom.us/sdk/uitoolkit/web/ NPM Package: https://www.npmjs.com/package/@zoom/videosdk-zoom-ui-toolkit Live Demo: https://sdk.zoom.com/videosdk-uitoolkit
New to UI Toolkit? Follow this path:
Having issues?
The Zoom Video SDK UI Toolkit is a pre-built video UI library that renders complete video conferencing experiences with minimal code. Unlike the raw Video SDK, the UI Toolkit provides:
When to use UI Toolkit:
When to use raw Video SDK instead:
npm install @zoom/videosdk-zoom-ui-toolkit jsrsasign
npm install -D @types/jsrsasign
Note: React support depends on the UI Toolkit version. Check the package peer dependencies for your installed version (React 18 is commonly required).
import uitoolkit from "@zoom/videosdk-zoom-ui-toolkit";
import "@zoom/videosdk-ui-toolkit/dist/videosdk-zoom-ui-toolkit.css";
const container = document.getElementById("sessionContainer");
const config = {
videoSDKJWT: "your_jwt_token",
sessionName: "my-session",
userName: "John Doe",
sessionPasscode: "",
features: ["video", "audio", "share", "chat", "users", "settings"],
};
uitoolkit.joinSession(container, config);
uitoolkit.onSessionJoined(() => {
console.log("Session joined");
});
uitoolkit.onSessionClosed(() => {
console.log("Session closed");
});
'use client';
import { useEffect, useRef } from 'react';
export default function VideoSession({ jwt, sessionName, userName }) {
const containerRef = useRef<HTMLDivElement>(null);
const uitoolkitRef = useRef<any>(null);
useEffect(() => {
let isMounted = true;
const init = async () => {
const uitoolkitModule = await import('@zoom/videosdk-zoom-ui-toolkit');
const uitoolkit = uitoolkitModule.default;
uitoolkitRef.current = uitoolkit;
// If TypeScript complains about CSS imports, configure your app to allow them
// (for example via a global `declare module \"*.css\";`), or import the CSS from
// a global entrypoint (Next.js layout/_app) instead of inlining here.
await import('@zoom/videosdk-ui-toolkit/dist/videosdk-zoom-ui-toolkit.css');
if (!isMounted || !containerRef.current) return;
const config: any = {
videoSDKJWT: jwt,
sessionName: sessionName,
userName: userName,
sessionPasscode: '',
features: ['video', 'audio', 'share', 'chat', 'users', 'settings'],
};
uitoolkit.joinSession(containerRef.current, config);
uitoolkit.onSessionJoined(() => console.log('Joined'));
uitoolkit.onSessionClosed(() => console.log('Closed'));
};
init();
return () => {
isMounted = false;
if (uitoolkitRef.current && containerRef.current) {
try {
uitoolkitRef.current.closeSession(containerRef.current);
} catch (e) {}
}
};
}, [jwt, sessionName, userName]);
return <div ref={containerRef} style={{ width: '100%', height: '100vh' }} />;
}
| Feature | Description |
|---------|-------------|
| video | Enable video layout and send/receive video |
| audio | Show audio button, send/receive audio |
| share | Screen sharing |
| chat | In-session messaging |
| users | Participant list |
| settings | Device selection, virtual background |
| preview | Pre-join camera/mic preview |
| recording | Cloud recording (paid plan) |
| leave | Leave/end session button |
Required: Generate JWT tokens on your server, never expose SDK secret client-side.
import { NextRequest, NextResponse } from 'next/server';
import { KJUR } from 'jsrsasign';
const ZOOM_VIDEO_SDK_KEY = process.env.ZOOM_VIDEO_SDK_KEY;
const ZOOM_VIDEO_SDK_SECRET = process.env.ZOOM_VIDEO_SDK_SECRET;
export async function POST(request: NextRequest) {
const { sessionName, role, userName } = await request.json();
if (!sessionName || role === undefined) {
return NextResponse.json({ error: 'Missing params' }, { status: 400 });
}
const iat = Math.floor(Date.now() / 1000);
const exp = iat + 60 * 60 * 2; // 2 hours
const oHeader = { alg: 'HS256', typ: 'JWT' };
const oPayload = {
app_key: ZOOM_VIDEO_SDK_KEY,
role_type: role, // 0 = participant, 1 = host
tpc: sessionName,
version: 1,
iat,
exp,
user_identity: userName || 'User',
};
const signature = KJUR.jws.JWS.sign(
'HS256',
JSON.stringify(oHeader),
JSON.stringify(oPayload),
ZOOM_VIDEO_SDK_SECRET
);
return NextResponse.json({ signature });
}
| Field | Required | Description |
|-------|----------|-------------|
| app_key | Yes | Your Video SDK Key |
| role_type | Yes | 0 = participant, 1 = host |
| tpc | Yes | Session/topic name |
| version | Yes | Always 1 |
| iat | Yes | Issued at (Unix timestamp) |
| exp | Yes | Expiration (Unix timestamp) |
| user_identity | No | User identifier |
uitoolkit.joinSession(container, config);
uitoolkit.closeSession(container);
uitoolkit.onSessionJoined(callback);
uitoolkit.onSessionClosed(callback);
uitoolkit.offSessionJoined(callback);
uitoolkit.offSessionClosed(callback);
uitoolkit.showChatComponent(container);
uitoolkit.hideChatComponent(container);
uitoolkit.showUsersComponent(container);
uitoolkit.hideUsersComponent(container);
uitoolkit.showControlsComponent(container);
uitoolkit.hideControlsComponent(container);
uitoolkit.showSettingsComponent(container);
uitoolkit.hideSettingsComponent(container);
uitoolkit.hideAllComponents();
<link rel="stylesheet" href="https://source.zoom.us/uitoolkit/2.3.5-1/videosdk-zoom-ui-toolkit.css" />
<script src="https://source.zoom.us/uitoolkit/2.3.5-1/videosdk-zoom-ui-toolkit.min.umd.js"></script>
<div id="sessionContainer"></div>
<script>
const uitoolkit = window.UIToolkit;
uitoolkit.joinSession(document.getElementById('sessionContainer'), {
videoSDKJWT: 'your_jwt',
sessionName: 'my-session',
userName: 'User',
features: ['video', 'audio', 'chat']
});
</script>
When deploying Next.js under a subpath:
// next.config.ts
const nextConfig = {
basePath: "/your-app-path",
assetPrefix: "/your-app-path",
};
Fetch API routes with full path:
fetch('/your-app-path/api/token', { ... })
| Browser | Version | |---------|---------| | Chrome | 78+ | | Firefox | 76+ | | Safari | 14.1+ | | Edge | 79+ |
| Issue | Solution |
|-------|----------|
| peer react@"^18.0.0" error | Use the React version required by the installed UI Toolkit package (check peer deps; React 18 is common) |
| CSS import TypeScript error | Configure TS/CSS handling (prefer a global *.css module declaration); avoid @ts-ignore except in throwaway demos |
| Config type error | Type config as any |
| API returns HTML not JSON | Check basePath in fetch URL |
This section was migrated from SKILL.md.
Complete navigation for all UI Toolkit documentation.
New to the UI Toolkit? Follow this learning path:
Understanding how UI Toolkit works:
Complete API documentation:
Core Methods (see skill.md)
joinSession() - Start a video sessioncloseSession() - End session and remove UIdestroy() - Clean up UI Toolkit instanceleaveSession() - Leave without destroying UIComponent Methods (see skill.md)
showControlsComponent() - Display control barshowChatComponent() - Display chat panelshowUsersComponent() - Display participants listshowSettingsComponent() - Display settings panelhideAllComponents() - Hide all componentsEvent Listeners (see skill.md)
onSessionJoined() - Session joined successfullyonSessionClosed() - Session endedonSessionDestroyed() - UI Toolkit destroyedonViewTypeChange() - View mode changedon() - Subscribe to Video SDK eventsoff() - Unsubscribe from eventsInformation Methods (see skill.md)
getSessionInfo() - Get session detailsgetCurrentUserInfo() - Get current usergetAllUser() - Get all participantsgetClient() - Get underlying Video SDK clientversion() - Get version infoControl Methods (see skill.md)
changeViewType() - Switch view modemirrorVideo() - Mirror self videoisSupportCustomLayout() - Check device supportStatistics Methods (see skill.md)
subscribeAudioStatisticData() - Audio quality statssubscribeVideoStatisticData() - Video quality statssubscribeShareStatisticData() - Share quality statsFeature Configuration (see skill.md)
featuresOptions structureSession Configuration (see skill.md)
videoSDKJWT, sessionName, userNamesessionPasscode, sessionIdleTimeoutMinsSee: troubleshooting/common-issues.md
Official Repositories:
| Framework | Repository | Key Features | |-----------|------------|--------------| | React | videosdk-zoom-ui-toolkit-react-sample | Hooks, TypeScript | | Vue.js | videosdk-zoom-ui-toolkit-vuejs-sample | Composition API | | Angular | videosdk-zoom-ui-toolkit-angular-sample | Services, Guards | | JavaScript | videosdk-zoom-ui-toolkit-javascript-sample | Vanilla JS | | Auth Endpoint | videosdk-auth-endpoint-sample | Node.js JWT |
import uitoolkit from "@zoom/videosdk-zoom-ui-toolkit";
import "@zoom/videosdk-ui-toolkit/dist/videosdk-zoom-ui-toolkit.css";
const config = {
videoSDKJWT: "YOUR_JWT",
sessionName: "test-session",
userName: "User",
featuresOptions: {
video: { enable: true },
audio: { enable: true }
}
};
uitoolkit.joinSession(document.getElementById("container"), config);
uitoolkit.onSessionJoined(() => console.log("Joined"));
uitoolkit.onSessionClosed(() => uitoolkit.destroy());
destroy() on cleanuponSessionClosed cleanupjoinSessionNavigation: ← Back to SKILL.md
.env keys and where to find each value.testing
Reads a forwarded customer email or ticket, pulls order/refund status from PayPal and account history from HubSpot, drafts a tone-matched reply in the owner's writing voice, and can issue a PayPal refund with explicit owner approval. Use when the user says "draft a response," "answer this customer," "where's my order," or "I want a refund."
development
Prepares tax-season materials for small business owners — framed as deliverables for their accountant, not tax advice. Two modes: (1) quarterly estimated tax calculation — pulls YTD net income from QuickBooks and calculates the federal income tax + self-employment tax liability and quarterly payment due; (2) year-end 1099 prep — scans QuickBooks, PayPal, and Stripe for contractors paid over $600, builds a 1099-NEC candidate list with missing W-9 flags, and produces a plain-English summary a CPA can work from directly. Trigger this skill whenever the user mentions: quarterly taxes, estimated tax payment, how much to set aside for taxes, 1099s, 1099-NEC, year-end tax prep, contractor payments, W-9s, or any phrase suggesting they are preparing for a tax deadline or handing materials to an accountant. Also trigger proactively when a user asks about net profit or YTD income in a context that suggests they are worried about their tax bill.
tools
Prepares tax-season materials — quarterly estimated tax calculation or year-end 1099 prep — and produces an accountant handoff packet. Accepts optional mode and year arguments.
tools
The front door to the Small Business plugin. Listens to what the owner needs right now — vague or specific — and routes them to the best skill or slash command for the moment. Also serves as a guide: explains what's available, suggests what to try next, and adapts recommendations based on stored business context. Trigger whenever the owner asks "what can you do," "help me with my business," "what should I focus on," "I don't know where to start," or any open-ended business request that doesn't clearly match a single skill.