Production-ready React SDK for Anam AI with dual-mode operation, WebSocket integration, and message accumulation
npm install @centive/aria-sdkA production-ready SDK for integrating Anam AI into your web application. Simple initialization, automatic session management, and a beautiful AI assistant interface.


``typescript
import { Aria } from '@centive/aria-sdk';
// Initialize with just 3 lines
Aria.init({
websocketUrl: 'wss://your-server.com/ws',
userId: 'user_123',
});
// That's it! The floating button appears automatically.
`
`bash`
npm install @centive/aria-sdk
`bash`
npm install react@^18.0.0 react-dom@^18.0.0 @anam-ai/js-sdk@^4.7.0
| Feature | Description |
|---------|-------------|
| Simple Init | Single function call to set up everything |
| Auto Session Management | WebSocket connection, token refresh, reconnection - all automatic |
| Dual-Mode UI | Floating button + center modal for WebSocket-triggered events |
| Session Persistence | Sessions survive page navigation and widget close/reopen |
| Error Recovery | Automatic reconnection with exponential backoff |
| Tool Call Indicators | Visual feedback when AI executes functions |
| Theme Support | Light and dark themes |
`typescript
Aria.init({
// Required
websocketUrl: string, // Your backend WebSocket URL
userId: string, // Unique user identifier
// Optional
theme?: 'light' | 'dark', // UI theme (default: 'light')
triggerLabel?: string, // Button label (default: 'Talk to Aria')
onError?: (error: Error) => void, // Error callback
});
`
`typescript
import { Aria } from '@centive/aria-sdk';
Aria.init({
websocketUrl: 'wss://api.example.com/ws',
userId: 'user_123',
theme: 'dark',
triggerLabel: 'Need Help?',
onError: (error) => {
console.error('Aria SDK error:', error);
},
});
`
| Method | Description |
|--------|-------------|
| Aria.init(config) | Initialize the SDK |Aria.open(mode?)
| | Open assistant widget ('user' or 'websocket') |Aria.close()
| | Close assistant widget |Aria.minimize()
| | Minimize to compact state |Aria.maximize()
| | Restore from minimized |Aria.destroy()
| | Cleanup and remove SDK |Aria.isInitialized()
| | Check if SDK is initialized |Aria.isOpen()
| | Check if widget is open |Aria.isConnected()
| | Check WebSocket connection |Aria.getSessionId()
| | Get current session ID |Aria.refreshSession()
| | Manually refresh session |
`typescript
// Open the assistant
Aria.open();
// Open in center mode (like incoming call)
Aria.open('websocket');
// Close the assistant
Aria.close();
// Minimize/maximize
Aria.minimize();
Aria.maximize();
// Check status
if (Aria.isConnected()) {
console.log('Session ID:', Aria.getSessionId());
}
// Cleanup when done
Aria.destroy();
`
The SDK connects to your backend via WebSocket. Your backend handles:
1. User Authentication - Validate the connecting user
2. Session Token Generation - Create Anam AI sessions
3. Persona Configuration - Control AI behavior server-side (avatar, voice, LLM, system prompt)
4. Message Storage - Store conversation history (optional)
#### 1. Session Request (user_trigger)
Sent when user opens the widget to request a new session token.
`json`
{
"user_trigger": true,
"userId": "user_123",
"skip_greeting": true // true after first session (to skip greeting on reopen)
}
| Field | Type | Description |
|-------|------|-------------|
| user_trigger | boolean | Always true when requesting a session |userId
| | string | User identifier passed to Aria.init() |skip_greeting
| | boolean | true if user has already had a session (skip greeting on subsequent opens) |
#### 2. Message History
Sent when conversation messages are updated.
`json`
{
"type": "message_history",
"session_id": "anam_session_abc123",
"user_id": "user_123",
"messages": [
{ "role": "persona", "content": "Hello! How can I help?", "timestamp": "2026-01-29T12:00:00.000Z" },
{ "role": "user", "content": "I need help with my account", "timestamp": "2026-01-29T12:00:05.000Z" }
]
}
#### 3. Message Stream
Sent for real-time message streaming (as user/persona speaks).
`json`
{
"type": "message_stream",
"session_id": "anam_session_abc123",
"user_id": "user_123",
"message": {
"role": "user",
"content": "partial transcript...",
"timestamp": "2026-01-29T12:00:05.000Z",
"is_final": false
}
}
#### 4. Session End
Sent when user closes the widget (hangs up).
`json`
{
"type": "session_end",
"session_id": "anam_session_abc123",
"user_id": "user_123"
}
#### Session Token Response
`json`
{
"status": "success",
"message": "Session created successfully",
"session_data": {
"session_id": "sess_abc123",
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-01-27T12:00:00Z"
},
"time_taken": 1234
}
#### Message Acknowledgments (Optional)
`json
// Message history acknowledgment
{ "status": "ok", "type": "message_history_ack", "message_count": 5 }
// Message stream acknowledgment (for is_final: true)
{ "status": "ok", "type": "message_stream_ack" }
// Session end acknowledgment
{ "status": "ok", "type": "session_end_ack", "message": "Session ended", "saved_count": 10 }
`
`javascript
const WebSocket = require('ws');
const axios = require('axios');
const wss = new WebSocket.Server({ port: 8000 });
wss.on('connection', (ws) => {
ws.on('message', async (message) => {
const data = JSON.parse(message);
// Handle session request
if (data.user_trigger !== undefined) {
const startTime = Date.now();
const session = await createAnamSession(data.userId, data.skip_greeting);
ws.send(JSON.stringify({
status: 'success',
message: 'Session created',
session_data: {
session_id: session.id,
token: session.sessionToken,
expires_at: session.expiresAt,
},
time_taken: Date.now() - startTime,
}));
}
// Handle message history (store in database)
if (data.type === 'message_history') {
await storeMessages(data.session_id, data.user_id, data.messages);
ws.send(JSON.stringify({
status: 'ok',
type: 'message_history_ack',
message_count: data.messages.length,
}));
}
// Handle session end
if (data.type === 'session_end') {
await finalizeSession(data.session_id, data.user_id);
ws.send(JSON.stringify({
status: 'ok',
type: 'session_end_ack',
message: 'Session ended',
saved_count: 10,
}));
}
});
});
async function createAnamSession(userId, skipGreeting = false) {
const response = await axios.post(
'https://api.anam.ai/v1/auth/session-token',
{
personaConfig: {
name: 'Aria',
avatarId: 'your-avatar-id',
voiceId: 'your-voice-id',
llmId: 'your-llm-id',
systemPrompt: 'You are Aria, a helpful AI assistant.',
skip_greeting: skipGreeting, // Pass skip_greeting to Anam
},
},
{
headers: { 'Authorization': Bearer ${process.env.ANAM_API_KEY} },
}
);
return response.data;
}
async function storeMessages(sessionId, userId, messages) {
// Store messages in your database
console.log(Storing ${messages.length} messages for user ${userId});
}
async function finalizeSession(sessionId, userId) {
// Mark session as complete, perform any cleanup
console.log(Session ${sessionId} ended for user ${userId});`
}
The SDK manages Anam sessions automatically:
| Event | What Happens |
|-------|--------------|
| Widget Opens (first time) | Sends user_trigger with skip_greeting: false → Creates Anam session with greeting |session_end
| Widget Closes (hang up) | Sends → Ends Anam session to free resources |user_trigger
| Widget Reopens | Sends with skip_greeting: true → Creates new session without greeting |user_trigger
| Page Refresh | Sends with skip_greeting: false → Fresh session with greeting |
This ensures:
- Anam resources are freed when the widget is closed
- Users don't hear the greeting repeatedly when reopening the widget
- Conversation context can be restored via your backend's message storage
For video sessions to persist across page navigation, initialize the SDK at the root level of your application:
`tsx
// App.tsx - Correct placement
import { Aria } from '@centive/aria-sdk';
// Initialize once at app startup
Aria.init({
websocketUrl: 'wss://your-server.com/ws',
userId: 'user_123',
});
function App() {
return (
);
}
`
The @anam-ai/js-sdk requires a Buffer polyfill. See the Integration Guide for Vite, Webpack, and Next.js configurations.
Quick fix for Vite:
`bash`
npm install buffer
`typescript`
// main.tsx (at the very top)
import { Buffer } from 'buffer';
globalThis.Buffer = Buffer;
- Use secure WebSocket connections (wss://`) in production
- Store Anam API keys only on the backend
- Validate user IDs on your backend
- Never expose API keys in frontend code
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Opera (latest)
Requires WebRTC support for video streaming.
- Integration Guide - Complete integration documentation
- WebSocket Events - Message specifications
- Type Reference - TypeScript types
- Anam AI Docs - Platform documentation
MIT © Centive