JavaScript SDK
Use the JavaScript SDK when you want to build a completely custom chat UI without the widget — your own design, your own layout, full control.
Setup
Add the SDK and block styles to your page:
<script src="https://ask-api.elaras.ai/sdk/sdk.js"></script> <link rel="stylesheet" href="https://ask-api.elaras.ai/sdk/blocks.css">
This exposes window.ElarasSDK with ChatClient, renderBlock, and renderBlocks.
Creating a client
const { ChatClient } = window.ElarasSDK const client = new ChatClient({ chatbotKey: 'cbt_your_key_here' })
Options
| Option | Type | Required | Description |
|---|---|---|---|
chatbotKey | string | Yes | Your public agent key (cbt_...) |
apiUrl | string | No | Override the API base URL. Defaults to https://api.elaras.ai |
Methods
getOrCreateSessionId()
Returns the current session UUID from localStorage, or generates a new one if none exists. Call this once when your chat component mounts.
const sessionId = client.getOrCreateSessionId() // e.g. "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
The session ID persists in localStorage across page reloads.
stream(sessionId, message)
Sends a message and yields streaming events as the AI responds.
for await (const event of client.stream(sessionId, 'What are your opening hours?')) { if (event.type === 'delta') { appendToken(event.content) } else if (event.type === 'done') { if (event.blocks?.length) { renderBlocks(messagesEl, event.blocks, (text) => client.stream(sessionId, text)) } } }
Event types:
| Event | Fields | Description |
|---|---|---|
delta | content: string | Next token chunk from the AI |
done | message_id: number, credits_used: number, blocks?: Block[] | Response complete. blocks is present when the agent returns structured UI components |
error | message: string, code?: string | An error occurred |
send(sessionId, message)
Sends a message and waits for the complete response (no streaming).
const result = await client.send(sessionId, 'What are your prices?') console.log(result.response)
Returns: { message_id, response, credits_used, blocks? }
getConfig()
Fetches the agent's public configuration — name, greeting, appearance settings.
const config = await client.getConfig() console.log(config.greeting_message) // "Hi! How can I help?" console.log(config.appearance?.primary_color) // "#00C4A7"
getSession(sessionId)
Fetches the session and its full message history.
const session = await client.getSession(sessionId) for (const msg of session.messages) { appendMessage(msg.role, msg.content) }
clearSession(sessionId)
Deletes all messages in the session on the server. The session UUID remains valid.
await client.clearSession(sessionId)
clearSessionId()
Removes the session UUID from localStorage so the next call generates a fresh one.
client.clearSessionId()
submitTriage(sessionId, answers)
Submits answers to pre-chat triage questions before the first message is sent.
await client.submitTriage(sessionId, [ { question_id: 'name', answer: 'Jordan' }, { question_id: 'email', answer: '[email protected]' }, ])
submitLead(sessionId, lead)
Associates an email address (and optional name) with the session.
await client.submitLead(sessionId, { email: '[email protected]', name: 'Jordan' })
submitFeedback(messageId, rating)
Records thumbs-up or thumbs-down feedback for an AI response.
await client.submitFeedback(42, 'up')
Full example
A complete working chat UI in a single HTML file — no build step, no npm. Copy it, swap in your agent key, and open it in a browser.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Chat</title> <link rel="stylesheet" href="https://ask-api.elaras.ai/sdk/blocks.css"> <script src="https://ask-api.elaras.ai/sdk/sdk.js"></script> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: system-ui, sans-serif; display: flex; flex-direction: column; height: 100vh; } #messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 8px; } .msg { max-width: 75%; padding: 10px 14px; border-radius: 16px; line-height: 1.5; } .msg--user { align-self: flex-end; background: #00C4A7; color: #fff; border-bottom-right-radius: 4px; } .msg--assistant { align-self: flex-start; background: #f0f0f0; color: #111; border-bottom-left-radius: 4px; } #form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid #e5e5e5; } #input { flex: 1; padding: 10px 14px; border: 1px solid #e5e5e5; border-radius: 8px; font-size: 14px; } #send { padding: 10px 20px; background: #00C4A7; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; } #send:disabled { opacity: 0.5; cursor: default; } </style> </head> <body> <div id="messages"></div> <form id="form"> <input id="input" type="text" placeholder="Ask something…" autocomplete="off"> <button id="send" type="submit">Send</button> </form> <script> const { ChatClient, renderBlocks } = window.ElarasSDK const CHATBOT_KEY = 'cbt_your_key_here' const client = new ChatClient({ chatbotKey: CHATBOT_KEY }) const sessionId = client.getOrCreateSessionId() const messagesEl = document.getElementById('messages') const inputEl = document.getElementById('input') const sendBtn = document.getElementById('send') const form = document.getElementById('form') function appendMessage(role, content) { const el = document.createElement('div') el.className = `msg msg--${role}` el.textContent = content messagesEl.appendChild(el) scrollToBottom() return el } function scrollToBottom() { messagesEl.scrollTop = messagesEl.scrollHeight } // Re-scroll when card images finish loading messagesEl.addEventListener('elaras:imageload', scrollToBottom) // Load history on mount const session = await client.getSession(sessionId) for (const msg of session.messages) { appendMessage(msg.role, msg.content) } form.addEventListener('submit', async (e) => { e.preventDefault() const text = inputEl.value.trim() if (!text) return inputEl.value = '' sendBtn.disabled = true appendMessage('user', text) const aiEl = appendMessage('assistant', '') for await (const event of client.stream(sessionId, text)) { if (event.type === 'delta') { aiEl.textContent += event.content scrollToBottom() } else if (event.type === 'done' && event.blocks?.length) { renderBlocks(messagesEl, event.blocks, (reply) => { inputEl.value = reply form.dispatchEvent(new Event('submit')) }) } else if (event.type === 'error') { aiEl.textContent = 'Something went wrong. Please try again.' } } sendBtn.disabled = false inputEl.focus() }) </script> </body> </html>
Swap cbt_your_key_here for your agent's public key (find it in the Embed tab). The sdk.js tag must appear before the inline <script> block — placing it at the top of <body> or in <head> with defer both work.
Error handling
SDK methods throw a standard Error on failure. The message property contains a human-readable description.
try { const result = await client.send(sessionId, 'Hello') } catch (err) { console.error(err.message) }
Block rendering
See Blocks for the full reference — all block types, specs, and theming.
