HEX
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/8.4.25
System: Windows NT DESKTOP-4TAV2RJ 10.0 build 19045 (Windows 10) AMD64
User: fred (0)
PHP: 8.4.25
Disabled: NONE
Upload Files
File: C:/Users/fred/.codex/.tmp/plugins/plugins/zoom/skills/general/use-cases/web-sdk-embedding.md
# Web SDK Embedding

Embed Zoom SDKs in iframes with proper cross-origin configuration.

## Overview

Configure your web application to properly embed Zoom Meeting SDK or Video SDK, including iframe setup, CORS headers, and cross-origin requirements.

## Skills Needed

- **zoom-meeting-sdk** (Web)
- **zoom-video-sdk** (Web)

## Embedding Options

| Option | Description |
|--------|-------------|
| Same-origin | SDK loaded in main page |
| iframe (same-origin) | SDK in iframe, same domain |
| iframe (cross-origin) | SDK in iframe, different domain |

## Required Headers

For cross-origin embedding with SharedArrayBuffer:

```
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```

## iframe Configuration

```html
<iframe
  src="https://your-zoom-app.com/meeting"
  allow="camera; microphone; display-capture"
  sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>
```

## Common Tasks

### Basic iframe Embedding

```html
<!-- Parent page -->
<iframe
  id="zoom-frame"
  src="https://your-app.com/meeting-page"
  allow="camera; microphone; display-capture; autoplay; clipboard-write"
  sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
  style="width: 100%; height: 600px; border: none;"
></iframe>
```

### Cross-Origin Setup with SharedArrayBuffer

SharedArrayBuffer is required for:
- 720p sending
- Virtual backgrounds
- Gallery view

**Server headers (Node.js/Express)**:
```javascript
app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
  next();
});
```

**Nginx config**:
```nginx
location / {
  add_header Cross-Origin-Opener-Policy same-origin;
  add_header Cross-Origin-Embedder-Policy require-corp;
}
```

**Cloudflare Workers**:
```javascript
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const response = await fetch(request);
  const newResponse = new Response(response.body, response);
  newResponse.headers.set('Cross-Origin-Opener-Policy', 'same-origin');
  newResponse.headers.set('Cross-Origin-Embedder-Policy', 'require-corp');
  return newResponse;
}
```

### Permission Handling

```javascript
// Request permissions before joining
async function requestMediaPermissions() {
  try {
    await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    });
    return true;
  } catch (err) {
    console.error('Permission denied:', err);
    return false;
  }
}

// Check permission state
async function checkPermissions() {
  const camera = await navigator.permissions.query({ name: 'camera' });
  const microphone = await navigator.permissions.query({ name: 'microphone' });

  return {
    camera: camera.state,      // 'granted', 'denied', 'prompt'
    microphone: microphone.state
  };
}
```

### Communication Between Parent and iframe

**From parent to iframe**:
```javascript
// Parent page
const iframe = document.getElementById('zoom-frame');
iframe.contentWindow.postMessage({
  type: 'JOIN_MEETING',
  meetingNumber: '123456789',
  password: 'pass'
}, 'https://your-app.com');
```

**From iframe to parent**:
```javascript
// Inside iframe (meeting page)
window.parent.postMessage({
  type: 'MEETING_STATUS',
  status: 'joined'
}, '*');
```

**Receive messages**:
```javascript
// In parent or iframe
window.addEventListener('message', (event) => {
  // Verify origin
  if (event.origin !== 'https://trusted-domain.com') return;

  const { type, ...data } = event.data;

  switch (type) {
    case 'MEETING_STATUS':
      handleMeetingStatus(data);
      break;
    case 'LEAVE_MEETING':
      handleLeaveMeeting();
      break;
  }
});
```

### Mobile Responsive Embedding

```html
<style>
  .zoom-container {
    position: relative;
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
  }

  .zoom-container iframe {
    width: 100%;
    height: 100vh;
    max-height: 720px;
    border: none;
  }

  @media (max-width: 768px) {
    .zoom-container iframe {
      height: calc(100vh - 60px); /* Account for mobile browser chrome */
    }
  }
</style>

<div class="zoom-container">
  <iframe src="..." allow="..."></iframe>
</div>
```

## Troubleshooting

| Issue | Solution |
|-------|----------|
| Camera/mic blocked | Check `allow` attribute |
| SharedArrayBuffer error | Add COOP/COEP headers |
| Cross-origin errors | Configure CORS properly |

## Resources

- **Meeting SDK Web**: https://developers.zoom.us/docs/meeting-sdk/web/
- **Video SDK Web**: https://developers.zoom.us/docs/video-sdk/web/