---
title: Simple Client-Side Example
url: https://docs.kaltura.com/docs/conversational-agents/agentic-avatars-sdk/examples-simple-client-side
---

## Simple Client-Side Example

Complete working example using SDK-based control (client-side only).

> **For Demos and Prototypes**
> This approach is perfect for demos, prototypes, and learning. For production, see [Server Controlled Example](/docs/conversational-agents/agentic-avatars-sdk/examples-server-controlled).

### Complete HTML + JavaScript Example

#### `index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Kaltura Avatar - Simple Example</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        max-width: 800px;
        margin: 50px auto;
        padding: 20px;
      }
      #avatar-container {
        width: 512px;
        height: 512px;
        border: 2px solid #333;
        border-radius: 12px;
        overflow: hidden;
        background: #000;
        margin: 20px 0;
      }
      .controls {
        display: flex;
        gap: 10px;
        margin: 20px 0;
      }
      button {
        padding: 12px 24px;
        font-size: 16px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        transition: background 0.3s;
      }
      button:hover:not(:disabled) {
        opacity: 0.9;
      }
      button:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }
      .primary {
        background: #007bff;
        color: white;
      }
      .danger {
        background: #dc3545;
        color: white;
      }
      .warning {
        background: #ffc107;
        color: black;
      }
      #status {
        padding: 12px;
        border-radius: 6px;
        margin: 20px 0;
        font-weight: bold;
      }
      #status.idle {
        background: #e9ecef;
      }
      #status.creating {
        background: #fff3cd;
        color: #856404;
      }
      #status.ready {
        background: #d4edda;
        color: #155724;
      }
      #status.error {
        background: #f8d7da;
        color: #721c24;
      }
      textarea {
        width: 100%;
        height: 100px;
        padding: 10px;
        font-size: 14px;
        border: 2px solid #ddd;
        border-radius: 6px;
        resize: vertical;
      }
      .error-message {
        color: #721c24;
        background: #f8d7da;
        padding: 10px;
        border-radius: 6px;
        margin: 10px 0;
        display: none;
      }
    </style>
  </head>
  <body>
    <h1>Kaltura Avatar - Simple Example</h1>
    <div id="status" class="idle">Not started</div>

    <!-- Avatar display -->
    <div id="avatar-container"></div>

    <!-- Controls -->
    <div class="controls">
      <button id="start-btn" class="primary">Start Avatar</button>
      <button id="end-btn" class="danger" disabled>End Session</button>
    </div>

    <!-- Text input -->
    <div>
      <textarea id="text-input" placeholder="Enter text for avatar to speak..."
        >Hello! I am your Kaltura Avatar. How can I help you today?</textarea
      >
      <div class="controls">
        <button id="speak-btn" class="primary" disabled>
          Make Avatar Speak
        </button>
        <button id="interrupt-btn" class="warning" disabled>Interrupt</button>
      </div>
    </div>

    <div id="error-message" class="error-message"></div>

    <script type="module" src="main.js"></script>
  </body>
</html>
```

#### `main.js`

```javascript
import { KalturaAvatarSession } from '@unisphere/models-sdk-js';

// Configuration
const KS = 'your-api-key-here'; // TODO: Replace with your Kaltura Session
const BASE_URL = 'https://api.avatar.us.kaltura.ai/';
const VISUAL_ID = 'visual-123';
const VOICE_ID = 'voice-456';

// UI Elements
const statusEl = document.getElementById('status');
const avatarContainer = document.getElementById('avatar-container');
const startBtn = document.getElementById('start-btn');
const endBtn = document.getElementById('end-btn');
const speakBtn = document.getElementById('speak-btn');
const interruptBtn = document.getElementById('interrupt-btn');
const textInput = document.getElementById('text-input');
const errorMessageEl = document.getElementById('error-message');

// Avatar session
let session = null;

// Update status
function setStatus(status, message) {
  statusEl.textContent = message;
  statusEl.className = status;
}

// Show error
function showError(message) {
  errorMessageEl.textContent = message;
  errorMessageEl.style.display = 'block';
  setTimeout(() => {
    errorMessageEl.style.display = 'none';
  }, 5000);
}

// Enable/disable controls
function updateControls(state) {
  startBtn.disabled = state !== 'idle';
  endBtn.disabled = state !== 'ready';
  speakBtn.disabled = state !== 'ready';
  interruptBtn.disabled = state !== 'ready';
}

// Start avatar
startBtn.addEventListener('click', async () => {
  try {
    setStatus('creating', 'Creating avatar session...');
    updateControls('creating');

    // Create SDK instance
    session = new KalturaAvatarSession({
      apiKey: API_KEY,
      baseUrl: BASE_URL,
      logLevel: 'info',
    });

    // Setup event listeners
    session.on('stateChange', (state) => {
      console.log('Session state:', state);
      switch (state) {
        case 'READY':
          setStatus('ready', `Avatar ready! Session: ${session.getSessionId()}`);
          updateControls('ready');
          break;
        case 'ENDED':
          setStatus('idle', 'Session ended');
          updateControls('idle');
          session = null;
          break;
        case 'ERROR':
          setStatus('error', 'Session error occurred');
          updateControls('idle');
          break;
      }
    });

    session.on('connectionChange', (state) => {
      console.log('Connection state:', state);
    });

    session.on('error', (error) => {
      console.error('Avatar error:', error.code, error.message);
      showError(`Error: ${error.message}`);
      setStatus('error', 'Error occurred');
      updateControls('idle');
    });

    // Create session with auto-attach
    await session.createSession({
      visualId: VISUAL_ID,
      voiceId: VOICE_ID,
      videoContainerId: 'avatar-container',
    });

    console.log('Avatar started!');

    // Welcome message
    await session.sayText('Hello! I am ready to assist you.');
  } catch (error) {
    console.error('Failed to start avatar:', error);
    showError(`Failed to start avatar: ${error.message}`);
    setStatus('error', 'Failed to start avatar');
    updateControls('idle');
  }
});

// Make avatar speak
speakBtn.addEventListener('click', async () => {
  if (!session) {
    showError('No active session');
    return;
  }

  const text = textInput.value.trim();
  if (!text) {
    showError('Please enter text');
    return;
  }

  try {
    await session.sayText(text);
    console.log('Avatar speaking:', text);
  } catch (error) {
    console.error('Failed to make avatar speak:', error);
    showError(`Failed: ${error.message}`);
  }
});

// Interrupt avatar
interruptBtn.addEventListener('click', async () => {
  if (!session) {
    showError('No active session');
    return;
  }

  try {
    await session.interrupt();
    console.log('Avatar interrupted');
  } catch (error) {
    console.error('Failed to interrupt:', error);
    showError(`Failed to interrupt: ${error.message}`);
  }
});

// End session
endBtn.addEventListener('click', async () => {
  if (!session) {
    showError('No active session');
    return;
  }

  try {
    await session.endSession();
    console.log('Session ended');
    setStatus('idle', 'Session ended');
    updateControls('idle');
    session = null;
  } catch (error) {
    console.error('Failed to end session:', error);
    showError(`Failed to end session: ${error.message}`);
  }
});

// Cleanup on page unload
window.addEventListener('beforeunload', () => {
  if (session) {
    session.endSession();
  }
});

// Initial state
updateControls('idle');
```

### Running the Example

#### 1. Install Dependencies

```bash
npm install @unisphere/models-sdk-js
```

#### 2. Setup Build Tool (Vite)

```bash
npm install -D vite
```

#### `package.json`

```json
{
  "name": "avatar-demo",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "@unisphere/models-sdk-js": "latest"
  },
  "devDependencies": {
    "vite": "latest"
  }
}
```

#### 3. Update Configuration

In `main.js`, replace:

- `API_KEY` - Your Kaltura Session
- `BASE_URL` - Your API endpoint
- `VISUAL_ID` - Your visual ID
- `VOICE_ID` - Your voice ID

#### 4. Run

```bash
npm run dev
```

Open [http://localhost:5173](http://localhost:5173) in your browser.

### Features Demonstrated

- Session creation with auto-attach
- Event handling (state, connection, error)
- Making avatar speak
- Interrupting speech
- Ending session
- Error handling
- UI state management

### Next Steps

- **[Server Controlled Example](/docs/conversational-agents/agentic-avatars-sdk/examples-server-controlled)** - Production-ready approach
- **[React Integration](/docs/conversational-agents/agentic-avatars-sdk/examples-react-integration)** - Use with React
- **[Error Recovery](/docs/conversational-agents/agentic-avatars-sdk/examples-error-recovery)** - Robust error handling
