Live on your account

Add Yar to your site in one script tag

A streaming, source-cited support chat that answers from your own documents. No build step, no dependencies — copy four lines, and a chat bubble appears in the corner of your page.

01Quick start

This is the whole integration. Paste it before </body> on any page — a plain HTML site, WordPress, Webflow, whatever you're running.

html
<script src="http://87.107.105.247:8001/static/yar-chat.js"></script>
<script>
  YarChat.init({
    host: 'http://87.107.105.247:8001',
    kb_id: 'your-knowledge-base-id',
    publishable_key: 'pk_live_...',
  });
</script>
Nothing to download. The widget is hosted on our server and loaded directly by the browser — there's no package to install or file to keep updated. The two placeholders above are yours specifically; see the next section for where to find them.

02Get your knowledge base ID and publishable key

Everything here happens once per site. Two ways to do it — pick whichever fits your workflow. Both produce the same credentials.

Option A — the dashboard

Go to /dashboard/register/ and give your business a name. You'll get a secret key (starts with sk_live_) — copy it somewhere safe now, it's shown exactly once and is your login for the dashboard. Log in, create a knowledge base, and upload whatever you want the assistant to answer from (PDF, DOCX, HTML, TXT). Open the knowledge base and copy its ID out of the address bar — the UUID right after /knowledge-bases/.

Option B — pure API, no browser required

Everything above has a JSON equivalent, so you can wire up a new customer's account entirely from a script or your own backend.

1. Register a tenant — this single call creates your account and hands back your secret key. It's shown only in this response, so save it immediately.

bash
curl -X POST http://87.107.105.247:8001/api/v1/tenants/ \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "slug": "acme-corp"}'
json
{
  "id": "3f9a1c...",
  "name": "Acme Corp",
  "slug": "acme-corp",
  "is_active": true,
  "created_at": "2026-07-08T12:00:00Z",
  "secret_key": "sk_live_..."
}

2. Create a knowledge base — authenticate with the secret key as a Bearer token from here on:

bash
curl -X POST http://87.107.105.247:8001/api/v1/knowledge-bases/ \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "Support Docs"}'

The response's id is your kb_id — save it for the snippet below.

3. Upload a document to that knowledge base (repeat per file):

bash
curl -X POST http://87.107.105.247:8001/api/v1/knowledge-bases/kb_id/documents/ \
  -H "Authorization: Bearer sk_live_..." \
  -F "file=@handbook.pdf"

Upload returns 202 immediately; the document is chunked, embedded, and indexed in the background. Poll GET /api/v1/knowledge-bases/{kb_id}/documents/{doc_id}/ until its status field reads indexed.

4. Create a publishable key — safe to embed in public HTML, it can only open a chat session:

bash
curl -X POST http://87.107.105.247:8001/api/v1/tenants/tenant_id/api-keys/ \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"tier": "publishable"}'

The response's key field is your pk_live_... — drop it straight into the widget snippet.

Every management call requires your secret key, scoped to your own tenant. Authorization: Bearer sk_live_... is required on every tenant, API key, knowledge base, and document endpoint except the initial registration call — and a secret key only ever works against the tenant it was issued for.

03Add the widget

Same snippet as the quick start, with your real values filled in. That's the entire integration — the bubble, panel, streaming, and error handling are all built in.

html
<script src="http://87.107.105.247:8001/static/yar-chat.js"></script>
<script>
  YarChat.init({
    host: 'http://87.107.105.247:8001',
    kb_id: '3f9a1c...',
    publishable_key: 'pk_live_9kD...',
    title: 'Ask us anything',
  });
</script>

Using React, Vue, or a bundler instead of a plain script tag? See the notes section for the ESM import.

Configuration options

OptionDefaultDescription
host— requiredYour Yar server origin.
kb_id— requiredKnowledge base the widget queries.
publishable_key— requiredYour pk_live_* key.
title"Chat"Header text in the widget panel.
placeholder"Ask a question..."Input box placeholder text.
position"bottom-right""bottom-right" or "bottom-left".
theme{}CSS variable overrides — see below.

Theming

Pass a theme object to match your brand. Anything you don't set keeps its default.

--yar-primary --yar-bg --yar-text --yar-border
js
YarChat.init({
  host: '...', kb_id: '...', publishable_key: '...',
  theme: {
    '--yar-primary': '#16a34a',   // bubble, header, send button
    '--yar-bg':      '#ffffff',              // panel background
    '--yar-text':    '#111827',              // message text
    '--yar-radius':  '12px',                 // corner rounding
    '--yar-width':   '380px',                // panel width
  },
});

The panel automatically goes full-screen below 440px viewport width, so mobile doesn't need separate handling.

Controlling the widget

YarChat.init() returns a controller, in case you want a custom "chat with us" button instead of relying on the built-in bubble:

js
const chat = YarChat.init({ /* ... */ });

chat.open();     // open the panel
chat.close();    // close the panel
chat.destroy();  // disconnect and remove from the page

What visitors see

SituationShown in the panel
Connecting"Connecting…", input disabled
ConnectedStatus clears, input enabled
Brief network drop"Reconnecting… (1/3)" with backoff, then (2/3), (3/3)
Reconnect attempts used up"Could not connect. Please refresh."
Wrong or revoked key"Invalid API key."
A secret key was used by mistake"Publishable key required."
Assistant temporarily unavailableInline error, input re-enabled so the visitor can retry

Notes

Using a bundler (React, Vue, Next.js)

js
import YarChat from '@yar/chat-widget'

useEffect(() => {
  const chat = YarChat.init({ host: '...', kb_id: '...', publishable_key: '...' })
  return () => chat.destroy()
}, [])
Currently HTTP, not HTTPS. The widget is served from a staging address (87.107.105.247:8001) while a permanent domain is set up. It works everywhere today, but browsers will eventually want a matching HTTPS origin if your own site is served over HTTPS — ask us if that's blocking you and we'll move this up.