I am currently developing an app for Zoom Phone. The app would basically get contextual information about a caller from a CRM system.
The phone SDK includes an event called ‘onPhoneContext’ which is meant to trigger every time the current phone status changes.
I am having these two issues with it:
- The event works fine when starting new calls and receiving calls, but when a call ends, the event does not trigger.
- When using the Workplace app with call control connected to a desk phone, the callId value is always empty, even though the callStatus updates
Does anyone know if there’s anything that can be done about this?
For context, this is my basic code for testing these features:
<?php
$nonce = base64_encode(random_bytes(16));
$clientId = 'CLIENT ID HERE';
$redirectUri = 'REDIRECT URL HERE';
// More standard headers for production
header("Strict-Transport-Security: max-age=31536000; includeSubDomains; preload");
header("X-Content-Type-Options: nosniff");
header("Content-Security-Policy: default-src 'self'; connect-src 'self' https://*.zoom.us; script-src 'self' https://*.zoom.us https://appssdk.zoom.us 'nonce-$nonce'; style-src 'self' 'unsafe-inline';");
header("Referrer-Policy: no-referrer");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zoom Phone Call Details</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
#call-details { margin-top: 20px; background: #f7f7f7; padding: 15px; border-radius: 5px; border: 1px solid #ccc; }
.log { margin: 10px 0; padding: 5px; background: #f0f0f0; font-family: monospace; font-size: 12px; }
.error { color: #d00; }
.success { color: #080; }
button { padding: 8px 16px; margin: 5px; }
</style>
<!-- Added external Zoom SDK script -->
<script src="https://appssdk.zoom.us/sdk.js" nonce="<?php echo $nonce; ?>"></script>
</head>
<body>
<div id="app">
<h1>Zoom Phone Call Details</h1>
<div id="status" class="log">Initializing app...</div>
<div id="call-details">Waiting for call data...</div>
<div id="actions" style="margin-top: 15px;">
<button id="btnCheck">Check Environment</button>
<button id="btnInit">Initialize SDK</button>
<button id="btnGet">Get Phone Data</button>
</div>
<div id="debug-info" class="log"></div>
</div>
<script nonce="<?php echo $nonce; ?>">
// Basic logging function
function log(message, type = 'info') {
const statusElement = document.getElementById('status');
const className = type === 'error' ? 'error' : type === 'success' ? 'success' : '';
statusElement.className = `log ${className}`;
statusElement.textContent = message;
console.log(`[${type.toUpperCase()}] ${message}`);
// Update debug info
const debugElement = document.getElementById('debug-info');
const now = new Date().toISOString();
debugElement.innerHTML += `<div>[${now}] ${message}</div>`;
}
// Display call details
function displayCallDetails(details) {
const detailsElement = document.getElementById('call-details');
if (details && Object.keys(details).length > 0) {
detailsElement.innerHTML = `<pre>${JSON.stringify(details, null, 2)}</pre>`;
} else {
detailsElement.textContent = "No active call detected or empty response received.";
}
}
// Check for Zoom environment
function checkEnvironment() {
log("Checking environment...");
// Get environment details
const userAgent = navigator.userAgent;
const inIframe = window !== window.top;
const sdkDefined = typeof zoomSdk !== 'undefined';
log(`Environment check:
- User Agent: ${userAgent}
- In iframe: ${inIframe}
- SDK defined: ${sdkDefined}`, 'info');
// Show window properties for debugging
log("Window properties:");
// Find Zoom-related properties
const zoomProps = Object.getOwnPropertyNames(window).filter(prop =>
prop.toLowerCase().includes('zoom')
);
if (zoomProps.length > 0) {
log(`Found Zoom properties: ${zoomProps.join(', ')}`, 'success');
} else {
log("No Zoom-related properties found on window object", 'error');
}
return {
isZoomEnvironment: userAgent.includes('Zoom') || inIframe,
sdkDefined: sdkDefined
};
}
// Initialize the SDK
function initializeSDK() {
log("Manual SDK initialization requested");
const env = checkEnvironment();
if (!env.isZoomEnvironment || !env.sdkDefined) {
log("Cannot initialize SDK. Either not in Zoom environment or zoomSdk not defined.", 'error');
return;
}
configureSDK();
}
// Add a global flag for SDK configuration
var sdkConfigured = false;
var sdkEventListenerAdded = false;
// Configure the SDK only (without event listeners)
function configureSDK() {
try {
if (!sdkConfigured) {
log("Configuring SDK", 'info');
// Configure with specific phone and context capabilities
zoomSdk.config({
version: '0.16.24',
capabilities: ['phone', 'onPhoneContext'],
clientId: '<?php echo $clientId; ?>',
redirectUri: '<?php echo $redirectUri; ?>'
});
log("SDK configuration complete - waiting for SDK to be ready", 'info');
sdkConfigured = true;
// Use longer delay to ensure SDK is fully initialized before registering event
setTimeout(registerPhoneEventListener, 2000);
} else {
log("SDK already configured", 'info');
if (!sdkEventListenerAdded) {
registerPhoneEventListener();
}
}
} catch (error) {
log(`Error configuring SDK: ${error.message}`, 'error');
}
}
// Register the onPhoneContext event listener separately
function registerPhoneEventListener() {
if (sdkEventListenerAdded) {
log("Event listener already registered", 'info');
return;
}
try {
log("About to register phone context event handler", 'info');
log("Available SDK methods: " + Object.keys(zoomSdk).filter(key => typeof zoomSdk[key] === 'function').join(", "), 'info');
if (typeof zoomSdk.onPhoneContext === 'function') {
log("Found onPhoneContext method in SDK", 'success');
zoomSdk.onPhoneContext((context) => {
log("Received phone context data via event!", 'success');
log("Event data: " + JSON.stringify(context), 'info');
displayCallDetails(context);
});
sdkEventListenerAdded = true;
log("Event handler successfully registered", 'success');
// Immediately try to get current phone context
getPhoneData();
} else {
log("onPhoneContext API not found in SDK", 'error');
}
} catch (error) {
log(`Error registering event listener: ${error.message}`, 'error');
}
}
// Get phone data
function getPhoneData() {
log("Requesting phone context data");
if (typeof zoomSdk.getPhoneContext !== 'function') {
log("getPhoneContext method not available", 'error');
return;
}
try {
zoomSdk.getPhoneContext()
.then(context => {
log("Got phone context successfully", 'success');
displayCallDetails(context);
})
.catch(error => {
log(`Error getting phone context: ${error.message}`, 'error');
// If it's an auth error, try to authorize
if (error.message && error.message.toLowerCase().includes('auth')) {
log("Needs authorization, attempting to authorize");
zoomSdk.authorize()
.catch(authError => {
log(`Authorization failed: ${authError.message}`, 'error');
});
}
});
} catch (error) {
log(`Exception calling getPhoneContext: ${error.message}`, 'error');
}
}
// Start the application and attach button listeners
function startApp() {
log("Application starting", 'info');
// Attach event listeners to buttons
document.getElementById("btnCheck").addEventListener("click", checkEnvironment);
document.getElementById("btnInit").addEventListener("click", initializeSDK);
document.getElementById("btnGet").addEventListener("click", getPhoneData);
const env = checkEnvironment();
if (env.isZoomEnvironment && env.sdkDefined) {
log("Detected Zoom environment. Configuring SDK now.", 'info');
// Directly configure SDK so that config is called before adding event listeners.
configureSDK();
} else {
log("Not running in Zoom environment or SDK not defined. Use the buttons to test functionality.", 'info');
}
}
// Start the app when document is fully loaded
document.addEventListener('DOMContentLoaded', startApp);
</script>
</body>
</html>