Chat widget
Add an AI support chatbot to any website or documentation site with an embed snippet and published knowledge-base articles.
The answerLoops chat widget adds a support chatbot to any website or documentation site that accepts custom JavaScript. Visitors ask questions about your community, business, or product and get answers from your published knowledge-base articles, without creating an account.
Availability
The widget is included on every hosted plan and on self-hosted installs. The Standard plan shows a "Powered by answerLoops" line; Pro and Enterprise can remove it and also capture unanswered widget questions in the Review queue. Each widget answer counts toward your plan's monthly deflection allowance. See Billing plans.
How it works
Your website
answerLoops
What visitors get
The widget answers from published knowledge-base articles only. Unlike your connected channels, it does not draw on past resolved tickets. Those are written for the one person who raised them and often contain account details or internal notes, and a widget visitor is anonymous.
Thin knowledge, thin answers
A workspace with an empty knowledge base gets thin widget answers. Promoting a few resolved tickets into the knowledge base is what makes the widget useful, and it is the same step that generalises an answer so it is safe for anyone to read.
Set it up
Allow your domain
Go to Settings → Widget and add your website or documentation domain under Allowed domains, then select Save domains. See Restricting where the widget works.
What you should see: the domain listed under Allowed domains. Until at least one domain is listed, the widget will not load on any site.
Copy the embed snippet
In the same Widget tab, copy the embed snippet. It looks like this:
<script src="https://your-instance.example.com/widget.js" data-widget-id="..."></script>Paste it into your site
Paste it into your site's HTML before the closing </body> tag, or follow the steps for your platform below.
What you should see: a chat bubble at the bottom right of pages where you installed the snippet. Visitors select it to open the chat panel.
Preview and test
Select Preview widget in Settings to try it without any extra configuration, then ask a question your articles cover. Open Knowledge Base → Knowledge coverage (also linked from Settings → Widget) to see exactly which articles the widget can answer from.
What you should see: an answer drawn from your articles. If the panel instead says the widget is not enabled for a domain, add that domain under Allowed domains.
Adding it by platform
Where you paste the snippet depends on how your site is built. Find your platform below.
Settings → Custom Code → add code → paste the snippet → set it to load on all pages, placement Body - end.
Whichever platform you use, the rule is the same: paste into the one file or field that wraps every page (a layout, an app shell, a footer-code field) — never a single page's content, or the widget only loads there.
What you can customize
| Setting | Where | Notes |
|---|---|---|
| Branding | Settings → Widget | Standard shows the answerLoops logo and a "Powered by answerLoops" line. Pro and Enterprise can remove the answerLoops branding; Settings → Widget shows an upgrade option when your plan does not include it. Self-hosted installs have it unlocked. |
| Allowed domains | Settings → Widget | The domains the widget may load on. Subdomains are included. |
| Embed token | Settings → Widget | Issued per workspace and expires after 90 days; Regenerate token issues a new one. |
| Public name | Settings → Widget | An optional stable name for the snippet, so regenerating the token never breaks a page. See Rotating the token. |
| Ask for an email | Settings → Widget | When the widget collects a visitor's email address: only after an unanswered question (default), before the conversation starts, or never. |
| What it knows | Knowledge Base | Publish or unpublish articles and sources. The widget only answers from published articles. |
| Contact and link cards | Your articles | Cards show links and contact details only when they are written in your articles. There is nothing to configure. |
The chat bubble sits at the bottom right of the page, and the answer language follows the visitor's language. Neither is configurable.
How the snippet gets its display settings
When a page loads, the snippet asks your answerLoops instance how this workspace wants the widget to look (window size and bubble color) and which widget token is current. The answer contains display settings and the widget token only, nothing else about your workspace. It is cached for about a minute, so a change reaches pages shortly after you save it. Which settings a workspace gets always follows its plan and is decided on the server, never by what the snippet says. Until you choose something the widget looks exactly as it did before, and if the lookup is slow or fails the snippet shows that default look after two seconds, so existing installs keep working without re-pasting anything.
Restricting where the widget works
The data-widget-id value is an embed token (or a public name, which resolves to one), and it is deliberately public: it ships in the HTML of every page the widget renders on. Because anyone can read it, Settings → Widget → Allowed domains is how you control where the widget works. List the domains you embed on, one per line:
example.com
docs.example.comSubdomains of a listed domain are included, so example.com also covers support.example.com. Ports are ignored. Embeds on any other domain show a short message explaining that the widget is not enabled there, rather than failing silently.
The widget will not load until you list a domain
The widget will not load anywhere until you list at least one domain. Your own answerLoops domain is always permitted, so the Preview widget link in Settings works without any configuration.
If the panel says it could not confirm which site it is embedded on, the page is blocking referrer information; loading the page over HTTPS usually resolves it.
Only workspace owners and admins can change the allowed domains or regenerate the token. Members can see the embed snippet but not alter where it works. Usage limits apply independently of the allowlist.
Documentation sites
If your docs run on a platform that executes custom JavaScript on every page — Mintlify, Docusaurus, and most others do — you can mount the widget there without editing templates. Drop a small script that injects the snippet, and add the docs domain to your allowed domains.
This is usually the highest-value place to put it: docs visitors are anonymous and arrive with support-shaped questions, which is exactly what the knowledge base answers.
On platforms with no build step, the embed token ends up committed to whatever repository holds your docs. The token is a public identifier rather than a secret, but rotating it then requires a commit.
Lead capture
Settings → Widget → Ask for an email controls whether, and when, the widget asks a visitor for their email address.
- Only if it can't help (default) — the visitor goes straight into the conversation. The widget only asks for an email after a turn it couldn't really answer: no knowledge-base article matched the question, or the visitor explicitly asked to talk to a person. The ask appears inline, right under that answer, with a short line explaining why ("I couldn't find anything on that — leave your email and someone will follow up"), and a No thanks option that lets the visitor keep chatting without it. It only appears once per conversation.
- Before the conversation starts — the visitor sees an email field before they can ask anything, with a Skip link to bypass it. If saving the address fails (a bad address, a rate limit or a network problem) the field stays up with a short message rather than letting the visitor through as if it had worked, and Skip is always there so nobody is stuck.
- Never — the widget never asks.
Why the default changed
Asking up front, before the widget has done anything to earn the visitor's trust, was costing more conversations than the leads it produced — a visitor arrives with a question, not an intent to hand over an email, and bounces rather than answer a stranger-bot. Asking after a real miss gives the visitor context for why they're being asked, and the resulting address is attached to an actual unresolved question rather than a cold form fill.
What is saved with an on-failure lead
When a visitor leaves an email through the "couldn't help" prompt, the lead also carries the question that failed, shown next to the address on the Leads page and included in the CSV export. That text is never taken from the visitor's browser at submit time. When the widget checks whether a turn failed, the server returns a short-lived signed token containing the question it recorded for that turn; the widget sends the token back with the email, and the server verifies it before saving. A made-up or altered token is ignored and the lead is saved without a question. The question is flattened to a single line of plain text and capped at 500 characters. If the same email already has a lead from the up-front form, the question is filled in on that existing lead rather than creating a second one. Treat the question as customer-supplied text that may contain personal details.
Architecture: the on-failure check is single-instance only
"Only if it can't help" works by having the widget poll a small lookup right after a turn finishes, asking whether that turn just failed. The answer to that lookup is recorded under that turn's own id in the memory of whichever application server process handled the chat request — it is never written to the database or to shared cache, and it is only recorded for workspaces set to "Only if it can't help". Because each turn has its own entry, asking again returns the same answer, so the widget can safely retry the lookup if a response is lost, and a turn that failed or was rejected before it recorded anything can never be mistaken for an earlier turn's result. If your deployment runs more than one application instance behind a load balancer (self-hosters scaling horizontally; this does not apply to the standard answerLoops Cloud deployment), the visitor's follow-up poll can land on a different instance than the one that just answered. That instance has nothing in its memory for this turn, so the lookup simply returns "no prompt needed" — the on-failure email ask silently never appears for that turn. Nothing errors, no data is lost, and the conversation itself is unaffected; the visitor is just never asked for an email on that particular miss. A single-instance deployment never hits this. If you run multiple instances and need the prompt to appear reliably, use "Before the conversation starts" or "Never" instead, both of which have no cross-instance dependency.
Rotating the token
Tokens expire after 90 days. Settings warns you as the date approaches, and Regenerate token issues a new one.
Rotating takes effect immediately
Regenerating invalidates the old token. Every page whose snippet carries the token itself stops working until you update it. Rotate when you are able to update your site, or give the widget a public name first and the pages need no edit at all.
Give the snippet a public name
A public name is a stable label for your widget, such as acme-support, that the snippet carries instead of the token. When a page loads, the snippet looks the name up and gets whichever token is current, so regenerating the token takes effect everywhere within about a minute and nobody has to edit or redeploy a page. This is the better choice for documentation sites, where changing the snippet means a commit.
- In Settings → Widget, enter a name under Public name and select Save name. Use 3 to 40 lowercase letters, numbers and single hyphens.
- Copy the updated snippet, which now shows your name in
data-widget-id, and paste it into your site.
What you should see: the snippet reads data-widget-id="acme-support", and after you regenerate the token the widget keeps loading on the same page with no change to it.
<script src="https://your-instance.example.com/widget.js" data-widget-id="acme-support"></script>A public name is as visible as the token and grants nothing more. The allowed-domains list still decides where the widget loads. Names are unique across the instance, so one that another workspace holds is refused. Snippets that carry the token keep working until it expires or is regenerated. Clearing the name stops the widget loading on any page that still uses it. Only owners and admins can set or clear it.
Rich answer cards
Besides text, the assistant can answer with a small set of prebuilt cards when one is clearer than a paragraph:
- Steps — a numbered how-to for setup and troubleshooting sequences.
- Quick replies — tappable options when a question is ambiguous. Tapping one sends it as the visitor's next message.
- Callout — a highlighted tip, warning or confirmation.
- Link card — a card pointing to a page from your knowledge base.
- Contact options — email, phone or support-page buttons when a visitor needs a person.
The assistant only fills in the content of these cards; it never produces markup or code, and the widget draws every card with its own components, so cards match the widget's look and work on mobile. Links and contact details only appear in a card when they are written in your knowledge base articles — the assistant can't invent a URL, email address or phone number. Links must be https, and they open in a new tab. If a card's content doesn't pass those checks, the widget shows nothing for it and the text answer stands on its own.
To get contact or link cards, put the addresses and URLs you want visitors to see in your knowledge base articles. There is nothing to configure.
Rate limits and input caps
The widget chat endpoint is public (no login required), so it enforces limits to protect your AI provider bill from abuse:
- Up to 100 requests/minute per widget token (caps total cost exposure for one site even if traffic comes from many IPs)
- Up to 20 requests/minute per visitor (token + IP combination)
- Up to 500 answers/hour and 3,000 answers/day per workspace, across all visitors and widget tokens
- Loading the widget panel itself is limited to 30 loads/minute per visitor address and 600/minute per widget token
- The display-settings lookup the snippet makes on every page load is limited to 120/minute per visitor address and 1,200/minute per widget
- Each message capped at 4,000 characters; at most 50 messages per request
- Request bodies capped at 512KB
The lead-capture endpoint, used when a visitor leaves an email address, is limited separately at 30/minute per token and 5/minute per visitor, with a 64KB body cap and a validated address.
The on-failure check — a small lookup the widget makes right after a turn finishes, to decide whether to show the lead-capture prompt — is limited at 100/minute per token and 20/minute per visitor, the same shape as the chat endpoint next to it.
Requests over these limits return 429 Too Many Requests. The chat and lead-capture limits are enforced across every running instance rather than per process, so those numbers are the real ceiling. The on-failure check is the one exception — see the single-instance callout under Lead capture above. None of these limits are currently configurable.
Separately from rate limits, every widget answer counts toward your plan's monthly deflection allowance. On Standard, the widget stops answering once the allowance is used up and resumes at the next calendar-month reset; Pro keeps answering and bills overage. See Billing plans.
What the widget can and cannot reach
It answers from your knowledge base — published articles only. It does not read your ticket queue, and it has no access to settings, billing, or team data either; the embed token grants none of those.
Treat knowledge base contents as visible to anyone who can use the widget. If you have ingested internal documentation, review it before making the widget public.