I ended up finally getting it to work like this.
// This is the final, validated, and self-contained solution.
(async () => {
const button = document.getElementById('talk-to-hubert-btn');
button.disabled = true;
button.textContent = 'Loading SDK...';
function loadScript(url) {
return new Promise((resolve, reject) => {
if (document.querySelector(\`script\[src="${url}"\]\`)) return resolve();
const script = document.createElement('script');
script.src = url;
script.onload = resolve;
script.onerror = () => reject(new Error(\`Failed to load script: ${url}\`));
document.body.appendChild(script);
});
}
try {
// Step 1: Load all dependencies
await loadScript('https://unpkg.com/eventemitter3/dist/eventemitter3.umd.min.js');
await loadScript('https://unpkg.com/livekit-client/dist/livekit-client.umd.js');
// Step 2: The critical fix for the naming mismatch
window.eventemitter3 = window.EventEmitter3;
window.livekitClient = window.LivekitClient;
// Step 3: Load the main Retell SDK
await loadScript('https://unpkg.com/retell-client-js-sdk/dist/index.umd.js');
// Step 4: Verify the SDK object has initialized
if (!window.retellClientJsSdk || !window.retellClientJsSdk.RetellWebClient) {
throw new Error('Retell SDK failed to initialize.');
}
button.textContent = 'Connecting...';
// Step 5: Get the session from our backend
} const response = await fetch(‘[INSERT API URL]’, { method: ‘POST’ });
if (!response.ok) {
throw new Error(\`Failed to create session: ${response.statusText}\`);
}
const sessionData = await response.json();
// Step 6: Initialize and start the call
const sdk = new window.retellClientJsSdk.RetellWebClient();
sdk.on('error', (error) => {
console.error('Retell SDK error:', error);
button.textContent = 'Talk to your AI Agent';
button.disabled = false;
});
sdk.on('conversationStarted', () => button.textContent = 'Call in Progress...');
sdk.on('conversationEnded', () => {
button.textContent = 'Talk to your AI Agent';
button.disabled = false;
});
// THE FINAL FIX: Create a new object with the correct camelCase property names.
const startCallData = {
callId: sessionData.call_id,
accessToken: sessionData.access_token,
sampleRate: sessionData.sample_rate
};
// Pass the correctly formatted object to the SDK.
await sdk.startCall(startCallData);
} catch (error) {
console.error("A fatal error occurred:", error);
button.textContent = 'Error: Setup Failed';
}
})();