From zoom-skills
Integrates Zoom Cobrowse SDK into web apps for real-time collaborative browsing between agents and customers, with annotation tools, privacy masking, remote assist, and PIN sharing.
npx claudepluginhub zoom/skills --plugin zoom-skillsThis skill uses the workspace's default tool permissions.
Expert guidance for implementing collaborative browsing with the Zoom Cobrowse SDK. This SDK enables support agents to view and interact with a customer's browser session in real-time, with privacy controls and annotation tools.
RUNBOOK.mdconcepts/distribution-methods.mdconcepts/jwt-authentication.mdconcepts/session-lifecycle.mdconcepts/two-roles-pattern.mdexamples/agent-integration.mdexamples/annotations.mdexamples/auto-reconnection.mdexamples/byop-custom-pin.mdexamples/customer-integration.mdexamples/multi-tab-persistence.mdexamples/privacy-masking.mdexamples/remote-assist.mdexamples/session-events.mdget-started.mdreferences/api-official.mdreferences/api-reference.mdreferences/api.mdreferences/authorization-official.mdreferences/authorization.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Delivers PostgreSQL patterns for indexing, schema design, query optimization, Row Level Security, UPSERT, pagination, and anti-pattern detection. Includes SQL examples and cheat sheets.
Expert guidance for implementing collaborative browsing with the Zoom Cobrowse SDK. This SDK enables support agents to view and interact with a customer's browser session in real-time, with privacy controls and annotation tools.
Official Documentation: https://developers.zoom.us/docs/cobrowse-sdk/
API Reference: https://marketplacefront.zoom.us/sdk/cobrowse/
Quickstart Repository: https://github.com/zoom/CobrowseSDK-Quickstart
Auth Endpoint Sample: https://github.com/zoom/cobrowsesdk-auth-endpoint-sample
New to Cobrowse SDK? Follow this path:
Core Concepts:
Features:
Troubleshooting:
Reference:
The Zoom Cobrowse SDK is a JavaScript library that provides:
Cobrowse has two distinct roles, each with different integration patterns:
| Role | role_type | Integration | JWT Required | Purpose |
|---|---|---|---|---|
| Customer | 1 | Website integration (CDN or npm) | Yes | User who shares their browser session |
| Agent | 2 | Iframe (CDN) or npm (BYOP only) | Yes | Support staff who views/assists customer |
Key Insight: Customer and agent use different integration methods but the same JWT authentication pattern.
For customer/agent demos, treat the PIN from customer SDK event pincode_updated as the only user-facing PIN.
If these rules are ignored, agent desk often fails with Pincode is not found / code 30308.
This is the flow most teams implement first, and what users usually expect in demos:
role_type=1)
role_type=2)
If a demo only has one generic "session" user, it is incomplete for real cobrowse operations.
Supported Browsers:
Network Requirements:
*.zoom.usThird-Party Cookies:
Note: Cobrowse SDK is a feature of Video SDK (not a separate product).
You'll receive 4 credentials from Zoom Marketplace → Video SDK App → Cobrowse tab:
| Credential | Type | Used For | Exposure Safe? |
|---|---|---|---|
| SDK Key | Public | CDN URL, JWT app_key claim | ✓ Yes (client-side) |
| SDK Secret | Private | Sign JWTs | ✗ No (server-side only) |
| API Key | Private | REST API calls (optional) | ✗ No (server-side only) |
| API Secret | Private | REST API calls (optional) | ✗ No (server-side only) |
Critical: SDK Key is public (embedded in CDN URL), but SDK Secret must never be exposed client-side.
Deploy a server-side endpoint to generate JWTs. Use the official sample:
git clone https://github.com/zoom/cobrowsesdk-auth-endpoint-sample.git
cd cobrowsesdk-auth-endpoint-sample
npm install
# Create .env file
cat > .env << EOF
ZOOM_SDK_KEY=your_sdk_key_here
ZOOM_SDK_SECRET=your_sdk_secret_here
PORT=4000
EOF
npm start
Token endpoint:
// POST https://YOUR_TOKEN_SERVICE_BASE_URL
{
"role": 1, // 1 = customer, 2 = agent
"userId": "user123",
"userName": "John Doe"
}
// Response
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}
<!DOCTYPE html>
<html>
<head>
<title>Customer - Cobrowse Demo</title>
<script type="module">
const ZOOM_SDK_KEY = 'YOUR_SDK_KEY';
// Load SDK from CDN
(function(r, a, b, f, c, d) {
r[f] = r[f] || { init: function() { r.ZoomCobrowseSDKInitArgs = arguments }};
var fragment = a.createDocumentFragment();
function loadJs(url) {
c = a.createElement(b);
d = a.getElementsByTagName(b)[0];
c["async"] = false;
c.src = url;
fragment.appendChild(c);
}
loadJs(`https://us01-zcb.zoom.us/static/resource/sdk/${ZOOM_SDK_KEY}/js/2.13.2`);
d.parentNode.insertBefore(fragment, d);
})(window, document, "script", "ZoomCobrowseSDK");
</script>
</head>
<body>
<h1>Customer Support</h1>
<button id="cobrowse-btn" disabled>Loading...</button>
<!-- Sensitive fields - will be masked from agent -->
<label>SSN: <input type="text" class="pii-mask" placeholder="XXX-XX-XXXX"></label>
<label>Credit Card: <input type="text" class="pii-mask" placeholder="XXXX-XXXX-XXXX-XXXX"></label>
<script type="module">
let sessionRef = null;
const settings = {
allowAgentAnnotation: true,
allowCustomerAnnotation: true,
piiMask: {
maskCssSelectors: ".pii-mask",
maskType: "custom_input"
}
};
ZoomCobrowseSDK.init(settings, function({ success, session, error }) {
if (success) {
sessionRef = session;
// Listen for PIN code
session.on("pincode_updated", (payload) => {
console.log("PIN Code:", payload.pincode);
// IMPORTANT: this is the PIN agent should use
alert(`Share this PIN with agent: ${payload.pincode}`);
});
// Listen for session events
session.on("session_started", () => console.log("Session started"));
session.on("agent_joined", () => console.log("Agent joined"));
session.on("agent_left", () => console.log("Agent left"));
session.on("session_ended", () => console.log("Session ended"));
document.getElementById("cobrowse-btn").disabled = false;
document.getElementById("cobrowse-btn").innerText = "Start Cobrowse Session";
} else {
console.error("SDK init failed:", error);
}
});
document.getElementById("cobrowse-btn").addEventListener("click", async () => {
// Fetch JWT from your server
const response = await fetch("https://YOUR_TOKEN_SERVICE_BASE_URL", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
role: 1,
userId: "customer_" + Date.now(),
userName: "Customer"
})
});
const { token } = await response.json();
// Start cobrowse session
sessionRef.start({ sdkToken: token });
});
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Agent Portal</title>
</head>
<body>
<h1>Agent Portal</h1>
<iframe
id="agent-iframe"
width="1024"
height="768"
allow="autoplay *; camera *; microphone *; display-capture *; geolocation *;"
></iframe>
<script>
async function connectAgent() {
// Fetch JWT from your server
const response = await fetch("https://YOUR_TOKEN_SERVICE_BASE_URL", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
role: 2,
userId: "agent_" + Date.now(),
userName: "Support Agent"
})
});
const { token } = await response.json();
// Load Zoom agent portal
const iframe = document.getElementById("agent-iframe");
iframe.src = `https://us01-zcb.zoom.us/sdkapi/zcb/frame-templates/desk?access_token=${token}`;
}
connectAgent();
</script>
</body>
</html>
Both customer and agent can draw on the shared screen:
const settings = {
allowAgentAnnotation: true, // Agent can draw
allowCustomerAnnotation: true // Customer can draw
};
Available tools:
Hide sensitive fields from agents using CSS selectors:
const settings = {
piiMask: {
maskType: "custom_input", // Mask specific fields
maskCssSelectors: ".pii-mask, #ssn", // CSS selectors
maskHTMLAttributes: "data-sensitive=true" // HTML attributes
}
};
Supported masking:
Agent can scroll the customer's page:
const settings = {
remoteAssist: {
enable: true,
enableCustomerConsent: true, // Customer must approve
remoteAssistTypes: ['scroll_page'], // Only scroll supported
requireStopConfirmation: false // Confirmation when stopping
}
};
Session continues when customer opens new tabs:
const settings = {
multiTabSessionPersistence: {
enable: true,
stateCookieKey: '$$ZCB_SESSION$$' // Cookie key (base64 encoded)
}
};
ZoomCobrowseSDKZoomCobrowseSDK.init(settings, callback)session.start({ sdkToken })pincode_updated event firesagent_joined event firessession.end() or agent leavessession_joined event firesWhen customer refreshes the page:
ZoomCobrowseSDK.init(settings, function({ success, session, error }) {
if (success) {
const sessionInfo = session.getSessionInfo();
// Check if session is recoverable
if (sessionInfo.sessionStatus === 'session_recoverable') {
session.join(); // Auto-rejoin previous session
} else {
// Start new session
session.start({ sdkToken });
}
}
});
Recovery window: 2 minutes. After 2 minutes, session ends.
Problem: Developers often accidentally embed SDK Secret in frontend code.
Solution:
// ❌ WRONG - Secret exposed in frontend
const jwt = signJWT(payload, 'YOUR_SDK_SECRET'); // Security risk!
// ✅ CORRECT - Secret stays on server
const response = await fetch('/api/token', {
method: 'POST',
body: JSON.stringify({ role: 1, userId, userName })
});
const { token } = await response.json();
| Credential | Used For | JWT Claim |
|---|---|---|
| SDK Key | CDN URL, JWT app_key | app_key: "SDK_KEY" |
| API Key | REST API calls (optional) | Not used in JWT |
Common mistake: Using API Key instead of SDK Key in JWT app_key claim.
| Limit | Value | What Happens |
|---|---|---|
| Customers per session | 1 | Error 1012: SESSION_CUSTOMER_COUNT_LIMIT |
| Agents per session | 5 | Error 1013: SESSION_AGENT_COUNT_LIMIT |
| Active sessions per browser | 1 | Error 1004: SESSION_COUNT_LIMIT |
| PIN code length | 10 chars max | Error 1008: SESSION_PIN_INVALID_FORMAT |
| Event | Timeout | What Happens |
|---|---|---|
| Agent waiting for customer | 3 minutes | Session ends automatically |
| Page refresh reconnection | 2 minutes | Session ends if not reconnected |
| Reconnection attempts | 2 times max | Session ends after 2 failed attempts |
Problem: SDK doesn't load on HTTP sites.
Solution:
Problem: Refresh reconnection doesn't work.
Solution: Enable third-party cookies in browser settings.
Affected scenarios:
| Method | Use Case | Agent Integration | BYOP Required |
|---|---|---|---|
| CDN | Most use cases | Zoom-hosted iframe | No (auto PIN) |
| npm | Custom agent UI, full control | Custom npm integration | Yes (required) |
Key Insight: If you want npm integration, you must use BYOP (Bring Your Own PIN) mode.
Problem: Cobrowse doesn't work in cross-origin iframes.
Solution: Inject SDK snippet into cross-origin iframes:
<script>
const ZOOM_SDK_KEY = "YOUR_SDK_KEY_HERE";
(function(r,a,b,f,c,d){r[f]=r[f]||{init:function(){r.ZoomCobrowseSDKInitArgs=arguments}};
var fragment=a.createDocumentFragment();function loadJs(url) {c=a.createElement(b);d=a.getElementsByTagName(b)[0];c.async=false;c.src=url;fragment.appendChild(c);};
loadJs('https://us01-zcb.zoom.us/static/resource/sdk/${ZOOM_SDK_KEY}/js');d.parentNode.insertBefore(fragment,d);})(window,document,'script','ZoomCobrowseSDK');
</script>
Same-origin iframes: No extra setup needed.
Not synchronized:
Partially synchronized:
Supported:
Not supported:
<img> elements ✗This skill includes comprehensive guides organized by category:
Need help? Start with Integrated Index section below for complete navigation.
This section was migrated from SKILL.md.
Complete navigation guide for all Cobrowse SDK documentation.
If you're new to Zoom Cobrowse SDK, follow this learning path:
Foundational concepts you need to understand:
Complete working examples for common scenarios:
Complete API and configuration references:
API Reference - All SDK methods and interfaces
Settings Reference - All initialization settings
Session Events Reference - All event types
Quick diagnostics and common issue resolution:
Common Issues - Quick fixes for frequent problems
Error Codes - Error code lookup and solutions
CORS and CSP - Cross-origin and Content Security Policy setup
Browser Compatibility - Browser requirements and limitations
Find documentation by what you're trying to do:
Set up cobrowse for the first time:
Add annotation tools:
Hide sensitive data from agents:
Let agents control customer's page:
Use custom PIN codes:
Handle page refreshes:
Integrate with npm (not CDN):
Debug session connection issues:
Configure CORS and CSP headers:
Quick lookup for error code solutions:
External documentation and samples:
cobrowse-sdk/
├── SKILL.md # Main skill entry point
├── SKILL.md # This file - complete navigation
├── get-started.md # Step-by-step setup guide
│
├── concepts/ # Core concepts
│ ├── two-roles-pattern.md
│ ├── session-lifecycle.md
│ ├── jwt-authentication.md
│ └── distribution-methods.md
│
├── examples/ # Working examples
│ ├── customer-integration.md
│ ├── agent-integration.md
│ ├── annotations.md
│ ├── privacy-masking.md
│ ├── remote-assist.md
│ ├── multi-tab-persistence.md
│ ├── byop-custom-pin.md
│ ├── session-events.md
│ └── auto-reconnection.md
│
├── references/ # API and config references
│ ├── api-reference.md # SDK methods
│ ├── settings-reference.md # Init settings
│ ├── session-events.md # Event types
│ ├── error-codes.md # Error reference
│ ├── get-started.md # Official docs (crawled)
│ ├── features.md # Official docs (crawled)
│ ├── authorization.md # Official docs (crawled)
│ └── api.md # API docs (crawled)
│
└── troubleshooting/ # Problem resolution
├── common-issues.md
├── error-codes.md
├── cors-csp.md
└── browser-compatibility.md
Find by keyword:
Not finding what you need? Check the Official Documentation or ask on the Dev Forum.
.env keys and where to find each value.