Chat widget

Add an AI chat bubble to your website that talks to one of your agents — install, configure, and go live.

The chat widget puts one of your oyehello agents on your website as a floating chat launcher — a button in the corner that opens a chat window. A chat agent answers questions in text on any page you embed it on, and when it needs a human, one of your teammates can quietly take over from the console.

A chat agent is built the same way as a call agent — same flow builder, knowledge base, and tools — but it’s created on the Chat channel instead of Call. An agent belongs to one channel, chosen at creation and fixed thereafter; to serve both phone and website chat you create two agents. Nothing about your calling setup changes.

There are two halves to getting live, and this page covers both:

  1. In the console — create a chat agent and a key that locks the widget to your website.
  2. On your website — paste in the widget (one line for most sites, or a headless client if you want to build your own UI).

The one rule that ties this page together: the widget only works when three things line up — chat is turned on for your workspace, the agent is a chat agent, and your website’s address is on the key’s allowlist. Miss any one and the launcher simply won’t open. We’ll set up all three below.


Before you start

You need:

  • Chat available on your workspace. Chat is on by default for every workspace. An admin can turn it off for a specific workspace — if that’s the case, you won’t see the Chat controls in the console. If you expected chat and don’t see it, get in touch.
  • A chat agent. Chat is answered by an agent created on the Chat channel — the channel is chosen when you create the agent and can’t be changed later. If you don’t have one yet, create one and pick Chat; see Create an agent.

Step 1 — Create a chat agent

Chat is answered by an agent on the Chat channel. In the console go to Agents → New agent and choose Chat as the channel (templates ask for this too). Build it like any agent — write the flow, attach a knowledge base and tools, and publish.

The channel is fixed once the agent is created: a call agent can’t be converted to chat, or vice-versa. To offer both phone and website chat, create one agent of each.

While building a chat agent you can optionally set up:

  • Client tools — browser actions the agent can take on your page (go to a page, open a link). See Client tools below.
  • Knowledge base — attach one so the agent answers from your own content and shows its sources. See Knowledge base & sources.

Get the agent id. Once the agent exists, open its page in the console — the agent id (agt_…) is shown right under the agent’s name with a one-click copy button. You’ll paste it into the widget in Step 3.


Step 2 — Create a publishable key

The widget runs in your visitor’s browser, so it needs a key that’s safe to expose publicly. That’s a publishable key — it starts with ohk_pub_, can only open chat sessions (it can’t touch your account or the rest of the API), and is locked to the website addresses you list.

In the console go to Settings → API keys → Publishable keys and create a key. When you create it:

  • Add your website’s origin(s) to the allowlist — e.g. https://www.yoursite.com. Only pages served from an address on this list can open the widget; anyone who copies your key onto a different domain is refused.
  • Copy the key. You’ll paste it into the widget in the next step.

Why this is safe to put in your page’s HTML: a publishable key is designed to be public. Even if someone reads it, the origin lock means it only works from your site, and the chat scope means it can’t do anything except start a chat with the agent you enabled. It is not your secret API key — never put a secret (ohk_sk_… / dashboard) key in a web page.


Step 3 — Install the widget

Pick the option that matches your site. In every case, base-url is the oyehello API:

https://api.oyehello.ai

The drop-in web component (most sites)

Works in plain HTML, Astro, Vue, Svelte — anything. Add the script once and drop the tag anywhere on the page — the widget positions itself as a floating launcher in the bottom-right corner, so where the tag sits in your markup doesn’t matter:

<script type="module">import '@oyehello/chat';</script>

<oyehello-chat
  api-key="ohk_pub_…"
  agent-id="agt_…"
  base-url="https://api.oyehello.ai"
></oyehello-chat>

Grab the agent id from the agent’s page in the console (under its name, with a copy button). The widget ships with a working default UI — a floating launcher, a chat panel, markdown-formatted replies, file uploads, and smart auto-scroll — so this is genuinely all you need.

No build step? Use a script tag

If you don’t use a bundler, load it straight from a CDN:

<script src="https://unpkg.com/@oyehello/[email protected]"></script>
<oyehello-chat api-key="ohk_pub_…" agent-id="agt_…" base-url="https://api.oyehello.ai"></oyehello-chat>

Pin a specific version (@0.5.0 above) rather than the bare package name so your site keeps loading the exact widget you tested — an unpinned URL silently upgrades to whatever we publish next.

Astro (env-driven — how oyehello.ai embeds it)

In an Astro project, import the component in a client <script> and read the config from PUBLIC_-prefixed environment variables instead of hard-coding keys. This is exactly how the oyehello site embeds the widget:

---
// src/pages/support.astro
const API_KEY = import.meta.env.PUBLIC_CHAT_API_KEY;
const AGENT_ID = import.meta.env.PUBLIC_CHAT_AGENT_ID;
const BASE_URL = import.meta.env.PUBLIC_CHAT_BASE_URL ?? 'https://api.oyehello.ai';
---
<oyehello-chat api-key={API_KEY} agent-id={AGENT_ID} base-url={BASE_URL}></oyehello-chat>
<script>import '@oyehello/chat';</script>

Set the three PUBLIC_CHAT_* values in your host’s environment (e.g. Cloudflare Pages → Settings → Environment variables) and redeploy — Astro bakes PUBLIC_-prefixed vars into the static build at build time, so an env change needs a rebuild to take effect. Exposing the publishable key in the page is expected; the origin allowlist is what keeps it locked to your site.

React

The custom element works in React as-is. The tag must stay hyphenated (<oyehello-chat>) and attributes stay kebab-case:

import '@oyehello/chat';

export default function SupportChat() {
  return (
    <oyehello-chat
      api-key="ohk_pub_…"
      agent-id="agt_…"
      base-url="https://api.oyehello.ai"
    />
  );
}

TypeScript users add this ambient declaration once (e.g. in oyehello-chat.d.ts) so the tag type-checks:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'oyehello-chat': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
        & { 'api-key'?: string; 'agent-id'?: string; 'base-url'?: string; title?: string };
    }
  }
}
export {};

Headless — build your own UI

Want your own chat interface instead of the built-in one? Use the headless client. You get the same session, streaming, and tools; you own the pixels:

import { createChatClient } from '@oyehello/chat';

const chat = createChatClient({
  apiKey: 'ohk_pub_…',
  agentId: 'agt_…',
  baseUrl: 'https://api.oyehello.ai',
});

chat.on((e) => {
  if (e.type === 'messages') render(e.messages); // full message list on every change
});

await chat.start();               // opens the session
await chat.sendMessage('Hello');  // replies stream in, message-by-message

Theming

The default widget is deliberately plain so it fits in. Set your brand accent with one CSS variable, and change the header text with the title attribute:

<oyehello-chat
  api-key="ohk_pub_…" agent-id="agt_…" base-url="https://api.oyehello.ai"
  title="Ask us anything"
  style="--oc-accent:#e5484d"
></oyehello-chat>

Light and dark. By default the widget follows your page’s own light or dark theme, and updates live when your theme toggle changes. It reads a data-theme or data-mode attribute set to dark or light, a dark or light class on <html>, <body> or any parent of the widget, or the page’s color-scheme. If your page declares none of these, the visitor’s OS preference is used. To force one, set the theme attribute to light or dark.


Client tools — let the agent act on your page

By default the agent can only talk. Client tools let it do two things in the visitor’s browser while the chat is open:

  • navigate — take the visitor to a page on your site.
  • openUrl — open a link.

The widget runs these itself. There’s nothing to install or register in your page: a plain embed already works. A tool runs only when it’s enabled for the agent in the console, and the destination passes the agent’s navigate allowlist.

Turn them on. Open the chat agent’s settings in the console, go to Behaviour, and under Client tools tick the actions the agent may take. Under Navigate allowlist, add the pages or sites the agent may send visitors to (for example /pricing or https://example.com). Leave the allowlist empty to allow any.

Security. Destinations are checked against the allowlist on our servers before a tool call ever reaches the visitor’s browser, so a visitor can’t talk the agent into sending them somewhere you didn’t allow. Keep the allowlist tight.

Optional: handle navigation yourself. If you use a client-side router and want navigate to go through it instead of a full page load, you can register your own handler before you start the session. A handler you register takes priority over the built-in one:

const chat = createChatClient({ apiKey, agentId, baseUrl });

chat.registerTools({
  navigate: ({ path }) => router.push(path),
});

await chat.start();

On the web component it’s the same idea: document.querySelector('oyehello-chat').registerTools({ … }). Only navigate and openUrl exist. Any other tool name has no handler.


Knowledge base & sources

Attach a knowledge base to the agent and the chat answers from your own content instead of general knowledge. When it does, the widget shows small source chips under the answer, so visitors can see where a fact came from. Nothing to configure on the widget side — connect the knowledge base to the agent and it just appears.


File & image uploads

Visitors can attach files to a message — handy for “here’s a screenshot of the error” or “here’s my receipt.”

To turn uploads on, your workspace needs file storage configured (this is an operator/environment setup — see your deployment’s RECORDING_S3_* settings). Until that’s set up, the widget quietly hides uploads and text chat works as normal.

What the agent does with each type:

  • Images (PNG, JPEG, GIF, WebP) — the agent actually sees them and can answer about their contents.
  • Documents (PDF, TXT, CSV) — attached to the conversation and visible to your human teammates in the inbox, but the AI does not read their contents yet. (Reading document contents is a planned enhancement.)

Defaults you can adjust in configuration: up to 4 files per message, 10 MB each, in the types listed above.


Live human handoff & the inbox

Sometimes a visitor needs a person. Two things can trigger that: the agent’s flow reaches a handoff step, or a teammate simply decides to jump in.

Either way, the conversation shows up in the Chat inbox in the console. From there a teammate can:

  • Take over — the AI pauses, and the teammate chats with the visitor directly, in real time.
  • Hand back — the AI resumes where it left off.

The visitor just sees a smooth conversation; they don’t see the switch. Sessions that get abandoned mid-handoff are closed automatically after a couple of hours of silence, so nothing sits open forever.


Billing

Chat is billed from the same prepaid wallet as your calls: ₹2 per AI conversation, and ₹0 per message. Whether chat is available at all is a workspace setting (see Before you start above). You can watch usage and top up under Billing & wallet.


Security & privacy, in one place

  • The publishable key is safe in your page. It’s origin-locked and chat-scoped — it can’t be used from another site and can’t reach anything but the chat.
  • Each chat gets a short-lived session token behind the scenes; the widget renews it automatically. You don’t manage it.
  • The origin allowlist is the real lock. Keep it tight — list only the exact sites you embed on.
  • Client tools are limited to navigate and openUrl, and only to destinations on the agent’s allowlist (see the security note above).

Troubleshooting

What you see What it means Fix
The bubble shows an error about api-key, agent-id and base-url One of the three attributes is missing or empty Check all three are set on the tag
Chat won’t open; “origin not allowed” Your site’s address isn’t on the key’s allowlist Add the exact origin (scheme + host) in Settings → Publishable keys
Chat won’t open; “feature locked” (plan_feature_locked) Chat has been turned off for your workspace Contact us (or your admin) to enable it
Chat won’t open; agent refuses (chat_not_enabled) The agent isn’t a chat agent (it was created on the Call channel) Use an agent created on the Chat channel — the channel is set at creation and can’t be changed
Uploads don’t appear File storage isn’t configured for the workspace Ask your operator to set up attachment storage
A client tool never fires It isn’t enabled on the agent, or the destination isn’t on the agent’s navigate allowlist Tick the tool under Client tools in the agent’s settings and add the destination to the Navigate allowlist

Quick reference

Web component attributes

Attribute Required What it is
api-key yes Your publishable key (ohk_pub_…)
agent-id yes The agent to chat with (agt_…)
base-url yes https://api.oyehello.ai
title no Header text (defaults to the agent’s name / workspace brand name)
theme no auto (default — follows your page’s own light/dark theme, live as it changes: data-theme/data-mode set to dark or light, or a dark/light class on <html>, <body> or a parent of the widget; the visitor’s OS when your page declares none), light, or dark. Light/dark only; the accent comes from your workspace brand
teaser no Overrides the agent’s teaser text. Normally you set this on the chat agent in the console, not here
suggestions no Static fallback chips. Normally the agent generates flow-aware chips automatically — see below
privacy-url no Shows a “By chatting… Privacy Policy” footer linking here (e.g. https://oyehello.ai/chat-privacy)
--oc-accent (CSS var) no Force the accent color; otherwise it follows your workspace brand (default #096DD9)

Set from the console, not attributes

Three things the widget shows come from your workspace/agent automatically — you don’t pass them as attributes:

  • Accent + logo + name (theming) come from your workspace Brand (Account → General). The widget themes its launcher, header, and buttons to match.
  • The teaser (“Need a hand? Ask me anything.” by default) is a field on the chat agent — set it on the agent’s Chat card.
  • Quick-reply chips are generated from the agent’s flow: after each reply, the widget offers the current step’s likely next questions. No setup — write clear flow transition conditions and they become the chips. (The suggestions attribute is only a static fallback for agents without a flow.)

Headless client

Call Purpose
createChatClient({ apiKey, agentId, baseUrl }) Create a client
chat.registerTools({ … }) Optional: override how navigate / openUrl run (before start)
chat.on((e) => …) Subscribe to updates (e.type === 'messages')
chat.start() Open the session
chat.sendMessage(text) Send a visitor message; replies stream back