@equos/react
v3.1.13
Published
React components for building real-time AI avatar conversations with [Equos](https://equos.ai).
Readme
@equos/react
React components for building real-time AI avatar conversations with Equos.
Provides a full conversation UI out of the box -- character video, media toggles, screenshare, hangup -- or lets you compose individual components for a custom layout.
Installation
npm install @equos/react @equos/browser-sdk @equos/core lucide-react reactImport the styles in your app entry:
import '@equos/react/dist/styles.css';Quick Start
import {
EquosConversationRenderer,
} from '@equos/react';
function App({ conversation, accessToken, onHangUp }) {
return (
<EquosConversationRenderer
conversation={conversation}
accessToken={accessToken}
allowMic
allowCamera
allowScreenshare
allowHangUp
onHangUp={onHangUp}
/>
);
}conversation is an EquosConversationWithCharacter object and accessToken is the consumer access token -- both returned by the Equos API when starting a conversation (via @equos/core or @equos/node-sdk).
Creating a conversation with @equos/node-sdk
Important:
@equos/node-sdkis a server-side only package. It requires an API key that must never be exposed to the browser. Use it from a backend (Node.js, Next.js API routes, etc.) and pass theconversationandconsumerAccessTokento your frontend.
// Server-side only (e.g. Next.js API route, Express handler)
import { EquosClient } from '@equos/node-sdk';
const client = EquosClient.create(process.env.EQUOS_API_KEY, {
endpoint: 'https://api.equos.ai',
});
const response = await client.conversations.startConversation({
createEquosConversationRequest: {
name: 'my-session',
characterId: CHARACTER_ID,
consumer: { name: 'User', identity: 'user-1' },
},
});
// Send these to the client
const { conversation, consumerAccessToken } = response;Components
EquosConversationRenderer
The main integration component. Orchestrates all media controls, character video, and user video tiles.
<EquosConversationRenderer
conversation={conversation}
accessToken={accessToken}
allowMic={true}
allowCamera={true}
allowScreenshare={false}
allowHangUp={true}
className="fixed inset-0"
characterVideoClassName="rounded-2xl"
locale={EquosLocale.EN}
onHangUp={() => { /* stop conversation */ }}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| conversation | EquosConversationWithCharacter \| null | -- | Conversation object from the API |
| accessToken | string \| null | -- | Consumer access token |
| allowMic | boolean | true | Show mic toggle |
| allowCamera | boolean | true | Show camera toggle |
| allowScreenshare | boolean | false | Show screenshare toggle |
| allowHangUp | boolean | true | Show hangup button |
| className | string | -- | Container class |
| characterVideoClassName | string | -- | Character video tile class |
| locale | EquosLocale | EN | UI language |
| onHangUp | () => void \| Promise<void> | -- | Called when hang up is triggered |
Renders a bottom toolbar with controls (mic, hangup, camera/screenshare) and overlays draggable camera and screenshare preview tiles when enabled.
EquosCharacterTile
Displays the AI character's video with connection status and remaining time.
<EquosCharacterTile
name="Tommy"
startedAt={conversation.startedAt}
maxSeconds={300}
locale={EquosLocale.EN}
recoveryTimeInSeconds={3}
showTimeLeft
onShouldLeave={handleHangUp}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| name | string | -- | Character display name |
| startedAt | Date | -- | Conversation start time |
| maxSeconds | number | -- | Max duration in seconds |
| locale | EquosLocale | EN | Language for status messages |
| recoveryTimeInSeconds | number | 3 | Grace period before auto-leave when agent disconnects |
| showTimeLeft | boolean | true | Show remaining time badge |
| onShouldLeave | () => void \| Promise<void> | -- | Called when the conversation should end (agent not joining, agent left) |
| className | string | -- | Container class |
Shows localized status messages: "joining...", "having trouble joining", and a countdown before auto-ending if the agent doesn't connect within 20 seconds.
Must be used inside an EquosConversationProvider.
EquosVideoTile
Local user video preview tile (camera or screenshare) with expand/collapse.
<EquosVideoTile source="camera" />
<EquosVideoTile source="screenshare" stream={screenshareStream} />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| source | 'camera' \| 'screenshare' | 'camera' | Video source type |
| stream | MediaStream \| null | -- | External stream (required for screenshare) |
| className | string | -- | Container class |
For camera source, automatically acquires a getUserMedia stream. For screenshare, expects a stream passed via props (managed by EquosScreenshareToggle).
EquosMicToggle
Microphone toggle button.
<EquosMicToggle onToggle={(enabled) => console.log(enabled)} />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onToggle | (enabled: boolean) => void | -- | Called when state changes |
| className | string | -- | Button class |
Defaults to enabled. Must be used inside an EquosConversationProvider.
EquosCameraToggle
Camera toggle button.
<EquosCameraToggle onToggle={(enabled) => console.log(enabled)} />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onToggle | (enabled: boolean) => void | -- | Called when state changes |
| className | string | -- | Button class |
Defaults to disabled. Must be used inside an EquosConversationProvider.
EquosScreenshareToggle
Screenshare toggle button. Manages the display media stream internally.
<EquosScreenshareToggle
onToggle={(enabled, stream) => {
setScreenshareEnabled(enabled);
setScreenshareStream(stream);
}}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onToggle | (enabled: boolean, stream: MediaStream \| null) => void | -- | Called with state and stream |
| className | string | -- | Button class |
Calls getDisplayMedia() when enabled. Automatically detects when the user stops sharing via the browser's native "Stop sharing" UI and syncs the toggle state back.
EquosHangupButton
Red hangup button with loading spinner.
<EquosHangupButton onHangup={handleHangUp} loading={isHangingUp} />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onHangup | () => void \| Promise<void> | -- | Called on click |
| loading | boolean | false | Shows spinner instead of icon |
| className | string | -- | Button class |
EquosLogo
Equos branding logo.
<EquosLogo className="size-16 rounded-xl" animate link />| Prop | Type | Default | Description |
|------|------|---------|-------------|
| className | string | -- | Image/link class |
| animate | boolean | false | Enable pulse animation |
| link | boolean | true | Wrap in link to equos.ai |
Hooks
useEquosConversation
Access the conversation instance and connection state from any component inside an EquosConversationProvider.
const { conversation, connectionState, agentConnected } = useEquosConversation();Returns:
| Field | Type | Description |
|-------|------|-------------|
| conversation | EquosConversation \| null | SDK conversation instance |
| connectionState | EquosConnectionStateType | 'disconnected' \| 'connecting' \| 'connected' \| 'reconnecting' |
| agentConnected | boolean | Whether the AI agent has joined |
EquosConversationProvider
Context provider that creates and manages the EquosConversation lifecycle.
<EquosConversationProvider
config={{ wsUrl, token, agentIdentity }}
autoPublishMic={true}
>
{children}
</EquosConversationProvider>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| config | EquosConversationConfig | -- | { wsUrl, token, agentIdentity? } |
| autoPublishMic | boolean | -- | Auto-enable mic on connect |
| mode | EquosModeType | -- | 'text' \| 'audio' \| 'video' |
| children | ReactNode | -- | Child components |
Connects on mount, disconnects on cleanup. Re-creates the connection when wsUrl, token, or agentIdentity change.
Utilities
cn
Tailwind CSS class name merger (wraps clsx + tailwind-merge).
import { cn } from '@equos/react';
cn('p-4 bg-red-500', condition && 'bg-blue-500', className);EquosLocale
Enum of supported locales for UI text.
import { EquosLocale } from '@equos/react';
// EN, FR, ES, DE, IT, PT, NL, RU, ZH, JA, KO, AR, HICopyUtils
Static class providing localized UI strings.
import { CopyUtils, EquosLocale } from '@equos/react';
CopyUtils.joiningCopy(EquosLocale.FR, 'Tommy');
// "Tommy se connecte..."
CopyUtils.timeLeftCopy(EquosLocale.EN, 120);
// "02m00s left"| Method | Description |
|--------|-------------|
| talkToCopy(locale, name?) | "Chat with [name]" |
| availableNowCopy(locale) | "Available" |
| timeLeftCopy(locale, seconds) | Formatted remaining time |
| joiningCopy(locale, name) | "[name] is joining..." |
| notJoiningCopy(locale, name) | "[name] is having trouble joining" |
| endingConversationCopy(locale, countdown) | "Auto ending in Ns..." |
| failedToHangupCopy(locale) | "We failed to hang up" |
Custom Layouts
For full control, use individual components with the provider:
import {
EquosConversationProvider,
useEquosConversation,
EquosCharacterTile,
EquosMicToggle,
EquosHangupButton,
} from '@equos/react';
function CustomConversation({ conversation, accessToken, onHangUp }) {
return (
<EquosConversationProvider
config={{
wsUrl: conversation.serverUrl,
token: accessToken,
agentIdentity: conversation.character.livekitIdentity,
}}
autoPublishMic
>
<div className="flex flex-col h-screen">
<EquosCharacterTile
name={conversation.character.name}
startedAt={conversation.startedAt}
maxSeconds={conversation.maxSeconds}
onShouldLeave={onHangUp}
/>
<div className="flex gap-2 p-4 justify-center">
<EquosMicToggle onToggle={() => {}} />
<EquosHangupButton onHangup={onHangUp} />
</div>
</div>
</EquosConversationProvider>
);
}Equos SDKs
| SDK | Platform | Package | |-----|----------|---------| | @equos/browser-sdk | Browser (vanilla JS/TS) | npm | | @equos/react | Browser (React) | npm | | @equos/node-sdk | Node.js (server-side only) | npm | | equos | Python (server-side only) | PyPI |
Reach Us
- Equos Slack Community: Join Equos Community Slack
- Support: Support Form
Documentation
- Official Documentation: https://docs.equos.ai
- Equos NodeJS Examples: https://github.com/EquosAI/equos-examples/tree/main/examples/equos-nextjs-integration
- Equos React Examples: https://github.com/EquosAI/equos-examples/blob/main/examples/equos-react-integration/README.md
