React
@zentiq/react gives you two components and a hook, on top of the browser SDK. Both components call your server, which holds the API key.
npm install @zentiq/react@^1 @zentiq/client@^1Coming to npm
@zentiq/react 1.0.0 is being released with the 2026-10-01 contract. The command above installs 1.0.0 or a later 1.x only, so it works as soon as 1.0.0 is out.It works with React 18 and later.
An embedded portal#
For the people already signed in to your app: your server asks for a five-minute, single-use embed token (POST /v1/portals/{id}/embed-tokens) after your own sign-in, and the component mounts the portal with it. It fetches a fresh token each time it mounts.
import { ZentiqPortal } from "@zentiq/react";
<ZentiqPortal getEmbedToken={() => fetch("/api/zentiq-embed").then((r) => r.json())} height={760} />;Or pass embedUrl. Only https (and http) addresses are ever mounted. The portal must be published.
A live session#
import { ZentiqSession } from "@zentiq/react";
<ZentiqSession getSession={() => fetch("/api/zentiq-session", { method: "POST" }).then((r) => r.json())} showTranscript />;It shows the avatar with its AI label (from the first render, restyle or move it with aiLabel, as in the browser SDK), the notice when the session starts, a start and an end button, captions, and for a duo, a name plate for each person that lights up while they speak. getSession calls your server, which starts the session. The end button leaves the room: have your server end the session too (see Live sessions).
For your own interface, the hook gives you the same state:
import { useZentiqSession } from "@zentiq/react";
function Tutor() {
const s = useZentiqSession({ getSession: () => fetch("/api/zentiq-session", { method: "POST" }).then((r) => r.json()) });
return (
<div>
{/* The AI label and the start notice are drawn on the video's container for you. */}
<div>
<video ref={s.videoRef} autoPlay playsInline />
</div>
<button onClick={s.status === "live" ? s.end : s.start}>{s.status === "live" ? "End" : "Talk"}</button>
</div>
);
}