Elaras/

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

OptionTypeRequiredDescription
chatbotKeystringYesYour public agent key (cbt_...)
apiUrlstringNoOverride 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:

EventFieldsDescription
deltacontent: stringNext token chunk from the AI
donemessage_id: number, credits_used: number, blocks?: Block[]Response complete. blocks is present when the agent returns structured UI components
errormessage: string, code?: stringAn 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.