arrow_backAll docs

Embed in your own design

Put the chatbot inside your own UI with the inline embed or headless SDK.

schedule6 min read

Not every site wants a floating chat bubble. If you'd rather place the chatbot insideyour own layout — a hero section, a support page, a sidebar you designed — you have two options, from quickest to most flexible.

warning
Heads upBefore you start: your chatbot must be set to Public, and your website's domain must be added to the chatbot's Allowed Domains in Settings. Requests from any other domain are blocked for security.

Option 1 — Inline embed (no code)

The fastest path: drop the chat straight into a container with a plain <iframe>. You control the size, placement, and everything around it; the chat UI (colors, name, welcome message) stays configured from your dashboard. Works on any site — HTML, WordPress, Shopify, Webflow, React.

html
<iframe
  src="https://nivichat.in/widget/YOUR_CHATBOT_ID"
  style="width:100%;height:600px;border:0;border-radius:16px"
  title="Chat"
></iframe>

Size the iframe however you like — it fills whatever box you give it.

Option 2 — Headless SDK (full design control)

Want to build the entire chat experience in your own design system — your bubbles, your fonts, your layout? Use the headless SDK. It handles sessions and streaming; you render the UI.

Quick start

  1. 1

    Add the SDK script

    Drop this once on your page (ideally before your own script):
    html
    <script src="https://nivichat.in/sdk/nivi-chat.js"></script>
  2. 2

    Create a bot instance

    Pass your chatbot ID (find it in your dashboard):
    javascript
    const bot = NiviChat.create({
      chatbotId: 'YOUR_CHATBOT_ID',
    });
  3. 3

    Send a message and stream the reply

    Tokens arrive as they're generated, so you can render a live typing effect:
    javascript
    bot.sendMessage('What are your business hours?', {
      onToken: (chunk, full) => {
        // 'full' is the whole reply so far — render it live
        replyEl.textContent = full;
      },
      onDone:  (full) => console.log('Finished:', full),
      onError: (err) => console.error(err),
    });

A complete minimal example

Copy this into an .html file, set your chatbot ID, and open it — a working custom chat:

html
<!doctype html>
<div id="log" style="font-family:sans-serif"></div>
<input id="msg" placeholder="Ask something…" style="width:100%;padding:10px" />

<script src="https://nivichat.in/sdk/nivi-chat.js"></script>
<script>
  const bot = NiviChat.create({ chatbotId: 'YOUR_CHATBOT_ID' });
  const log = document.getElementById('log');
  const input = document.getElementById('msg');

  input.addEventListener('keydown', (e) => {
    if (e.key !== 'Enter' || !input.value.trim()) return;
    const text = input.value.trim();
    input.value = '';
    addLine('You', text);
    const reply = addLine('Bot', '');
    bot.sendMessage(text, {
      onToken: (_chunk, full) => { reply.textContent = full; },
      onError: (err) => { reply.textContent = 'Error: ' + err.message; },
    });
  });

  function addLine(who, text) {
    const p = document.createElement('p');
    p.innerHTML = '<strong>' + who + ':</strong> ';
    const span = document.createElement('span');
    span.textContent = text;
    p.appendChild(span);
    log.appendChild(p);
    return span;
  }
</script>

SDK reference

  • NiviChat.create({ chatbotId }) — create a bot instance. Optional apiBase and sessionId.
  • bot.getConfig() — Promise of the public config (name, colors, welcome message).
  • bot.sendMessage(text, handlers) — stream a reply. Handlers: onToken(chunk, full), onMetadata(data), onDone(full), onError(err). Returns { abort() }.
  • bot.getHistory() — Promise of prior messages for the current session (handy after a page reload).
  • bot.resetSession() — start a fresh conversation.

REST API (any language)

Prefer to call the API directly — from a server, mobile app, or another language? The SDK is a thin wrapper over three public endpoints:

  • GET /api/widget/{chatbotId}/config — public chatbot config.
  • POST /api/widget/{chatbotId}/chat — body { message, sessionId }; streams the reply as Server-Sent Events.
  • GET /api/widget/{chatbotId}/messages/{sessionId} — message history for a session.

The chat endpoint streams SSE frames — each a data: line — ending with [DONE]:

text
data: {"type":"token","data":"Our hours "}
data: {"type":"token","data":"are 9-5, Mon-Fri."}
data: {"type":"metadata","data":{"sources":[ ... ]}}
data: [DONE]
info
NoteSessions: keep a stable sessionId per visitor so the conversation has memory. The SDK stores one in localStorage automatically; if you call the API directly, generate one per visitor and reuse it.

Frequently asked questions

Do I still need to use your widget script?

No. With the headless SDK (or the REST API) you build your own chat UI entirely — the floating widget script is optional and separate.

Why am I getting a CORS or “domain not allowed” error?

Your website’s domain must be added to the chatbot’s Allowed Domains in Settings, and the chatbot must be Public. Add your exact domain, then reload.

Does the headless integration still capture leads?

Lead capture is handled by the bot’s conversation logic. The inline embed keeps the built-in lead flow; with a fully custom UI you control the conversation, so you’d collect and submit lead details yourself.

Can I call the API from a backend or mobile app?

Yes. The same three endpoints work from any client. Send a stable sessionId per user and read the streamed Server-Sent Events for the reply.