@talqing/sdk/browser is the React layer that joins a voice or video call from a web page. It wraps LiveKit so you never type livekit-client yourself, and it carries the pieces a Talqing call needs on top of a room: the token mint, userdata over RPC, images, screen share, the avatar track and frontend actions. This page is the reference. For the end-to-end integration — minting the token on your server, the first working component — read web calls and web call features.

Install

The browser layer is a second entrypoint of the same package, not a second install:
livekit-client and @livekit/components-react come with the package. react and react-dom are peer dependencies — ^18.3.1 or ^19 — and are used by this entrypoint only; the API client at @talqing/sdk renders nothing.

The three rules

One session is one call. useTalqingSession builds one Room and one token source. Start it when the component mounts and end it on the way out. To place a second call, mount a second session — render the call component while a call is up and drop it to hang up — and give it a key that changes per call. A finished session cannot be restarted. Its token names the room that call used, and the API refuses a second call rejoining it. start() on a spent session does not give you a new call. Screen share must start from a click. getDisplayMedia requires a transient user activation, so start() has to run inside a real user gesture. An agent can ask for a screen; it can never take one.

Joining a call

useTalqingSession

Builds the Room and the token source, and returns LiveKit’s session object — { room, isConnected, connectionState, start, end, waitUntilConnected, … }. callOptions is everything POST /v1/calls/token accepts except agent_id: contact_key, userdata, vars, agent_version, agent_override, agent_team. onTokenDetails receives the whole token response — including conversation_id, session_id, the minted contact_key and any warnings — the moment it is minted.
Pass contact_key — your own id for the person — if the agent should recognise a returning caller. Each call mints its own key when you leave it out, so two calls from the same person arrive as two strangers and an agent set to carry past conversations has nothing to carry. roomOptions is LiveKit’s own RoomOptions, spread over the audio capture defaults below. Override audioCaptureDefaults there if you must.

TalqingSessionProvider

Puts the session in context — which is what every hook below except useTalqingImages reads — and mounts LiveKit’s audio renderer so the agent is audible. Pass audio={false} only if you are rendering the audio element yourself.

useTalqingConnection

The call itself, read from context. room is what useTalqingImages takes; end() hangs up.
The room’s state is not the agent’s state. isConnected goes true partway through the join, while the agent is still starting up. A button keyed off isConnected alone tells the caller to speak to somebody who is not listening yet — wait for useTalqingAgent().state === "listening".

createTalqingTokenSource

What useTalqingSession builds internally. Reach for it only if you are managing your own Room. It mints once per source and caches the in-flight promise, which is load-bearing: POST /v1/calls/token files the session row the call is later read back from, and LiveKit asks its token source three times per call — to warm the connection, to connect, and once more as the call ends. Without the cache, the third mint filed a session nobody ever joined, which sat in the workspace’s call list forever. A failed mint is kept out of the cache so the surface can offer the call again. Freshness comes from a new source per call, never from re-minting inside one.

TALQING_AUDIO_CAPTURE_DEFAULTS

Applied by useTalqingSession unless your roomOptions overrides audioCaptureDefaults. Echo cancellation is what stops the agent hearing its own speech through the caller’s microphone and interrupting itself — a call without it is broken in a way that sounds like a bad model, which is why it is a default rather than something each app has to remember.

Media

useTalqingAgent

state is disconnected, connecting, pre-connect-buffering, initializing, idle, listening, thinking, speaking or failed. isFinished is true once the client has disconnected from the agent, expectedly or not.

useTalqingMessages

The live transcript, and a way to type into a voice call — useful for a spelling, an order number, or an accessible path into an audio agent. messages belongs to the live session only; the stored transcript, with tool calls and cost, is on GET /v1/calls/{session_id}.

setTalqingBrowserLogLevel

Sets the underlying LiveKit client’s log level. "debug" is the first move on a connection problem you cannot see.

Images

A caller attaches a photo mid-call and the agent sees it. The bytes go over a LiveKit byte stream addressed to the agent; the agent acknowledges over RPC, and the id send returns is the id that acknowledgement carries, so there is nothing to correlate by hand.
The agent deliberately does not speak when a photo lands. The caller is mid-conversation and about to say what it is for, so the image goes into the model’s view for their next turn.

useTalqingImages

Takes the Room rather than reading context, because a byte stream and an RPC handler are room-level things — pass useTalqingConnection().room, or the Room you built yourself. send validates, downscales, sends, and resolves once the bytes are on their way. The outcome arrives on sent, which is what a thumbnail should render. Each entry is a TalqingSentImage: unknown is the state people forget: the agent going away mid-upload, where no acknowledgement is ever coming. It is set after 30 seconds of silence, with “we did not hear back — the agent may not have received it”.

talqingImageRejection

The sentence to show, or null when the file is fine. Refuses anything that is not JPEG, PNG or WebP (“that file is not a JPEG, PNG or WebP”) and anything over 10 MB (“images are 10 MB or smaller”). The server re-validates regardless — this exists so the common mistakes cost nothing to catch.

talqingDownscaleImage

Downscales to 1568 px on the longest edge and re-encodes — PNG stays PNG to keep transparency, everything else becomes JPEG at quality 0.85. It is also what normalizes whatever the OS handed the file input, so a Safari HEIC becomes a JPEG here. Throws if the image cannot be decoded. useTalqingImages.send calls it for you.

talqingImageDataUrl

Validate and downscale into the data: URL a text message carries — POST /v1/conversations/messages takes images: [{ data_url, filename }], and this produces the data_url. It doubles as a thumbnail src, so there is no object URL to create and revoke. Throws the sentence to show if the file is refused.

Image constants

Screen share

useTalqingScreenShare

enabled is whether a screen is being shared right now; pending is true while the browser picker is open or the track is publishing. stop() ends it, and the agent is told it can no longer see on its next turn.
start() must be called from a user gesture. A browser will not open the share picker for a page that asks on its own.
The capture and publish options are fixed, and they are the reason a shared screen stays readable:

Userdata

Read and write the live session’s userdata from the page, over RPC to the agent. See userdata for what it is.

useTalqingUserdata

Bound to the connected room. Both throw Error("room is not connected") when there is no room.

setTalqingUserdata and getTalqingUserdata

The same calls outside React, against a Room you hold. They find the agent participant and call talqing.client.userdata_set / talqing.client.userdata_get on it. With no agent connected, set resolves { ok: false, error: "agent participant is not connected" } while get throws — a write that did not land is a state you can render, a read that returned nothing is not. Omit keys on get to fetch the whole bag.

Frontend RPC

A tool’s frontend_rpc operation calls back into your page mid-call — to highlight a product, open a form, or move the user along. See frontend RPC for the tool side.

useTalqingRpcHandlers

Registers the talqing.frontend_rpc method on the room and dispatches by the envelope’s method. A "*" key catches everything unmatched — and when the wildcard handles a call, data.payload is the whole envelope (method and payload) rather than just the payload, so the handler can tell what it caught. An unknown method with no wildcard throws TalqingRpcError code 1404 back to the agent; anything else your handler throws goes back as code 1500 with its message. Each handler receives a TalqingRpcInvocation: and must return a string (or a promise of one), which is what the agent receives.
Registration is skipped until the room is connected, and unregistered on unmount. Pass enabled: false to hold off.

useTalqingFrontendRpcs

The declarative alternative: it registers a wildcard handler for you and keeps the latest payload per method name, with at as the timestamp it arrived. Always answers the agent "ok". Use it to render whatever the agent asked for without writing a handler per method.

TalqingRpcError

Throw it from a handler to send a specific code back to the agent instead of the generic 1500.

Video

useTalqingAvatarTrack

Finds the video track to render for a video agent. It prefers the avatar worker’s camera track — the worker publishes on the agent’s behalf, which is how it is identified — and falls back through the worker’s screen share and then the agent’s own tracks. undefined until one is published.

TalqingVideoTrack

Renders it at the publication’s own dimensions.

Exported types

Web calls

The token, the join, and a complete integration.

Web call features

Images, screen share, userdata and frontend actions in context.