Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.equos.ai/llms.txt

Use this file to discover all available pages before exploring further.

Once your backend has called startConversation, the response contains everything your web client needs to join the live room:
  • conversation.serverUrl — the LiveKit WebSocket URL
  • consumerAccessToken — the end-user’s JWT
  • conversation.character.livekitIdentity — the character’s identity for event wiring
Pick the SDK that matches your stack.

@equos/browser-sdk

Vanilla TypeScript/JavaScript. Great for custom UIs or non-React frameworks.

@equos/react

Provider + renderer components for React, Next.js, Remix, etc.

Browser SDK

Install:
npm i @equos/browser-sdk
Fetch the conversation credentials from your backend, then hand them to EquosConversation:
import { EquosConversation, EquosEvent } from "@equos/browser-sdk";

const video = document.getElementById("character-video") as HTMLVideoElement;

// 1. Get credentials from your backend
const res = await fetch("/api/start-conversation", { method: "POST" });
const { conversation: conv, consumerAccessToken } = await res.json();

// 2. Build the client with the three fields
const conversation = new EquosConversation({
  config: {
    wsUrl: conv.serverUrl,
    token: consumerAccessToken,
    agentIdentity: conv.character.livekitIdentity,
  },
});

// 3. Handle events and connect
conversation.on(EquosEvent.AgentConnected, () => conversation.attach(video));
conversation.on(EquosEvent.Utterance, ({ utterance }) =>
  console.log(utterance.author, utterance.content)
);

await conversation.connect();
Common controls:
await conversation.setMicrophoneEnabled(true);   // mic on
conversation.sendText("Hello!");                  // send a text message
await conversation.disconnect();                  // hang up
conversation.detach(video);                       // unbind the <video>

Full vanilla example

Plain HTML + TypeScript project using Vite.

React SDK

Install:
npm i @equos/react
The React SDK wraps the browser SDK in a provider + renderer so you don’t have to wire events manually:
import {
  EquosConversationProvider,
  EquosConversationRenderer,
} from "@equos/react";
import { useState } from "react";

export default function App() {
  const [response, setResponse] = useState(null);

  const start = async () => {
    const res = await fetch("/api/start-conversation", { method: "POST" });
    setResponse(await res.json()); // { conversation, consumerAccessToken }
  };

  if (!response) return <button onClick={start}>Start conversation</button>;

  return (
    <EquosConversationProvider
      conversation={response.conversation}
      accessToken={response.consumerAccessToken}
      autoPublishMic
    >
      <EquosConversationRenderer
        allowMic
        allowCamera
        allowScreenshare
        allowHangUp
        onHangUp={() => setResponse(null)}
      />
    </EquosConversationProvider>
  );
}
Inside the provider, a useEquosConversation() hook exposes methods like sendText() and sendContext() for building custom controls.

Full React example

Vite + React app using <EquosConversationProvider> and <EquosConversationRenderer>.

Next.js (full-stack pattern)

Next.js is the canonical full-stack pattern: your API key stays on the server (in a server action or route handler), and only the conversation payload crosses to the client. Server actionapp/actions.ts:
"use server";
import { equos } from "@/lib/equos"; // server-only EquosClient

export async function startConversationAction() {
  return equos.conversations.startConversation({
    createEquosConversationRequest: {
      name: `nextjs-demo-${Date.now()}`,
      characterId: process.env.EQUOS_CHARACTER_ID!,
      consumer: { name: "Demo User", identity: "demo-user" },
    },
  });
}

export async function stopConversationAction(id: string) {
  await equos.conversations.stopConversation({ id });
}
Client componentapp/conversation-client.tsx:
"use client";
import {
  EquosConversationProvider,
  EquosConversationRenderer,
} from "@equos/react";
import { useState, useTransition } from "react";
import {
  startConversationAction,
  stopConversationAction,
} from "./actions";

export function ConversationClient() {
  const [response, setResponse] = useState(null);
  const [, startTransition] = useTransition();

  const start = () =>
    startTransition(async () =>
      setResponse(await startConversationAction())
    );

  const stop = async () => {
    const id = response.conversation.id;
    setResponse(null);
    await stopConversationAction(id);
  };

  if (!response) return <button onClick={start}>Start conversation</button>;

  return (
    <EquosConversationProvider
      conversation={response.conversation}
      accessToken={response.consumerAccessToken}
      autoPublishMic
    >
      <EquosConversationRenderer
        allowMic
        allowCamera
        allowHangUp
        onHangUp={stop}
      />
    </EquosConversationProvider>
  );
}
Mark your server-side Equos client with import "server-only" so Next.js fails the build if anything tries to import the API key into a client bundle.

Full Next.js example

Next.js 15 app with server actions + @equos/react.

Features

The following features are available in both the Browser SDK and the React SDK.

Mode switch (text · audio · video)

A conversation can run in one of three modes:
  • EquosMode.Text — typed messages only, no audio or video
  • EquosMode.Audio — voice conversation, no video
  • EquosMode.Video — full video + voice (default)
import { EquosMode, EquosEvent, type EquosModeType } from "@equos/browser-sdk";

// Change mode at runtime
conversation.setMode(EquosMode.Audio);

// React to remote changes
conversation.on(EquosEvent.ModeChanged, (mode: EquosModeType) => {
  console.log("Mode is now", mode); // "text" | "audio" | "video"
});
In the React SDK, mode is a controlled prop on EquosConversationProvider—update your state and re-render to change it.

Send user text

Send a text message from the user to the character—useful for typed input, accessibility, or in EquosMode.Text conversations. Behaves like the user spoke the message.
conversation.sendText("What's the refund policy?");

Send context

Inject silent context into the conversation—information the character should know about, but that isn’t spoken by the user and doesn’t appear as a message. Great for things like:
  • Telling the character who the logged-in user is ("The user's name is Alex, Pro tier, signed up in 2024.")
  • Passing in the current page or screen the user is on
  • Feeding live data (cart contents, current order, sensor readings) as the conversation evolves
conversation.sendContext("The user is currently viewing the pricing page.");
Unlike sendText, sendContext does not surface as a user utterance. The character picks it up as background knowledge for its next response.