Generated banner for Zoom Apps SDK
Generated logo for Zoom Apps SDK

Zoom Apps SDK

OpenAIOfficialCreated by ZoomDistributed by OpenAI

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Medium risk

From the author

Use when using Apps SDK.
— the description by Zoom

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The Zoom Apps SDK skill provides a structured approach for developers building applications that run directly inside the Zoom client. It covers the lifecycle of a Zoom App, from initial configuration and context verification to implementing advanced features like the Layers API, in-client OAuth, and inter-instance communication. The skill emphasizes the importance of identifying the correct running context—such as meetings, webinars, or the main client—to ensure features are gated appropriately and the user experience remains consistent across different Zoom environments.

What it does

  • Initializes the Zoom Apps SDK with required capabilities.
  • Identifies the current running context, such as meeting or main client.
  • Facilitates in-client OAuth flows for secure user authentication.
  • Enables communication between different app instances.
  • Provides access to meeting-specific data and participant information.
  • Supports advanced UI and media features like virtual backgrounds and notification management.

When to use it

  • When building an application intended to run inside the Zoom client interface.
  • When you need to access meeting context, participant lists, or recording status.
  • When implementing custom UI overlays or media controls within a Zoom meeting.
  • When you need to authenticate users without redirecting them to an external browser.

Advantages

  • Provides a unified API for interacting with various Zoom client contexts.
  • Supports secure, in-client authentication workflows.
  • Enables deep integration with Zoom meeting features and participant data.
  • Offers clear patterns for handling cross-instance communication.

Usage examples

“How do I initialize the Zoom Apps SDK?”
You must call zoomSdk.config() first, passing in the required capabilities and version to initialize the SDK and declare the features your app intends to use.
“How can I get the current meeting ID?”
After initializing the SDK, you can call zoomSdk.getMeetingContext() to retrieve the meetingID, meetingTopic, and meetingStatus.
“How do I trigger authentication within the Zoom client?”
Use the zoomSdk.authorize() method to trigger the in-client OAuth flow, which avoids external browser redirects and fires an onAuthorized event upon completion.
“How do I send a message to another instance of my app?”
First call zoomSdk.connect() to establish the connection, then use zoomSdk.postMessage() to send a payload to other app instances.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/openai/zoom-apps-sdk/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip zoom-apps-sdk.zip -d .agents/skills

Documentation by Zoom

Zoom Apps SDK

Use this skill when the app runs inside the Zoom client. If the user only needs to embed a meeting in an external app, route to Meeting SDK instead.

Workflow

  1. Confirm the running context: meeting, webinar, main client, phone, collaborate mode, immersive mode, camera mode, or Layers API.

  2. Configure Marketplace app settings, allowed domains, redirect URIs, and in-client OAuth before implementing SDK calls.

  3. Initialize zoomSdk and gate features by capability and running context.

  4. Design client communication and data flow: frontend SDK calls, backend REST calls, in-client OAuth tokens, and webhook handoff.

  5. Implement advanced client features only after the base app loads reliably: Layers API, breakout rooms, guest mode, collaborate mode, or ZMail.

  6. Debug blank panels, domain allowlist issues, CSP, missing capabilities, running-context mismatch, and OAuth redirect problems independently.

References

Files

examples/layers-immersive.md

Layers API - Immersive Mode

Custom video layouts that replace the standard gallery view. Position participant video feeds, backgrounds, and web content anywhere on screen.

Overview

Immersive mode takes over the entire meeting video area. You control where each participant's video appears, add background images, and overlay web content.

Use cases: Podcast layout, talk show, classroom, game show, branded meetings.

Quick Start

import zoomSdk from '@zoom/appssdk';

// 1. Config with Layers capabilities
await zoomSdk.config({
  capabilities: [
    'getRunningContext',
    'runRenderingContext', 'closeRenderingContext',
    'drawParticipant', 'clearParticipant',
    'drawImage', 'clearImage',
    'drawWebView', 'clearWebView',
    'getMeetingParticipants', 'onParticipantChange',
    'postMessage', 'onMessage',
    'sendAppInvitationToAllParticipants',
    'onRenderedAppOpened'
  ],
  version: '0.16'
});

// 2. Start immersive mode (Team = person cutout, Presentation = rectangle)
await zoomSdk.runRenderingContext({
  view: 'immersive',
  defaultCutout: 'person'  // Removes backgrounds via AI segmentation
});

// 3. Draw a background (imageData = JS ImageData object, NOT base64)
const canvas = document.createElement('canvas');
canvas.width = 1280;
canvas.height = 720;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, 1280, 720);
const imageData = ctx.getImageData(0, 0, 1280, 720);

await zoomSdk.drawImage({
  imageData,
  x: 0, y: 0,
  zIndex: 0
});

// 4. Position participants
const { participants } = await zoomSdk.getMeetingParticipants();

await zoomSdk.drawParticipant({
  participantUUID: participants[0].participantUUID,
  x: 50, y: 100,
  width: 500, height: 400,
  zIndex: 1,
  cutout: 'person'  // Override default if needed
});

await zoomSdk.drawParticipant({
  participantUUID: participants[1].participantUUID,
  x: 730, y: 100,
  width: 500, height: 400,
  zIndex: 1,
  cutout: 'person'
});

Drawing Methods

drawParticipant

Position a participant's video feed. In immersive mode, you can draw any participant.

await zoomSdk.drawParticipant({
  participantUUID: 'uuid-string',  // From getMeetingParticipants()
  x: 0,          // PixelValue: "Npx", "N%", or number
  y: 0,          // PixelValue
  width: 640,    // PixelValue (aspect ratio maintained)
  height: 480,   // PixelValue (aspect ratio maintained)
  zIndex: 1,     // Stacking order (higher = on top)
  cutout: 'person'  // Optional: "person"|"standard"|"rectangle"|"circle"|"square"|"verticalRectangle"
});

Cutout shapes (all have 30px rounded corners except "standard"):

  • "person" — AI background removal (v5.9.3+)

  • "standard" — Full uncropped video, squared corners (v5.11.3+)

  • "rectangle" — Rounded rectangle (v5.11.0+)

  • "circle" — Circle (v5.11.3+)

  • "square" — Square with rounded corners (v5.11.3+)

  • "verticalRectangle" — Vertical rectangle with rounded corners (v5.11.3+)

Deprecated: participantId — use participantUUID instead.

drawImage

Add images (backgrounds, overlays, borders). Uses standard JavaScript ImageData (NOT base64):

const canvas = document.createElement('canvas');
canvas.width = 1280;
canvas.height = 720;
const ctx = canvas.getContext('2d');
// ... draw on canvas ...
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

const { imageId } = await zoomSdk.drawImage({
  imageData,     // ImageData object from canvas.getImageData()
  x: 0, y: 0,
  zIndex: 0      // Behind participants
});
// Save imageId for clearImage() later
drawWebView

Embed your app's webview as an interactive overlay. Only one webview per rendering context.

await zoomSdk.drawWebView({
  x: 400, y: 600,
  width: 480, height: 100,
  zIndex: 2  // On top of everything
});

See ../references/layers-api.md for full drawWebView details, webview communication, and the webviewId documentation inconsistency.

Clearing
await zoomSdk.clearParticipant({ participantUUID: 'uuid' });
await zoomSdk.clearImage({ imageId: 'id-from-drawImage-response' });
await zoomSdk.clearWebView();  // No params per TypeDoc v0.16.36
Exit Immersive Mode
await zoomSdk.closeRenderingContext();

Complete Example: Podcast Layout

Two hosts side-by-side with custom background:

import zoomSdk from '@zoom/appssdk';

class PodcastLayout {
  constructor() {
    this.active = false;
  }

  async start() {
    await zoomSdk.runRenderingContext({ view: 'immersive', defaultCutout: 'person' });
    this.active = true;

    // Draw background
    await this.drawBackground();

    // Position hosts
    const { participants } = await zoomSdk.getMeetingParticipants();
    await this.layoutParticipants(participants);

    // React to participant changes
    zoomSdk.addEventListener('onParticipantChange', async () => {
      const { participants } = await zoomSdk.getMeetingParticipants();
      await this.layoutParticipants(participants);
    });
  }

  async drawBackground() {
    const canvas = document.createElement('canvas');
    canvas.width = 1280;
    canvas.height = 720;
    const ctx = canvas.getContext('2d');

    // Gradient background
    const gradient = ctx.createLinearGradient(0, 0, 1280, 720);
    gradient.addColorStop(0, '#1a1a2e');
    gradient.addColorStop(1, '#16213e');
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, 1280, 720);

    // Title
    ctx.fillStyle = 'white';
    ctx.font = 'bold 32px sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText('The Zoom Podcast', 640, 60);

    const imageData = ctx.getImageData(0, 0, 1280, 720);
    await zoomSdk.drawImage({
      imageData,
      x: 0, y: 0, zIndex: 0
    });
  }

  async layoutParticipants(participants) {
    if (participants.length === 1) {
      // Single host - centered
      await zoomSdk.drawParticipant({
        participantUUID: participants[0].participantUUID,
        x: 340, y: 100, width: 600, height: 500, zIndex: 1
      });
    } else if (participants.length >= 2) {
      // Two hosts - side by side
      await zoomSdk.drawParticipant({
        participantUUID: participants[0].participantUUID,
        x: 40, y: 100, width: 580, height: 500, zIndex: 1
      });
      await zoomSdk.drawParticipant({
        participantUUID: participants[1].participantUUID,
        x: 660, y: 100, width: 580, height: 500, zIndex: 1
      });
    }
  }

  async stop() {
    await zoomSdk.closeRenderingContext();
    this.active = false;
  }
}

HiDPI Support

For Retina/HiDPI displays, multiply coordinates by window.devicePixelRatio:

const dpr = window.devicePixelRatio || 1;

await zoomSdk.drawParticipant({
  participantUUID: uuid,
  x: 100 * dpr,
  y: 100 * dpr,
  width: 640 * dpr,
  height: 480 * dpr,
  zIndex: 1
});

Multi-Participant Sync

The host controls the layout. Use Socket.io to broadcast layout changes:

// Host sends layout to all participants via your backend
socket.emit('layout-change', {
  participants: [
    { uuid: 'a', x: 40, y: 100, w: 580, h: 500 },
    { uuid: 'b', x: 660, y: 100, w: 580, h: 500 }
  ]
});

// All participants apply the layout
socket.on('layout-change', async (layout) => {
  for (const p of layout.participants) {
    await zoomSdk.drawParticipant({
      participantUUID: p.uuid,
      x: p.x, y: p.y, width: p.w, height: p.h, zIndex: 1
    });
  }
});

Performance Tips

  • Use requestAnimationFrame for animations

  • Minimize drawImage calls (batch updates)

  • Pre-render complex backgrounds to canvas

  • Keep zIndex values low (0-10 range)

  • Clear unused elements to free resources

Resources

Requirements and compatibility

Written for: OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

What our scanner noticed· Medium risk

  • Possible data-exfiltration endpoints

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Zoom
Publisher
OpenAI (Official)
Distributed by
OpenAI
Source
openai/plugins · plugins/zoom/skills/zoom-apps-sdk · commit d420d13
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from plugins/zoom/LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Zoom or OpenAI.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download zoom-apps-sdk.zip