Skip to main content

Website Widgets

Embed your voice agent on any website so visitors can start a voice conversation directly from the browser. The Widgets tab provides embed codes, customization options, and domain security settings.

Looking for the callback widget?

The Callback Widget works very differently from the widgets on this page — instead of starting a browser voice call, it collects the visitor's phone number and has your agent dial them back. See the dedicated Callback Widget page.

Widget Types

Hanc.AI offers four in-browser widget types, plus a separate Callback Widget for phone callbacks:

WidgetTag NameDescriptionBest For
Floating Widgethanc-ai-floating-callOrb button that floats over your pageAlways-visible call-to-action
Pill Widgethanc-ai-pill-callCompact pill-shaped button placed inline in your contentMinimal footprint inside an existing layout
Pill Floating Widgethanc-ai-pill-floating-callSame compact pill shape as Pill, but floats with the page like the Floating widgetWhen you want a pill aesthetic that follows the visitor as they scroll
Inline Widgethanc-ai-inline-callFull-size call button embedded in page contentDedicated "Talk to Us" sections
Callback Widgethanc-ai-callbackPhone-number form; agent calls the visitor backLead-gen pages, high-intent landing pages — see Callback Widget

Common Attributes

All widget types support these core attributes:

AttributeRequiredDescriptionDefault
agent-idYesYour agent's unique identifier
voice-service-urlNoOverride the voice service URLAuto-detected
api-base-urlNoOverride the API base URLAuto-detected

Display Attributes

AttributeDescriptionValuesDefault
positionWidget position on the pagebottom-right, bottom-left, top-right, top-left, staticbottom-right
sizeWidget size in pixelsNumber120
themeColor theme nameSee Color Themesdefault

Button Text Attributes

AttributeDescriptionDefault
button-start-textText shown on the idle button"Call"
button-connecting-textText shown while connecting"Connecting..."
button-end-textText shown during an active call

Terms Attributes

AttributeDescriptionDefault
terms-enabledEnable consent dialog before callfalse
terms-contentMarkdown-formatted consent text""
terms-urlLink to your Terms & Conditions page"https://hanc.ai/terms"
privacy-urlLink to your Privacy Policy page"https://hanc.ai/privacy"
info

Terms attributes set on the HTML element are overridden by the agent's widget settings fetched from the API, unless skip-fetch is set to true.

Sound Attributes

AttributeDescriptionDefault
sound-enabledEnable call start/end soundstrue
sound-volumeSound effect volume0.25
sound-presetSound preset identifier"1"

Color Themes

Customize widget appearance with 11 built-in color themes:

ThemeValue
Defaultdefault
Purplepurple
Blueblue
Cyancyan
Emeraldemerald
Amberamber
Tangerinetangerine
Roserose
Emberember
Blackblack
Whitewhite

Each theme has both dark and light variants. Set the theme via the theme attribute in the embed code, or configure it in the agent's widget settings.


Embed Examples

Floating Widget

<hanc-ai-floating-call agent-id="YOUR_AGENT_ID"></hanc-ai-floating-call>
<script src="https://unpkg.com/hanc-webrtc-widgets" async type="text/javascript"></script>

Floating Widget with Theme and Position

<hanc-ai-floating-call
agent-id="YOUR_AGENT_ID"
theme="emerald"
position="bottom-left"
size="140"
></hanc-ai-floating-call>
<script src="https://unpkg.com/hanc-webrtc-widgets" async type="text/javascript"></script>

Pill Widget

<hanc-ai-pill-call agent-id="YOUR_AGENT_ID"></hanc-ai-pill-call>
<script src="https://unpkg.com/hanc-webrtc-widgets" async type="text/javascript"></script>

Inline Widget

<hanc-ai-inline-call agent-id="YOUR_AGENT_ID"></hanc-ai-inline-call>
<script src="https://unpkg.com/hanc-webrtc-widgets" async type="text/javascript"></script>
Pinning a widget version

The script URL above always loads the latest released widget — your site picks up improvements automatically, and @latest is the default when no version is specified. If you need to lock to a fixed release, pin explicitly by appending the version you want, e.g. https://unpkg.com/hanc-webrtc-widgets@X.Y.Z.


Widget Events

Widgets emit events that you can listen for in JavaScript:

EventDescription
status-changedFired when the call status changes
connectingCall is being established
connectedCall is active
idleNo active call
errorAn error occurred
audio-trackRemote audio track received (for visualization)
local-audio-trackLocal microphone audio track (for visualization)
microphone-enabledMicrophone was enabled
microphone-disabledMicrophone was disabled
call-startFired when a call starts successfully
call-endFired when the call ends

Example: Listening for Events

const widget = document.querySelector('hanc-ai-floating-call');

widget.addEventListener('call-start', () => {
console.log('Call started');
});

widget.addEventListener('call-end', () => {
console.log('Call ended');
});

Letting the Agent Open Pages

During a browser call the agent can ask your site to open a page — "let me show you the pricing" — and the visitor sees it happen while they keep talking.

Your page stays in charge. The agent sends a request; your code decides what it means. Opening a URL, switching a tab, scrolling to a section and expanding an accordion are all valid answers.

This takes three steps, and none of them work alone.

Step 1 — Tell the agent which pages exist

The agent cannot see your site map. It only ever asks for a path you gave it, so list them in the agent's prompt or knowledge base:

Pages on our site:
/pricing — plans and prices
/contact — contact form and phone number
/product/crm — the CRM

Skip this step and the agent has nothing to ask for, so it never tries.

Step 2 — Handle the request on your page

Add this once, anywhere after the widget script. The event travels up through the page, so document is a fine place to listen:

<script>
document.addEventListener('agent-command', (event) => {
const { type, payload } = event.detail;

if (type === 'navigate') {
// Single-page app: route without reloading — the call keeps running.
router.push(payload.path);

// Classic site: open a second tab, so this one (and the call) survives.
// window.open(payload.path, '_blank');

event.preventDefault(); // ← tells the agent you handled it
}
});
</script>
A full page load ends the call

The call lives in this page. window.location.href = … unloads the document and the conversation goes with it — the visitor is cut off mid-sentence. Route client-side if you have a router, or open the page in a new tab. There is no reconnect: nothing survives a reload.

preventDefault() is not optional

It is the only way to say "I handled it". Leave it out and the agent is told the site does not support navigation: it stops trying for the rest of the call and falls back to describing where to click. Nothing appears in the browser console — the page simply looks like it ignored the request, because it did.

Step 3 — Try it

Call your agent from the site and ask for a page by name. Two things should happen: the page opens, and the agent says something like "here are the prices" rather than "you can find them in the menu".


Answering the agent with data

Some commands are questions rather than instructions. They arrive the same way, but you reply with respond():

CommandThe agent is askingYou reply with
navigate"open this path"nothing — just preventDefault()
page_context"what is the visitor looking at?"anything useful: path, title, product
cart_state"what is in their basket?"items, totals, currency
<script>
document.addEventListener('agent-command', (event) => {
const { type, respond } = event.detail;

if (type === 'page_context') {
event.preventDefault();
respond({ path: location.pathname, title: document.title });
}
});
</script>

You have about a second to answer after preventDefault(), so an await is fine but a slow API call is not. Answer with what you already have.


What the agent may and may not ask for

  • Paths on your own site only. A path must start with /. Anything that could leave your domain — //evil.com, https://…, backslashes — is refused before it reaches your page. An agent cannot send your visitors somewhere else.
  • Browser calls only. There is no page to open on a phone call, so these commands do not exist there.
  • One refusal is enough. If your page does not confirm the first request, the agent stops asking for the rest of the call. It will not keep trying, and — importantly — it will not tell the visitor it opened something it did not.
Nothing happens?

Log every command before you filter it: document.addEventListener('agent-command', e => console.log(e.detail)). If you see navigate in the console, the agent is doing its part and the missing piece is preventDefault() or your own handler. If you see nothing, the agent was never told the path exists — go back to step 1.


Technical Requirements

Widgets require the visitor's browser to support:

  • WebGL 2.0 — for rendering
  • Web Audio API — for audio processing
  • WebRTC — for real-time voice communication

All modern browsers (Chrome, Firefox, Safari, Edge) support these technologies.


Domain Restrictions

Control which websites can embed your agent widget.

Always Allowed Domains

The following domains are always allowed regardless of configuration:

  • hanc.ai (and subdomains)
  • hanc.me (and subdomains)
  • localhost

Allow All Domains

By default, your widget can be embedded on any website. Toggle "Allow all domains" in widget settings to restrict this.

Restrict to Specific Domains

When restricted, add each domain that should be allowed:

  • Enter domain names without https:// (e.g., example.com)
  • Subdomains need separate entries (e.g., www.example.com, shop.example.com)
  • Ports can be specified (e.g., localhost:3000)
  • Maximum 50 domains can be whitelisted
Security

For production agents, restrict widgets to your own domains to prevent unauthorized embedding.


Terms & Conditions

Enable a consent dialog before callers can start a conversation.

Configuration

SettingDescription
Enable TermsToggle terms dialog on/off
Terms ContentMarkdown-formatted consent text shown to users (max 5,000 characters)
Terms URLLink to your full Terms & Conditions page
Privacy URLLink to your Privacy Policy page

When enabled:

  • Users see a consent dialog before starting a call
  • They must click "Agree" to proceed
  • Consent is stored locally in the browser
  • Reset Consent button clears stored consent for testing

Content Formatting

Terms content supports Markdown formatting:

  • Use #### for headings
  • Use **bold** for emphasis
  • Use line breaks for readability