Subchapter 114.28
use-cases/customer-support-cobrowsing.mdMarkdown13 KBView on GitHub
Enable real-time collaborative browsing between support agents and customers for efficient issue resolution and form completion assistance.
References
App TypesProblem: Customers struggle to describe issues or complete complex forms, leading to long support calls and high frustration.
Solution: Implement Zoom Cobrowse SDK to allow support agents to view and assist customers’ browsers in real-time, with privacy controls for sensitive data.
Related Skills:
┌──────────────────────┐ ┌──────────────────────┐
│ Customer Browser │ │ Support Agent │
│ • View form/page │◄───────►│ • View customer │
│ • Share PIN │ Sync │ • Provide guidance │
│ • Get assistance │ │ • Draw annotations │
└──────────────────────┘ └──────────────────────┘
│ │
└────────────┬───────────────────┘
▼
┌──────────────────────┐
│ Your Auth Server │
│ • Generate JWTs │
│ • Log sessions │
│ • Track agents │
└──────────────────────┘// server.js - JWT token generation
const express = require('express');
const { KJUR } = require('jsrsasign');
app.post('/cobrowse-token', (req, res) => {
const { role, userId, userName, caseId } = req.body;
const iat = Math.floor(Date.now() / 1000);
const exp = iat + 60 * 60 * 2; // 2 hours
const payload = {
app_key: process.env.ZOOM_SDK_KEY,
role_type: role, // 1 = customer, 2 = agent
user_id: userId,
user_name: userName,
iat,
exp
};
const token = KJUR.jws.JWS.sign('HS256',
JSON.stringify({ alg: 'HS256', typ: 'JWT' }),
JSON.stringify(payload),
process.env.ZOOM_SDK_SECRET
);
// Log session for tracking
logCobrowseSession(caseId, userId, role);
res.json({ token });
});<!-- support.html -->
<!DOCTYPE html>
<html>
<head>
<script type="module">
const ZOOM_SDK_KEY = 'YOUR_SDK_KEY';
// Load Cobrowse SDK
(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>
<div id="support-widget">
<button id="start-cobrowse">Get Support Help</button>
<div id="pin-display" style="display:none;">
<p>Share this PIN with your support agent:</p>
<div id="pin-code"></div>
</div>
</div>
<!-- Customer form with sensitive fields -->
<form id="customer-form">
<input name="name" placeholder="Full Name">
<input name="email" placeholder="Email">
<input name="ssn" class="pii-mask" placeholder="SSN">
<input name="account" class="pii-mask" placeholder="Account Number">
</form>
<script>
let sessionRef = null;
const settings = {
allowAgentAnnotation: true, // Agent can highlight fields
allowCustomerAnnotation: false, // Customer can't annotate
piiMask: {
maskType: "custom_input",
maskCssSelectors: ".pii-mask" // Hide sensitive fields from agent
}
};
ZoomCobrowseSDK.init(settings, function({ success, session, error }) {
if (success) {
sessionRef = session;
session.on("pincode_updated", (payload) => {
document.getElementById("pin-code").innerText = payload.pincode;
document.getElementById("pin-display").style.display = "block";
});
session.on("agent_joined", () => {
console.log("Support agent connected");
showNotification("Agent is now viewing your screen");
});
}
});
document.getElementById("start-cobrowse").addEventListener("click", async () => {
const caseId = getCurrentCaseId();
const response = await fetch("/cobrowse-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
role: 1,
userId: "customer_" + Date.now(),
userName: "Customer",
caseId: caseId
})
});
const { token } = await response.json();
sessionRef.start({ sdkToken: token });
});
</script>
</body>
</html><!-- agent-portal.html -->
<!DOCTYPE html>
<html>
<head>
<title>Support Agent - Co-Browse</title>
</head>
<body>
<div class="agent-dashboard">
<div class="case-info">
<h2>Case #<span id="case-id"></span></h2>
<p>Customer: <span id="customer-name"></span></p>
</div>
<iframe
id="cobrowse-frame"
width="1024"
height="768"
allow="autoplay *; camera *; microphone *; display-capture *; geolocation *;"
></iframe>
</div>
<script>
async function loadCobrowseSession(caseId) {
const response = await fetch("/cobrowse-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
role: 2,
userId: "agent_" + Date.now(),
userName: getAgentName(),
caseId: caseId
})
});
const { token } = await response.json();
const iframe = document.getElementById("cobrowse-frame");
iframe.src = `https://us01-zcb.zoom.us/sdkapi/zcb/frame-templates/desk?access_token=${token}`;
}
// Load cobrowse when case requires it
const caseId = getCurrentCaseId();
loadCobrowseSession(caseId);
</script>
</body>
</html>Automatically hide sensitive customer data:
const settings = {
piiMask: {
maskType: "custom_input",
maskCssSelectors: ".pii-mask, .sensitive, [data-private]",
maskHTMLAttributes: "data-private=true"
}
};What gets masked:
.pii-mask classAgents can guide customers visually:
Track and log all cobrowse sessions:
function logCobrowseSession(caseId, userId, role) {
const log = {
caseId,
userId,
role: role === 1 ? 'customer' : 'agent',
timestamp: new Date(),
sessionType: 'cobrowse'
};
database.sessions.insert(log);
}Context: Customer struggles with multi-step insurance application
Flow:
Outcome: Form completed in 5 minutes vs 20 minutes phone call
Context: Customer can’t find account settings
Flow:
Outcome: No screen sharing software needed, instant resolution
Context: First-time user needs guided tour
Flow:
Outcome: Interactive onboarding, higher completion rate
// GDPR/CCPA compliant data handling
const privacySettings = {
piiMask: {
maskType: "custom_input",
maskCssSelectors: ".pii-mask"
},
sessionRecording: false, // Don't record sessions
dataRetention: "24h" // Auto-delete session logs
};// Verify agent credentials before token generation
async function validateAgent(agentId) {
const agent = await database.agents.findOne({ id: agentId });
if (!agent || !agent.cobrowseEnabled) {
throw new Error("Agent not authorized for cobrowse");
}
return agent;
}Track cobrowse effectiveness:
// Track session metrics
const metrics = {
sessionDuration: calculateDuration(startTime, endTime),
issueResolved: true,
customerSatisfaction: 5,
formFieldsCompleted: 12,
annotationsUsed: 8
};
analytics.track('cobrowse_session_completed', metrics);Key Metrics:
// Log cobrowse session to Salesforce case
async function logToSalesforce(caseId, sessionData) {
await salesforce.cases.update(caseId, {
Cobrowse_Session_Date__c: new Date(),
Cobrowse_PIN__c: sessionData.pin,
Agent_Id__c: sessionData.agentId,
Session_Duration__c: sessionData.duration
});
}// Add cobrowse note to Zendesk ticket
await zendesk.tickets.addComment(ticketId, {
body: `Cobrowse session completed. PIN: ${pin}. Duration: ${duration}`,
public: false
});Clear Privacy Disclosure
Selective Masking
.pii-mask class liberallySession Logging
Agent Training
Customer Consent
Zoom SDK Pricing:
Estimated Costs:
Issue: Customer can’t see PIN
Solution: Check pincode_updated event handler is properly attached
Issue: Agent sees sensitive data
Solution: Verify .pii-mask class applied to sensitive fields
Issue: Session disconnects on page refresh
Solution: Implement auto-reconnection pattern (see Auto-Reconnection (opens in a new tab))