Skip to the content
Menu: Browser

Browser SDK

@zentiq/client joins a live session in the browser: it shows the avatar in a <video> element, plays its voice, uses the microphone, and tells you what is said and who is speaking. It never needs your API key: your server starts the session and hands the browser the answer of POST /v1/sessions/tokens.

Install
npm install @zentiq/client@^1

Coming to npm

@zentiq/client 1.0.0 is being released with the 2026-10-01 contract. npm has 0.2.0, an earlier version. The command above installs 1.0.0 or a later 1.x only, so it works as soon as 1.0.0 is out.

npm 7 or later also installs the one package it needs alongside it; with another package manager, install the peer dependency its package.json names.

Join#

quickstart-browser.ts
import { joinSession, type SessionToken } from "@zentiq/client";

const token = (await fetch("/zentiq/session", { method: "POST" }).then((r) => r.json())) as SessionToken;

// People must know they are talking to an AI: show the persona's words for the whole session.
const disclosure = document.querySelector<HTMLElement>("#disclosure");
if (disclosure && token.disclosure?.required) disclosure.textContent = token.disclosure.text;

const session = await joinSession(token, {
  video: document.querySelector<HTMLVideoElement>("#avatar")!,
  onTranscript: (t) => {
    if (t.final) console.log(t.role === "user" ? "You" : t.speaker ?? token.persona.name, t.text);
  },
  onSpeaking: (who) => document.body.setAttribute("data-speaking", who),
});

joinSession(token, options) takes the whole token answer (it names the persona, so a duo's two people are known). The options:

OptionWhat it does
videoThe <video> element the avatar appears in (autoplay, playsinline).
audioAnother element for the voice, if you want one.
microphoneStart with the microphone on (default true).
onTranscript(t)Captions: { role, text, final, speaker }, and for a duo's turn, lines with each person's words.
onSpeaking(who)"avatar", "user" or "none".
onSpeakerChange(name)A duo: the person speaking now, or null.
onEvent(e)The session's live events, each with seq, type, ts and data: what the person said (learner.transcript.partial, learner.transcript.final), the avatar's whole turn (tutor.transcript.final) and, for a line your server sent with sessionSay, avatar.speaking.start and avatar.speaking.end. New types can appear: ignore the ones you don't handle.
onReady, onEnd, onErrorWhen the session is joined, when it ends, when something fails.

It answers with a session: setMicrophoneEnabled(on), end(), the cast (who is on the stage) and sessionId.

Leaving and ending#

quickstart-browser.ts
document.querySelector("#end")?.addEventListener("click", async () => {
  session.end(); // leaves the room
  // …and your server ends the session, so its minutes stop now.
  await fetch("/zentiq/end", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sessionId: token.sessionId }) });
});

session.end() leaves the room. It doesn't end the session: your server does, with POST /v1/sessions/{id}/end, and its minutes stop then. If the page just closes, Zentiq's clean-up ends the session a few minutes after the room is found empty.

Duos#

A duo's token names both people ("Mark & Susan"). The SDK then knows who is on the stage (session.cast.members, left then right), names the speaker on every caption, and calls onSpeakerChange as the floor passes from one to the other. castOf(name) and namedLines(text, cast) are exported for your own interface.

The AI label#

joinSession draws an AI label on the avatar's video for the whole session, in the session's language (the token's disclosure.label), and shows the token's notice for a few seconds when the session starts. It marks the video data-ai-generated="true" and describes it with the label for screen readers. It needs no style sheet, and the video's container becomes its frame (a container that is position: static is set to relative).

aiLabel optionWhat it does
position"top-left" (default), "top-right", "bottom-left" or "bottom-right".
className, styleRestyle it. A style can't hide it.
textYour own words; they must still say it's an AI.
noticeMsHow long the start notice stays (at least 3 seconds).
show: falseHide it, only when the token's disclosure.ownLabel is true.

In full screen, put the video's container in full screen, not the video. See Telling people it's an AI.