Skip to content
Docs

Search the docs

Find a page or a section

Website

Customize the website widget

Attributes, colours, JavaScript methods and events for the uare.ai chat widget, plus React, Next.js, iframe and Content Security Policy setup.

View as Markdown

The widget is one script that defines a <uare-chat> HTML element. You can configure it two ways:

  • On the script tag, with data- attributes. The script then adds a chat bubble to the page by itself:

    <script async src="https://app.uare.ai/embed/v1.js" data-handle="your-handle" data-position="bottom-left"></script>
    
  • On a <uare-chat> element you place yourself, which is how you put the chat inside your layout. Load the script once per page:

    <script async src="https://app.uare.ai/embed/v1.js"></script>
    
    <uare-chat handle="your-handle" mode="inline" theme="light" style="height: 640px"></uare-chat>
    

Your website must be on your AI's list of allowed websites, either way. The AI's owner adds it, in their Settings on uare.ai: see Allow your website.

Attributes

Attribute Values Default
handle Your AI's handle, from your public profile's address. Required.
mode bubble: a button in the corner that opens the chat. inline: the chat fills the element, which you size. bubble
theme auto follows the visitor's light or dark setting, or force light or dark. auto
accent-color Any CSS colour, for the bubble, the send button and the visitor's messages. The text on it turns black or white to stay readable. When your AI has an avatar, the avatar fills the bubble, so the colour shows only on the send button and the visitor's messages. Near-black, or near-white in dark mode
position bottom-right or bottom-left, for the bubble. bottom-right
greeting The line shown before the first message. Your AI's bio
placeholder The message box's placeholder. Message <name>…
open Present to start with the bubble open. On the element, chat.open = true or false opens or closes the bubble, and chat.open() still works: see JavaScript. Closed
lang The visitor's language, as a tag such as fr or es. It's set on the chat for screen readers and kept with the conversation. Your AI picks the language of its replies itself, and the widget's own labels stay in English: use greeting and placeholder for the words visitors read first. en

On the script tag, add data- to each name: data-accent-color="#7c3aed". You can change attributes on the element at any time and it updates.

Colours and fonts

The widget lives in its own shadow DOM, so your site's CSS doesn't leak into it. To restyle it, set these CSS variables on uare-chat:

CSS
uare-chat {
  --uare-accent: #7c3aed;     /* bubble (when your AI has no avatar), send button, visitor messages */
  --uare-accent-fg: #ffffff;  /* text on the accent */
  --uare-font: "Inter", system-ui, sans-serif;  /* defaults to your page's font */
  --uare-radius: 20px;        /* corners of the chat panel */
  --uare-bg: #ffffff;         /* panel background */
  --uare-fg: #18181b;         /* text */
  --uare-surface: #f4f4f5;    /* your AI's messages */
  --uare-muted: #6b6b72;      /* secondary text */
  --uare-border: #e4e4e7;     /* lines and outlines */
}

Variables you set apply in both light and dark mode. Leave one unset to keep the widget's default for the visitor's theme.

JavaScript

Methods on the element:

Method What it does
open() Opens the bubble. In inline mode, focuses the message box.
close() Closes the bubble.
toggle() Opens or closes the bubble.
send(text) Sends text as the visitor's message. Returns a promise that resolves when the reply has finished, and rejects when the message isn't sent or the reply fails.
reset() Starts a new conversation.

open is also a property that takes a boolean, the way frameworks such as React 19 set it: chat.open = true opens the bubble and adds the open attribute, chat.open = false closes it and removes the attribute. Reading chat.open still gives the method.

When send() doesn't send, or the reply fails, its promise rejects with an Error whose code says why:

code Why
not_ready Your AI hasn't loaded yet, or couldn't load. Call send() after uare:ready.
turn_in_progress A reply is still being written. Send the next message once the previous send() has settled.
invalid_request The text is empty.
message_limit_reached The conversation's free messages are used up. The error's continue_url is your AI's page on uare.ai, and uare:limit fires too.
Any other The reply failed. code and message are the ones uare:error reports, such as chat_unavailable.

If the visitor stops the reply, or reset() starts a new conversation while it's streaming, the promise resolves.

Events, which bubble up to document. Each one's detail is described here:

Event detail
uare:ready { ai: { handle, name, avatar_url, bio, profile_url } } when your AI has loaded: once per load, so again only if you change handle or api-base
uare:open, uare:close {}
uare:message { role: "user" | "assistant", text } for each finished message
uare:limit { limit, continue_url } when the conversation's free messages are used up
uare:error { code, message } when the widget can't load or a reply fails

For example, open the chat from your own button and send a first question. This works with the one-line snippet, which adds <uare-chat> to the page only once its script has loaded, and with an element you place yourself:

HTML
<button id="ask">Ask about pricing</button>

<script>
  document.getElementById("ask").addEventListener("click", () => {
    // Look the element up when it's needed: with the one-line snippet,
    // it isn't on the page yet while this script runs.
    const chat = document.querySelector("uare-chat");
    chat?.send("How does your pricing work?").catch((error) => {
      console.warn(`Not sent (${error.code}): ${error.message}`);
    });
  });

  // The widget's events bubble up to document, so listen there.
  document.addEventListener("uare:message", (event) => {
    console.log(event.detail.role, event.detail.text);
  });
</script>

send() opens the bubble if it's closed. Call it after uare:ready: before your AI has loaded, it rejects with not_ready and sends nothing.

React and Next.js

React 19 renders custom elements directly. Load the script once with next/script, then use the element like any other:

"use client";

import Script from "next/script";
import { useEffect, useRef } from "react";

export function AiChat() {
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    const chat = ref.current;
    if (!chat) return;
    const onMessage = (event: Event) => {
      const { role, text } = (event as CustomEvent<{ role: string; text: string }>).detail;
      console.log(role, text);
    };
    chat.addEventListener("uare:message", onMessage);
    return () => chat.removeEventListener("uare:message", onMessage);
  }, []);

  return (
    <>
      <Script src="https://app.uare.ai/embed/v1.js" strategy="afterInteractive" />
      <uare-chat ref={ref} handle="your-handle" mode="inline" style={{ height: 640 }} />
    </>
  );
}

In JSX, open is a boolean: React 19 sets it on the element as a property, which opens or closes the bubble. For the methods, type your ref as useRef<UareChatElement>(null).

For a chat you design yourself, use the public API with the AI SDK instead.

Embed with an iframe

Some site builders and platforms only accept an iframe. uare.ai's own pages refuse to be framed by your site, so host a small chat page on a website you allowed, and frame that page wherever you need the chat:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      html, body { height: 100%; margin: 0; font-family: system-ui, sans-serif; }
      uare-chat { display: block; height: 100%; }
    </style>
  </head>
  <body>
    <script async src="https://app.uare.ai/embed/v1.js"></script>
    <uare-chat handle="your-handle" mode="inline"></uare-chat>
  </body>
</html>

The widget uses the page's font, so give chat.html the font you want. The website that has to be on your list is the one serving chat.html. The page holding the iframe can be on any site, because the chat talks to uare.ai from inside the frame. Browsers keep an iframe's storage separate for each website that frames it, so the conversation follows visitors from page to page on one website, and another website framing the same chat.html starts a conversation of its own.

Content Security Policy

If your site sends a Content-Security-Policy header, allow uare.ai to serve the script and answer the chat:

HTTP
Content-Security-Policy: script-src 'self' https://app.uare.ai; connect-src 'self' https://app.uare.ai; img-src 'self' https:

img-src needs to cover your AI's avatar. https: allows it wherever it's hosted. The widget's styles need nothing: they're applied from the script, so style-src doesn't have to allow inline styles.

Privacy

  • The widget sends no cookies and sets none. The conversation lives in your site's localStorage, under keys starting with uare-chat:, and leaves when visitors start a new chat or it expires.
  • Messages go to uare.ai and your AI answers them in public mode, as on your public profile. uare.ai sees the visitor's IP address, which it uses for rate limits and visitor counts.
  • Mention uare.ai in your privacy policy as a service that processes the chat messages visitors send.

Versions

/embed/v1.js stays compatible: updates add features without breaking the attributes, methods and events above. A breaking change would ship as /embed/v2.js.