Blocked: Integrating External JS SDK (Retell AI) due to Content Security Policy (CSP) Blocking the NPM Plugin

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';

}

})();

1 Like