Browser SDK
@dialgem/client: microphone, playback and live events for a web call, with a React hook.
@dialgem/client lets a visitor talk to an agent from a web page. It opens the microphone, streams the voice to the agent, plays the reply as it arrives, and gives you events for your interface. Your API key never reaches the page.
It has no runtime dependencies. It works in Chrome 66+, Edge 79+, Firefox 76+ and Safari 14.1+ (anything with AudioWorklet), over HTTPS or localhost.
Install
npm install @dialgem/clientHow a call starts
Your server asks Dialgem for a call with your API key and gives the page a one-use token that lasts 60 seconds. The page connects with that token alone.
// On your server, with @dialgem/sdk
const { access_token } = await dialgem.webCalls.create({ agent_id: "AGENT_ID" })// On your page
import { DialgemCall } from "@dialgem/client"
const call = new DialgemCall({
accessToken: () => fetch("/api/start-call").then((r) => r.text()),
})
call.on("transcript", (t) => console.log(t.role, t.text, t.final ? "" : "…"))
call.on("agent_speaking", ({ speaking }) => orb.classList.toggle("talking", speaking))
call.on("ended", ({ reason }) => console.log("call ended:", reason))
call.on("error", (e) => alert(e.message))
button.onclick = () => call.start() // from a click: browsers only allow sound after one
hangUp.onclick = () => call.stop()Before the first call, allow your page's origin in Settings, Web calls, or with webCalls.updateSettings. See Web calls.
React
import { useDialgemCall } from "@dialgem/client/react"
function Talk() {
const call = useDialgemCall({ getAccessToken: () => fetch("/api/start-call").then((r) => r.text()) })
return (
<>
<button onClick={call.start} disabled={call.state === "connecting" || call.state === "active"}>Talk to us</button>
{call.state === "active" && <button onClick={call.stop}>Hang up</button>}
{call.transcript.map((l) => <p key={l.id}>{l.role}: {l.text}</p>)}
{call.error && <p role="alert">{call.error.message}</p>}
</>
)
}React 18 or newer is an optional peer dependency.
DialgemCall
new DialgemCall({ accessToken, microphone? })
accessTokenis the token, or a function returning it (sync or async). A function is called after the visitor has allowed the microphone, because the token lives 60 seconds and a permission prompt can take longer.microphoneis{ deviceId, echoCancellation, noiseSuppression, autoGainControl }. The last three default totrue. Without echo cancellation the agent's own voice comes back through the microphone and it answers itself.
Methods: start() (resolves when connected), stop(), and setMuted(boolean) (the agent hears silence and the call stays open). Properties: state, callId, muted.
A DialgemCall is used once, because a token is single-use. The React hook makes a new one on every start().
Events
| Event | Payload |
|---|---|
state | idle, connecting, active, ended or error. |
started | { callId }. The agent is live. |
transcript | { role: "user" or "agent", text, final }. A caller's line arrives as final: false while they speak, then settles. |
agent_speaking | { speaking }. True from the first audio until it has played out. |
interrupted | The caller talked over the agent. |
level | { level }: microphone level from 0 to 1, about ten times a second. |
ended | { reason }: hangup, agent_ended or connection_lost. |
error | { code, message, reason? } |
Error codes
| Code | Meaning |
|---|---|
unsupported | The browser lacks AudioWorklet, or your Content-Security-Policy blocks blob:. |
mic_denied, mic_unavailable | The microphone was refused or is missing. |
token_unavailable | Your function that fetches the token failed. |
refused | The token is invalid, expired or used, or the page's origin is not allowed. reason says which. |
busy | Too many calls are running. |
call_refused | The server declined the call. reason says why, for example insufficient_credit. |
server_error, connection_failed | A failure on the way. |
See Troubleshooting for fixes.
There is no reconnecting
The conversation lives on the server for as long as the connection does, and the token is single-use. A call that drops has ended with reason: "connection_lost". Tell the visitor and start a new one.
Things worth knowing
- Content-Security-Policy. The audio processor loads from a
blob:URL, soscript-srcneedsblob:. - Autoplay. Call
start()straight from a click or tap handler. Browsers count that as the visitor starting the sound. - Billing. Browser calls are billed like any other call. See Billing and pricing.