Tried ships one client library, @tried/web-sdk, for running web calls in the browser. Server code talks to the REST API over plain HTTPS, so any HTTP client works. The website chat widget is a single script tag.
| Where | What to use |
|---|---|
| Browser, voice | @tried/web-sdk (TriedWebClient, also exported as RetellWebClient) |
| Browser, chat | The /widget.js script, or the chat API |
| Server | The REST API at https://api.tried.com.au with any HTTP client |
Browser SDK#
@tried/web-sdk wraps livekit-client. It joins the call's LiveKit room with the token from POST /v3/create-web-call, publishes the microphone, plays the agent's audio and emits transcript and talking events. Its API matches Retell's web client, so front ends written for RetellWebClient switch by changing the import.
The package lives in the Tried monorepo at packages/web-sdk and is marked private, so it is not on the public npm registry. Build it with pnpm --filter @tried/web-sdk build and use the dist output, or add it as a workspace dependency.
Start a web call#
Never put your API key in the browser. Create the web call on your server and send the browser only the access_token and livekit_url.
// Your backend: create the web call and return the token to the browser.
const res = await fetch("https://api.tried.com.au/v3/create-web-call", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRIED_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
agent_id: "agent_3f1c9a7b2d4e6f8091a2b3c4",
retell_llm_dynamic_variables: { first_name: "Sam" },
}),
});
const { call_id, access_token, livekit_url } = await res.json();import { TriedWebClient } from "@tried/web-sdk";
const client = new TriedWebClient();
client.on("call_started", () => console.log("connected"));
client.on("agent_start_talking", () => setTalking(true));
client.on("agent_stop_talking", () => setTalking(false));
client.on("update", ({ transcript }) => render(transcript));
client.on("call_ended", () => console.log("call ended"));
client.on("error", (err) => console.error(err));
// call from a click handler so the browser allows audio
await client.startCall({ accessToken: access_token, livekitUrl: livekit_url });
// later
client.mute();
client.unmute();
client.stopCall();A browser can also start web calls without your server by using a public key from Chat Agents, Website widget. Public keys are limited to allowed domains and can require reCAPTCHA. See Deploy.
startCall(config)#
| Field | Type | Description |
|---|---|---|
accessToken |
string | Required. The access_token from create-web-call. |
livekitUrl |
string | The livekit_url from create-web-call. Falls back to the client's url option, then wss://livekit.tried.com.au. |
sampleRate |
number | Microphone sample rate. |
captureDeviceId |
string | Microphone device ID. |
playbackDeviceId |
string | Speaker device ID. |
emitRawAudioSamples |
boolean | Emit audio events with the agent's PCM samples as Float32Array. |
The microphone is opened with echo cancellation, noise suppression and auto gain control.
Methods#
| Method | Description |
|---|---|
startCall(config) |
Connect, publish the microphone and emit call_started. Throws and emits error if the connection fails. |
stopCall() |
Leave the room and emit call_ended. |
mute(), unmute() |
Turn the microphone off and on. |
startAudioPlayback() |
Resume audio when the browser blocked autoplay. Call it from a user gesture. |
on, off, once, removeAllListeners |
Event listeners. |
The isAgentTalking property is true while the agent speaks.
Events#
| Event | Payload | When |
|---|---|---|
call_started |
none | The browser joined the room and published the microphone. |
call_ready |
none | The agent joined the room. |
agent_start_talking |
none | The agent started speaking. |
agent_stop_talking |
none | The agent stopped speaking. |
update |
{ transcript: { role, content }[] } |
The live transcript changed. The array holds the whole conversation so far. |
metadata |
any | The agent published a JSON data message. |
audio |
Float32Array |
Agent audio samples, only with emitRawAudioSamples. |
call_ended |
none | The call ended, or the agent left the room. |
error |
error | Connection or listener error. |
Client options#
new TriedWebClient(options) accepts:
| Option | Description |
|---|---|
url |
Default LiveKit URL when startCall has no livekitUrl. |
audioContainer |
Function that returns the element where agent audio elements are attached. Defaults to document.body. |
roomFactory |
Replace the LiveKit room, for tests. |
Migrating from Retell's web client#
// before
// import { RetellWebClient } from "retell-client-js-sdk";
import { RetellWebClient } from "@tried/web-sdk";
const client = new RetellWebClient();
await client.startCall({ accessToken });The default export is also the client class.
Chat widget script#
Add the chat widget to a site with one script tag served by the API. It needs a public key created under Chat Agents, Website widget.
<script src="https://api.tried.com.au/widget.js"
data-public-key="public_key_..."
data-title="Chat with us"
data-color="#4f46e5"></script>Other attributes: data-api (API base URL) and data-recaptcha-site-key (reCAPTCHA v3 site key). See Chat agents.
Server code#
Tried does not publish a server SDK. Every endpoint is plain JSON over HTTPS with a bearer key, so fetch, requests or any HTTP client works. Every API reference page has cURL, Node and Python examples.
curl https://api.tried.com.au/v2/get-call/call_8d2f0c1e9b7a6543210fedcb \
-H "Authorization: Bearer $TRIED_API_KEY"const call = await fetch("https://api.tried.com.au/v2/get-call/call_8d2f0c1e9b7a6543210fedcb", {
headers: { Authorization: `Bearer ${process.env.TRIED_API_KEY}` },
}).then((r) => r.json());import os, requests
call = requests.get(
"https://api.tried.com.au/v2/get-call/call_8d2f0c1e9b7a6543210fedcb",
headers={"Authorization": f"Bearer {os.environ['TRIED_API_KEY']}"},
).json()If your existing code uses a Retell server SDK, set that SDK's base URL option to https://api.tried.com.au and pass your Tried API key. The paths it calls are the ones Tried serves; check Migrate from Retell for field and path differences.