Skip to content
Skip to main content
An old brass telephone switchboard with unplugged patch cords next to a modern white network patch panel with one new orange cable, a metaphor for moving Retell web calls from the LiveKit transport to the v3 gateway
9 min readBy Carlos Aragon

Retell Web SDK 3.0: Migrate RetellWebClient Before Oct 18

Retell's browser SDK 2.x and /v2/create-web-call are deprecated on October 18, 2026. Upgrade retell-client-js-sdk to 3.x in the browser first, then move your server to /v3/create-web-call, then rewrite RetellWebClient to RetellClient.createWebCall(). Do it in the other order and your web calls stop connecting. I hit both endpoints this morning with the same agent and read through the 2.0.8 and 3.0.2 packages to see what actually changed. The short version: the transport changed, and four events went away.

What is Retell deprecating, and when?

Two things that only make sense together:

  • Version 2.x of retell-client-js-sdk, the browser package with RetellWebClient.
  • POST /v2/create-web-call, the server call that hands the browser an access token.

The Retell deprecation page now says October 18, 2026. Earlier copies said September 30, which is why you'll see that date quoted in community threads and in a few roundups. SDK 3.0.0 landed on npm on September 8, and 3.0.2 on September 30.

Nothing is broken yet. At 9:08 CT today, /v2/create-web-callstill returned a 201 with a working token. You have about two weeks, which is enough if you don't spend the first one finding out the order matters.

What changes between v2 and v3 create-web-call?

I called both versions with the same agent and the same metadata. Both returned 201 in under 200 ms. The bodies are very different:

  • v2 (12 fields): call_id, call_type, agent_id, agent_version, agent_name, call_status: "registered", latency, metadata, call_cost, data_storage_setting, opt_in_signed_url, and a 262-character access_token that decodes to a LiveKit room grant.
  • v3 (5 fields): call_id, a 383-character access_token, transport: "gateway", ice_servers (TURN on turn.retellai.com:3478) and expires_at, which was about two hours out.

v3 isn't a call object anymore. It's connection details for a different transport. If your backend saved agent_name or call_status straight from the create response, say to log the call in a CRM row, that code gets undefined after the switch. Read those from get-call or from the call webhooks instead.

Why does the order of the migration matter?

Because retell-client-js-sdk@2.0.8 only knows one way to connect. Its type definitions have startCall({ accessToken, sampleRate, captureDeviceId, playbackDeviceId, emitRawAudioSamples }) and nothing else; the bundle contains a LiveKit room and no gateway code path. Hand it a v3 gateway token and it has nowhere to send it.

The 3.x package, on the other hand, still ships RetellWebClient (deprecated, slated for removal in 4.0) and its startCall now accepts transport, url and iceServers. So 3.x can talk to both v2 and v3 tokens. That gives you a migration with no flag day:

  1. Ship the browser upgrade alone. npm install retell-client-js-sdk@3, keep RetellWebClient, keep your v2 server. Calls should behave exactly as before.
  2. Forward the new fields. Have the page pass whatever the server returns into startCall, so it works with either response shape.
  3. Switch the server to /v3/create-web-call. Now the same client code connects over the gateway.
  4. Rewrite to RetellClient when you have a quiet afternoon, before 4.0.

Step 2 is a few lines:

// server returns the v3 body as-is
const res = await fetch("/api/retell/web-call", { method: "POST" });
const { access_token, transport, url, ice_servers } = await res.json();

await retellWebClient.startCall({
  accessToken: access_token,
  transport,               // "gateway" on v3, undefined on v2
  url,
  iceServers: ice_servers,
});

This is the same pattern as last week's SIP endpoint retirement: Retell is moving traffic off livekit.cloud onto its own infrastructure, one surface at a time. If you run both phone and web agents, check both.

What does the new RetellClient code look like?

The big change is that the browser can create the call itself. You make a public keyin Retell's account settings, restrict it to your domains (localhost for dev), and the SDK calls /v3/create-web-callfor you. Your real API key stays on the server and you can delete the little "create web call" route.

import { RetellClient } from "retell-client-js-sdk";

const client = new RetellClient({ key: "public_key_..." });

// call this from a click: the mic prompt happens here
const call = client.createWebCall({
  agent_id: "agent_...",
  retell_llm_dynamic_variables: { first_name: "Dana" },
  hooks: {
    onStatus: (s) => setStatus(s),          // connecting -> live -> ended
    onEnd: ({ disconnection_reason }) => log(disconnection_reason),
    onError: (err) => showError(err),        // mic denied, key rejected, dropped
  },
});

await call.ready;   // optional; resolves when live
// call.mute(); call.unmute();
await call.end();   // leaving is what ends a web call

Three things that tripped me up reading it:

  • createWebCall() returns before it connects. The session is in connectingimmediately. Don't wait on it to render your "calling..." state.
  • Mic denied, key rejected and dropped connections all arrive on onError, and call.readyrejects with the same error. Handle one, not both, or you'll show two toasts.
  • The SDK reports its own version to Retell. Behind the recommended version you get a console.error; below the minimum you get an errorevent. Pin a version, but don't forget it for a year.

If reCAPTCHA is on for the public key, pass recaptchaToken(a fresh v3 token per request) in the same options object. The SDK won't load Google's script for you. The Retell web call guide covers the key setup screens.

Which events stop firing after the migration?

This is the part that will actually cost you time. Calls created by createWebCall() (or by v3 tokens in general) don't emit:

  • agent_start_talking / agent_stop_talking: what most demos use to animate the orb or waveform.
  • update: the live transcript plus turntaking.
  • metadata: whatever your LLM websocket pushed to the browser mid-call.

A developer reported this on Retell's community forum on September 16 and pushed again on the 22nd. Support's answer: the gateway "doesn't relay those events to the browser", it would need changes to both the gateway and the SDK, and they "can't provide a timeline." The 3.x README now says the same thing in its migration section. Don't plan around these coming back before the cutoff.

How do I rebuild the transcript and talking indicator?

Live transcript: transcript: true

Add transcript: true to createWebCall and you get onTranscript, onNodeTransition, and a disconnection_reason on onEnd. Two catches. onTranscripthands you the whole list on every change, so replace your state, don't append, or you'll render every line twenty times. And tool calls, DTMF and node transitions ride in the same array with their own role, so filter to agent and user for a chat-style view.

The bigger catch is security: the transcript stream needs a key with Call.Write, and it's a WebSocket that carries the key itself. A public key scoped only to web calls won't have that permission, and a proxy can't hide the key for the socket. If your marketing site shows a live transcript today, either drop it or move that page behind your own login.

Talking indicator: read the audio

For the waveform you don't need any event. Set audio: { emitRawAudioSamples: true } and the SDK attaches an AnalyserNode to the remoteaudio track (I checked the 3.0.2 bundle; it's the agent's playback, not your mic). call.analyzerComponent.calculateVolume() returns an RMS level you can threshold:

const call = client.createWebCall({
  agent_id,
  audio: { emitRawAudioSamples: true },
  hooks: { onStatus },
});

let lastLoud = 0;
function tick() {
  const level = call.analyzerComponent?.calculateVolume() ?? 0;
  const now = performance.now();
  if (level > 0.02) lastLoud = now;          // tune per voice
  setAgentTalking(now - lastLoud < 300);     // 300 ms hangover
  if (call.status !== "ended") requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

The 0.02 threshold and 300 ms hangover are starting points, not measured values. Tune them with your agent's actual voice, because a quiet voice and a loud one land in different places. The hangover matters: without it the indicator flickers between words and looks broken.

If you were using agent_start_talkingfor logic rather than looks (muting a UI, timing barge-in), that's a sign the logic belongs in the agent config, not the browser. I covered the agent-side knobs in the post on agents that keep interrupting.

metadata has no browser replacement. If your LLM websocket pushed data to the page mid-call (a booked slot, a quote), send it through your own channel: a Supabase realtime row keyed by call_idworks, and it's what I'd build anyway because it survives a page refresh.

Migration checklist

  1. grep -r "RetellWebClient\|create-web-call" across every repo, including old landing pages and Webflow/WordPress embeds that load the SDK from a CDN.
  2. Upgrade the browser package to 3.x and deploy on its own.
  3. Forward transport, url and ice_servers into startCall.
  4. Switch the server to /v3/create-web-call; stop reading call fields from its response.
  5. Make a test call and confirm it in Retell's call history, not just in your console.
  6. Rebuild the talking indicator from audio; decide where the transcript is allowed to live.
  7. Rewrite to RetellClient with a domain-restricted public key before SDK 4.0.

Step 1 is where people get burned. The SDK version that matters is the one in the page your visitor loads, and that's often a two-year-old snippet nobody remembers. If you're setting up a web agent from scratch, start on 3.x and skip all of this; my Retell setup guide covers the agent side.

If you've got Retell on a site and would rather not find out on the 19th that the call button does nothing, send me the URL and I'll tell you what needs to change.

Tested 5 October 2026 at 09:08 CT: POST /v2/create-web-call and POST /v3/create-web-call against the same Retell agent, both 201. SDK behavior read from the published retell-client-js-sdk2.0.8 and 3.0.2 tarballs (type definitions, README and bundle). Deprecation date from Retell's deprecation notice as of this morning; check it again before you plan around it.

Related Posts