Deploy

Embeddable chat widget

The widget is the fastest way to put an agent in front of users: a snippet you paste on your site, backed by a public key that's safe to ship in the browser.

Chat or voice

The widget runs in one mode, and you don't set it on the widget. It follows the agent's own Where it talks setting: an agent set to Voice gets a voice-call widget, where visitors talk to it and the transcript sits behind a toggle, and any other agent gets the text chat widget. This is the second place a voice agent takes calls, alongside a phone number, and it needs no number of its own: a voice and a widget key are enough.

Changing that setting rewrites widgets that are already live. Switch an agent from Chat to Voice and every embed on your site becomes a voice call the next time a visitor loads the page, with the text input gone. Switching back returns them to text chat. The dashboard warns you before you save.

A public, domain-restricted key

The widget runs in the browser, so it uses a dedicated widget key (prefix hania_) rather than your account key. The widget key is public by design and restricted to the websites you allow, with its own hourly rate limit. Create one per agent, naming it for where it'll live (for example, "Marketing site").

List the allowed websites separated by commas. Each entry can be a plain address like example.com or a full URL, and it also covers that site's subdomains, so example.com allows shop.example.com but never a look-alike such as example.com.evil.net. Leave the list empty, or enter *, to allow any site. You can rename a key, change its websites or change its rate limit at any time, and each key shows when it was created and when it was last used.

Never use your account hania_sk_ key in the widget or any client-side code; that key is a full-tenant secret for your backend only. The widget uses the public hania_ key.

Customize the look

Tune the widget's appearance and copy to match your site: theme colour, position and distance from the edge of the page (set separately for desktop and mobile), title, greeting, message box placeholder, avatar image, and whether to show the "Powered by Hania AI" line. Leave a text field empty to use the widget's default. The greeting shows when a visitor opens an empty chat, and the agent answers their first message. A live preview in the dashboard shows the result as you edit, closed or open, and as a voice call for a voice agent. Changes apply to the live widget, with no redeploy needed. On phones, the open chat fills the screen.

Let visitors attach images

Turn on Let visitors attach images to let visitors add pictures to their messages. The widget accepts PNG, JPEG, GIF and WebP, up to 10 MB each and up to 20 per visitor. The agent's own replies show images inline either way, and links to video or audio get a player.

Proactive messages

A proactive message is one the widget shows visitors on its own, as a card beside the bubble or by opening the chat. Use them to offer help on a pricing page, greet returning visitors, or catch someone who is about to leave. Each message has:

  • Where it shows. Every page, or only where your rules match. Rules look at the page address, the page title, whether the visit is new or returning, the visitor's language, and whether the visitor is known. Conditions in one set must all be true, and the message shows when any set matches. You can also list pages it must never show on, such as checkout.
  • When it shows. When the page loads, after a number of seconds on the page, after the visitor scrolls part of the way down, or when they are about to leave (desktop only). You can limit it to your business hours, or to outside them.
  • How often. Once per visitor, once per visit, or every time it matches.
  • How it shows. A card next to the bubble, or the chat opening on desktop. On phones it always shows as a card.
  • Status and priority. Only Live messages reach visitors; Draft and Paused ones don't. When several messages match, the one with the lowest priority number shows first.

Write {name} in a message to greet a verified visitor by name. When the name isn't known, it's left out along with the space before it, so "Hi {name}, need a hand?" reads "Hi, need a hand?". Each message counts how many visitors it was sent to, how many opened it by clicking the card, and how many replied.

Business hours

Set the days and times you're open on the widget's Business hours tab. A day can have more than one range, and a day with no hours counts as closed. The times are read in the agent's timezone, which you change in the agent's settings. Set hours before you limit a proactive message to them.

Get the embed snippet

Once you have an agent, a widget key, and your customization, grab the ready-to-paste embed snippet for that agent and key, and drop it into your site's HTML. You can manage keys, customization, and the embed code in the Widgets area of the dashboard, or over the Widgets API.

Advanced embedding

Add these attributes to the script tag to change how the widget loads:

  • data-view="limited" shows only the conversation, without the header and branding. The default is full.
  • data-mount="#chat" renders the widget inside that element on your page instead of the corner bubble. Proactive messages don't run there.
  • data-session="ephemeral" starts fresh every time and remembers nothing.

Your own code can control the widget through window.HaniaWidget: open() (which also puts the cursor in the message box), close() (which also ends a call), toggle(), sendMessage(text), endCall() and getCallState(). showMessage(text) shows a card with your own text, which isn't counted in the message numbers, and hideMessage() hides it. In a single-page app, call refresh() after a page change so the widget checks its proactive messages again.

The widget also announces what happens as events on window: hania:ready, hania:session, hania:error, hania:call-started, hania:call-ended, hania:proactive-shown (detail { id, message }), hania:proactive-opened and hania:proactive-dismissed (detail { id }). The id is null for a card from showMessage.

window.addEventListener("hania:proactive-opened", (e) => {
  console.log("Card opened", e.detail.id);
});
Restrict each widget key to the exact domains it should run on. If a key is ever misused elsewhere, the domain restriction and rate limit contain the blast radius, and you can revoke it any time.