---
title: JavaScript SDK
sidebar_position: 3
---

# JavaScript SDK

`@elaras/chat-sdk` is a zero-dependency TypeScript SDK that wraps the Elaras Chat API. Use it when you want to build a completely custom chat UI without the widget.

## Installation

```bash
npm install @elaras/chat-sdk
```

## Quick start — streaming

```ts
import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({chatbotKey: 'cbt_your_key_here'});

const sessionId = client.getOrCreateSessionId();

for await (const event of client.stream(sessionId, 'What are your opening hours?')) {
  if (event.type === 'delta') {
    process.stdout.write(event.content); // stream tokens to the UI
  } else if (event.type === 'done') {
    console.log('\nCredits used:', event.credits_used);
  } else if (event.type === 'error') {
    console.error('Error:', event.message);
  }
}
```

## Creating a client

```ts
import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({
  chatbotKey: 'cbt_your_key_here',
  // apiUrl defaults to 'https://api.elaras.ai'
  apiUrl: 'https://api.elaras.ai',
});
```

### Options

| Option | Type | Required | Description |
|---|---|---|---|
| `chatbotKey` | `string` | Yes | Your public chatbot key (`cbt_...`) |
| `apiUrl` | `string` | No | Override the API base URL. Defaults to `https://api.elaras.ai` |

## Methods

### `getConfig()`

Fetches the chatbot's public configuration — name, greeting, appearance settings, and lead capture setup. Called automatically by `stream()` if needed; you only need to call it directly if you want to read config values before starting a conversation.

```ts
const config = await client.getConfig();

console.log(config.name);              // "Aria"
console.log(config.greeting_message); // "Hi! How can I help?"
console.log(config.collect_leads);    // true
console.log(config.appearance?.primary_color); // "#00C4A7"
```

**Returns:** `ChatbotConfig`

```ts
interface ChatbotConfig {
  id:               string;
  name:             string;
  avatar_url?:      string | null;
  greeting_message: string | null;
  collect_leads:    boolean;
  lead_prompt:      string | null;
  appearance: {
    primary_color?: string;
    position?:      'bottom-right' | 'bottom-left';
    bubble_text?:   string;
    powered_by?:    boolean;
    theme?:         'light' | 'dark' | 'auto';
  } | null;
  triage_questions: {
    ask_name:  { enabled: boolean; question: string };
    ask_email: { enabled: boolean; question: string };
    custom:    { question: string }[];
  } | null;
}
```

---

### `stream(sessionId, message)`

Sends a message and returns an async generator that yields streaming events as the AI responds. Uses a WebSocket connection for real-time token delivery.

```ts
for await (const event of client.stream(sessionId, 'Tell me about your plans.')) {
  switch (event.type) {
    case 'delta':
      // A new token arrived — append to the current message
      appendToUI(event.content);
      break;

    case 'done':
      // Response complete
      console.log('Message ID:', event.message_id);
      console.log('Credits used:', event.credits_used);
      break;

    case 'error':
      console.error('Error code:', event.code);
      console.error('Error message:', event.message);
      break;
  }
}
```

**Event types:**

| Event | Fields | Description |
|---|---|---|
| `delta` | `content: string` | Next token chunk from the AI |
| `done` | `message_id: number`, `credits_used: number` | Response complete |
| `error` | `message: string`, `code?: string` | An error occurred |

---

### `send(sessionId, message)`

Sends a message and waits for the complete AI response synchronously (no streaming). Useful for server-side or simple integrations where you do not need real-time delivery.

```ts
const result = await client.send(sessionId, 'What are your prices?');

console.log(result.response);      // Full AI response text
console.log(result.message_id);    // Database ID of the saved message
console.log(result.credits_used);  // Credits consumed
```

**Returns:**

```ts
interface CompletionResult {
  message_id: number;
  response: string;
  credits_used: number;
}
```

---

### `getOrCreateSessionId()`

Returns the current session UUID from `localStorage`, or generates a new one if none exists. Call this once when your chat component mounts.

```ts
const sessionId = client.getOrCreateSessionId();
// e.g. "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
```

The session ID is stored in `localStorage` under `elaras_session_{chatbotKey}` and persists across page reloads.

---

### `clearSessionId()`

Removes the session UUID from `localStorage`, causing the next call to `getOrCreateSessionId()` to generate a fresh session. Use this for a "start over" button.

```ts
client.clearSessionId();
const freshSessionId = client.getOrCreateSessionId(); // New UUID
```

---

### `getSession(sessionId)`

Fetches the session and its full message history from the API.

```ts
const session = await client.getSession(sessionId);

for (const msg of session.messages) {
  console.log(`[${msg.role}] ${msg.content}`);
}
```

**Returns:**

```ts
interface Session {
  session: string;     // Session UUID
  messages: ChatMessage[];
}

interface ChatMessage {
  id: number;
  session_id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  credits_used: number | null;
  feedback: 'up' | 'down' | null;
  created_at: string;
}
```

---

### `clearSession(sessionId)`

Deletes all messages in the session on the server. The session UUID remains valid — the next message will start a fresh conversation.

```ts
await client.clearSession(sessionId);
```

---

### `submitLead(sessionId, lead)`

Associates an email address (and optional name) with the session. Triggers the `lead.captured` webhook event.

```ts
await client.submitLead(sessionId, {
  email: 'user@example.com',
  name: 'Jordan',         // optional
});
```

---

### `submitTriage(sessionId, answers)`

Submits pre-chat triage answers collected before the conversation begins.

```ts
await client.submitTriage(sessionId, [
  {type: 'name',   question: 'What is your name?',         answer: 'Jordan'},
  {type: 'email',  question: 'What is your email?',        answer: 'jordan@example.com'},
  {type: 'custom', question: 'What can we help you with?', answer: 'Billing question'},
]);
```

Each answer has these fields:

| Field | Type | Values |
|---|---|---|
| `type` | `string` | `'name'` \| `'email'` \| `'custom'` |
| `question` | `string` | The question text |
| `answer` | `string` | The user's answer |

---

### `submitFeedback(messageId, rating)`

Records thumbs-up or thumbs-down feedback for an AI response.

```ts
await client.submitFeedback(42, 'up');   // thumbs up
await client.submitFeedback(42, 'down'); // thumbs down
```

## Full example — streaming chat UI (vanilla JS)

```ts
import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({chatbotKey: 'cbt_your_key_here'});
const sessionId = client.getOrCreateSessionId();

const messagesEl = document.getElementById('messages')!;
const inputEl    = document.getElementById('input')! as HTMLInputElement;
const sendBtn    = document.getElementById('send')!;

// Load history on mount
const session = await client.getSession(sessionId);
for (const msg of session.messages) {
  appendMessage(msg.role, msg.content);
}

sendBtn.addEventListener('click', async () => {
  const text = inputEl.value.trim();
  if (!text) return;

  inputEl.value = '';
  appendMessage('user', text);

  const aiEl = appendMessage('assistant', '');

  for await (const event of client.stream(sessionId, text)) {
    if (event.type === 'delta') {
      aiEl.textContent += event.content;
    } else if (event.type === 'error') {
      aiEl.textContent = 'Something went wrong. Please try again.';
    }
  }
});

function appendMessage(role: 'user' | 'assistant', content: string): HTMLElement {
  const el = document.createElement('div');
  el.className = `message message--${role}`;
  el.textContent = content;
  messagesEl.appendChild(el);
  messagesEl.scrollTop = messagesEl.scrollHeight;
  return el;
}
```

## Error handling

All methods throw a `ChatError` on non-2xx responses:

```ts
import {ChatClient, ChatError} from '@elaras/chat-sdk';

try {
  const result = await client.send(sessionId, 'Hello');
} catch (err) {
  if (err instanceof ChatError) {
    console.error(err.message);  // Human-readable message
    console.error(err.code);     // Error code (if provided)
    console.error(err.status);   // HTTP status code
  }
}
```
