Assistable chat widget · version 2

The complete feature guide

Every setting the chat widget has, what it does, where you change it in the dashboard, and what your visitor actually sees. Written for support staff and customers, with screenshots and recordings from a real widget running against a real API.

On this page

  1. Start here: three things that explain everything else
  2. Installing the widget
  3. The widget editor, tab by tab
  4. The launcher
  5. The teaser
  6. The Home tab
  7. Home action cards
  8. Form field types
  9. Destinations: where form answers go
  10. Where the data actually landed
  11. Tabs and the bottom nav
  12. The Messages tab
  13. The News tab
  14. The Roadmap tab
  15. The Help tab
  16. The pre-chat form
  17. The chat panel
  18. Human handoff and office hours
  19. Voice calls
  20. Tool cards
  21. The bug reporter
  22. Appearance: colour, theme, shape
  23. The small ones (and the dead ones)
  24. Allowed domains and other security settings
  25. Full configuration reference
  26. Troubleshooting
  27. How this guide was made

1. Start here: three things that explain everything else

1. Answers are always saved to Assistable first

An integration is an optional extra destination, never a requirement. Every submitted form is written to Assistable's own records, and whenever there is something a human would want to read, it also opens a conversation in your Inbox. That happens before anything is forwarded anywhere, whether or not a tool is chosen, whether or not Gleap, Zendesk, GHL or Stripe is connected, and even when the forward fails outright.

If you have not connected a helpdesk yet, set the form up anyway. It will work. Connect the helpdesk later and new submissions start flowing there as well, with no change to the form.

2. The settings live on the server, not in the embed code

The snippet you paste onto your website carries only a widget id. On load the widget calls GET /api/v1/widget-config/<widget id> and takes almost everything from the answer. That is why you never have to re-copy the snippet after changing a setting.

It also means changes are cached: about 30 seconds in the visitor's browser and up to 5 minutes on the server. If a change does not appear immediately, wait a minute and hard-refresh before assuming the save failed.

3. A few settings are not in that call

allowed_domains, ghlSync and ticketsEnabled are deliberately kept off the public configuration so that one customer cannot read another's. They are enforced server-side. A handful of other options can only come from the embed snippet, and a handful of switches in the dashboard currently do nothing at all. Both groups are flagged throughout with embed only and no effect badges, and listed together in section 23.

2. Installing the widget

Open Portal › Widgets, pick your widget, and go to the Install section (or press Get code in the header, which produces exactly the same snippet). Paste it just before the closing </body> tag of every page you want the widget on.

<script
  src="https://app.assistable.ai/chat-widget-v2.js"
  data-widget-id="cmqj7kubf0001rua7841r0345"
  data-api-url="https://api.assistable.ai"></script>
The Install section of the widget editor showing the embed snippet and a Copy button.
The Install section. The snippet contains only the widget id and the API address, so it never needs updating when you change a setting.
A demo company web page with the chat widget launcher and teaser card in the bottom right corner.
The result on an ordinary page: a launcher in the corner and, above it, the teaser card inviting the visitor in.
If the widget renders nothing

The widget refuses to render at all when the configuration call fails or when the returned widget id, assistant id or account id does not match the id you embedded. That is a deliberate safety check. Three causes cover almost every case: the widget is archived or deleted (the API answers 404 widget_not_found), the widget has no assistant assigned, or data-api-url points somewhere unreachable. Open the browser console; the widget logs a one-line reason such as widget_config_http_error or widget_config_timeout.

3. The widget editor, tab by tab

Everything in this guide is set in one place: Portal › Widgets › (your widget). The editor has six sections down the left and a live preview on the right that updates as you type, before you save.

A tour of the six sections: Assistant, Tabs & content, Appearance, Integrations & tools, Behavior, Install.
SectionWhat lives there
Assistant Which assistant answers, and the three messages the widget can override from it: popup message, intro message, fallback message. Suggested prompts are edited here too, but as a plain list with no Override switch. Also the door to the assistant's own knowledge bases and its shared messaging defaults.
Tabs & content Which of the five tabs are shown, the Home header and action cards, the News / Roadmap / Help content, and the launcher teaser.
Appearance Display name, company name, header subline, online dot, launcher icon, avatars, brand colour, teaser colour, light/dark, corner style, launcher size, position, auto-open.
Integrations & tools Which tools the assistant may call. These toggles belong to the assistant, not the widget, so they apply on every channel that assistant runs on.
Behavior Voice calling, GoHighLevel sync, human handoff and its mode, office hours, pre-chat form, notification sound, persist conversation, AI disclaimer, allowed domains.
Install The embed snippet.

Two conveniences worth knowing. The editor writes the open section into the address bar as ?section=behavior (and on Tabs & content also &card=help), so you can send a colleague straight to the exact control. And Cmd/Ctrl+S saves.

The Widgets list in the Assistable portal.
The widgets list. Click a widget's name to open its editor.

The Assistant section, and where messages really come from

Three of the widget's messages have two possible sources: the assistant (shared by every channel that assistant runs on) and the widget (this widget only). Each has an Override switch. Off, the field shows "Inherits from {assistant}: …" and follows the assistant. On, you type a value that applies to this widget alone. The teaser Greeting, over in Tabs & content, behaves the same way.

Suggested Prompts is not one of them. It has no Override switch: it is a plain list that simply replaces the assistant's prompts whenever you put anything in it, and falls back to the assistant's when you empty it.

The Assistant section showing the assistant picker and a Connect knowledge base button.
Which assistant answers, and the link to its knowledge bases. Persona, knowledge and tools all come from the assistant, not the widget.
The Assistant section showing Popup Message, Intro Message and Fallback Message with Override switches, and a Suggested Prompts list below them.
The three overridable messages: Popup Message, Intro Message and Fallback Message. Suggested Prompts sits below them with no Override switch.
Readiness chip

Beside the Save button the header shows Ready to publish or N to set up. Hover it for the list. It flags: no assistant assigned, voice on without a voice agent, handoff on without Slack, no greeting, and no display or company name.

Saving is all or nothing

Save changes validates every home action before it saves anything. A form card with no fields, or a link card with no URL, blocks the whole save with a red toast such as Invalid Home Actions: Action "Track my order" is a link but has no URL. An unrelated broken card will therefore stop your new one from saving too. On success you get Widget updated successfully.

4. The launcher

Launcher icon server

Appearance › Icons & avatars › Launcher icon · five choices · button_icon

Five presets, shown here in the brand colour. The dashboard labels them Chat, Message, Help, Support and AI; the stored values are chat, message, question, headset and sparkles. Anything else falls back to Chat.

Launcher with the Chat icon.
Chat
Launcher with the Message icon.
Message
Launcher with the Help icon.
Help
Launcher with the Support icon.
Support
Launcher with the AI icon.
AI

A logo replaces the icon server

Appearance › Icons & avatars › Header & bot avatar · logo_url

Set an avatar and it covers the whole launcher circle while the widget is closed. The preset icon is then never seen. Two consequences that generate tickets: the launcher stops looking like your brand colour (the image covers it), and opening the widget swaps the logo for a chevron, so "my logo disappears when I open the chat" is expected behaviour, not a bug.

Launcher showing a company logo instead of an icon.
With a logo
Launcher showing the chat icon in the brand colour.
Without one

Launcher size server

Appearance › Theme › Launcher size · Small / Medium / Large · launcher_size

48, 60 and 72 pixels across, with a 20, 24 or 28 pixel glyph inside. Medium is the default.

Small launcher.
Small (48px)
Medium launcher.
Medium (60px)
Large launcher.
Large (72px)

Position server

Appearance › Theme › Position · four corners · position

Bottom right is the default. The panel, the teaser and the launcher all move together.

Widget anchored to the bottom left of the page.
bottom-left
Widget anchored to the top right of the page.
top-right

Auto-open on page load server

Appearance › Theme › Auto-open on page load · auto_open

The panel is open the moment the page finishes loading, on every page the snippet is on. Use sparingly; it is the single most intrusive setting in the widget.

A web page loading with the chat widget already open.
With auto_open on, the visitor never sees the launcher first.

5. The teaser

The teaser is the small card that floats above the launcher to invite people in. It is made of three separate settings and can be turned off entirely.

The teaser fading in, being dismissed, and the panel opening and closing.

Greeting, subtitle and suggestion chips

Tabs & content › Launcher teaser for the greeting and chips · Assistant › Popup Message for the subtitle · teaser_greeting, teaser_suggestions, idle_message

The teaser card with a greeting, a subtitle and the assistant name.
Greeting and subtitle only. The meta line under it is always {display name} · Just now and cannot be changed.
The teaser card with three suggestion chips underneath.
With three suggestion chips. Tapping one opens the chat and sends it.

Clicking anywhere on the card body opens the chat. Only the small X dismisses it.

Teaser bubble colour server

Appearance › Theme › Teaser bubble color · teaser_color

The teaser does not use your brand colour by default. Left unset it is a near-black #1c1c1e. The dashboard has a Match brand color link if you want them the same. Text contrast flips automatically based on how dark the colour you pick is.

Teaser in the default near-black.
Default #1c1c1e
Teaser in brand blue.
teaser_color: #2563eb

Turning the teaser off server

Tabs & content › Launcher teaser › Show teaser bubble · show_prompt

Turn Show teaser bubble off and only the launcher renders. Clearing the greeting and the popup message and removing the chips has the same visible effect, but the switch is the direct control.

Only the launcher, with no teaser card.
Launcher on its own.
The Launcher teaser block in the editor with a Greeting field and a Suggestion chips textarea.
The Launcher teaser block, at the bottom of Tabs & content.
Two teaser gotchas

Dismissal only lasts for the browser tab. The X writes to sessionStorage, so the teaser is back in a new tab or after the browser is restarted. "It keeps coming back" is by design.

There is no delay setting. The card is held back by a fixed 350 millisecond delay, then fades up over 220 milliseconds, with the chips staggering in behind it from 400 milliseconds. Nothing in the dashboard changes any of that timing.

6. The Home tab

Home is the first thing a visitor sees. Top to bottom it is: the logo, the heading, the sub-heading, an ask box, then either your action cards or a pair of prompt chips, then the optional bug reporter.

The widget Home tab with a heading, sub-heading, ask box and five action cards.
A configured Home tab.

Header and sub-header server

Tabs & content › Home › Header / Sub-header · menu_header, menu_subheader

Leave the header blank and the widget falls back to "How can we help?". Leave the sub-header blank and it falls back to "We typically reply in a few minutes." There is no way to render Home with no sub-heading at all; you can only replace the wording.

The Home card in the editor with Header and Sub-header inputs and the live preview alongside.
The Home card in Tabs & content, with the live preview reflecting it.

The ask box

Always present, always reading "Ask me anything...". There is no setting for this placeholder. Typing here and pressing Enter opens the chat with that question already sent.

Prompt chips, and when they disappear server

Assistant › Suggested Prompts · prompts

Suggested prompts show on Home as chips, but only when there are no home action cards at all, and only the first two. Add a single action card and every chip vanishes from Home. They still show inside an empty chat, where all of them render.

Home tab with two prompt chips instead of action cards.
No action cards, so the first two prompts render as chips.
Home tab with the built-in Report an issue and Request a feature chips.
No cards and no prompts: two built-in chips appear, "Report an issue" and "Request a feature".

The chip icons are chosen by position, not by wording: the first chip always gets a bug icon and the second always a lightbulb, whatever the text says.

Not on Home

Three settings people expect on Home are not there. The online dot, the header subline and the "Powered by" line all live in the chat panel, not the Home tab. So does the AI disclaimer. See section 17.

7. Home action cards

Tabs & content › Home › Home action cards · home_actions

Action cards are the buttons on Home. Each has a title, an optional subtitle, an icon, an optional accent colour, and a mode that decides what tapping it does.

Adding a card from a template, reviewing its fields, and saving.
ModeDashboard labelWhat happensWhen to use it
chatOpen the chat Opens the chat. If you set a Starter message it is sent to the AI immediately; otherwise the card's title is sent as the visitor's first message. Anything conversational.
formShow a form to fill in Opens a form built from the fields you define. On submit the answers are saved, and optionally forwarded to one destination. Bug reports, feature requests, NPS surveys, lead capture.
linkSend to another page Opens a URL in a new tab. Status pages, docs, booking pages, courier tracking.
Four home action cards demonstrating chat, form and link modes plus an unrecognised icon.
All three modes on one Home tab. The fourth card has icon: "not-a-real-icon" and has silently fallen back to the generic message bubble.

Starting from a template

Add from template gives you five complete, working cards: Bug report, Feature request, NPS survey, Order status (commerce), and Ask a question (chat). Starting from a preset is easier than starting blank because the field keys are already correct.

The Add from template row in the home actions builder.
The template gallery. Add blank card below it starts from nothing.

Editing a card

The Home action cards list in the editor with five collapsed rows each showing its mode and field count.
The card list. Each row's summary line tells you its mode and, for forms, the destination and field count, for example form · create_support_ticket · 5 fields. Use the pencil to expand and the bin to delete.
An expanded action card showing the destination dropdown and the form field editor.
An expanded form card: title, mode, subtitle, icon, accent colour, the destination dropdown, and the field editor.

Advanced: edit as code, top right of the card list, swaps the visual builder for the raw JSON. Handy for bulk edits and for copying a set of cards between widgets, and the only way to produce a configuration the visual builder would refuse.

Icon names

The Icon box is free text and expects a lucide icon name in kebab-case: help-circle, alert-triangle, smile, bug, package, credit-card, calendar, star, zap. Case and punctuation are forgiven, so HelpCircle also works, but a name outside the supported set silently falls back to the generic message bubble. That is the usual reason every card ends up with the same icon. Watch the live preview as you type: if the icon does not change, the name is not recognised.

A form card with no fields is not a form

The editor blocks saving a form card with zero fields. But if one reaches the widget anyway (for example through the Advanced: edit as code JSON box), the card silently behaves as a chat card and sends its own title as a message. Similarly, a card with no title is dropped entirely when the configuration is served.

8. Form field types

Each field row in the editor has four controls: the label the visitor reads, the type, a Required toggle, and the key box on the right (that is maps_to, covered below).

A widget form showing short text, long text, email and dropdown controls.
Short text, long text, email, dropdown.
A widget form showing radio, checkbox, smiley rating, NPS, numeric scale and priority controls.
Single choice, checkbox, smiley rating, NPS, numeric scale, priority.
Dashboard labelStored asWhat the visitor sees
Short texttextOne-line input, with your placeholder if you set one.
Long texttextareaFour-row resizable box.
EmailemailEmail input. The only type whose format is validated.
DropdownselectA select built from your comma-separated options, with a leading "Select…".
Single choice (radio)radioA vertical radio list built from your options.
Checkbox (yes/no)checkboxOne tick box. Required means it must be ticked.
Smiley rating (1-5)ratingFive faces, stored as "1" to "5".
NPS (0-10)npsA 0 to 10 row labelled "Not at all likely" and "Extremely likely".
Numeric scalescaleA numeric row with the min and max you set, defaulting to 1 and 5. No captions.
Priority (low/normal/high/urgent)priorityFour buttons: Low, Normal, High, Urgent, each with a colour dot.

Validation, in practice

A widget form with red Required messages under three empty fields.
Required fields checked on submit. Each shows the word Required and a red border.
The same form filled in with a subject, description, High priority, name and email.
Filled in, with High selected on the priority row.

Field keys and maps_to

Every field gets a random internal id such as f-a3k9, and raw answers are stored under those ids. When answers are forwarded to a destination they need a meaningful key instead: a ticket needs to know which answer is the subject, GHL needs to know which is the email address. That is what the key box (maps_to) sets.

  1. If you typed something in maps_to, that is used.
  2. Otherwise the label is slugified. If the result is one of email, phone, first_name, last_name or name, that is used. A field labelled simply "Email" needs no maps_to.
  3. Otherwise, if the field type is Email, the key is email.
  4. Otherwise the random id is used, which no destination understands.

A leading contact. or ticket. is accepted and stripped automatically, so ticket.subject and subject mean the same thing. The stock templates ship the prefixed form.

DestinationKeys it reads
Support ticket subject, description (or body), priority; requester email from email, requester_email or visitor_email; requester name from name, requester_name, visitor_name or first_name
Feedback message, description, comment or title for the comment; type, severity; plus the email and name keys above. The score is taken from the rating, NPS or scale field automatically.
GHL contact email, phone, first_name, last_name, name, tag. Anything else is attached as a contact note.
Stripe lookupsemail
Knowledge-base searchquery

Submitting, from the visitor's side

A visitor opening the "Report a bug" card, filling it in and submitting. This is a real submission against the real API; the records it created are in section 10.
An empty widget form with five fields, required ones marked with a red asterisk.
Empty. Required fields carry a red asterisk.
The same form filled in.
Filled in.
The success screen showing a green tick, the word Submitted and a confirmation message.
The success screen. The wording comes from the card's Success message; the heading is always "Submitted".

9. Destinations: where form answers go

The What should happen with this form? dropdown picks a single optional destination for a copy of the answers. "Just collect the answers" is a perfectly good choice; everything still lands in your Inbox.

Read this table with section 1 in mind

Whatever the "if it is not connected" column says, the answers are already saved on Assistable's side before the forward is even attempted.

Destination What it does What must be connected If it is NOT connected
Just collect the answers Saves the answers and opens a conversation in your Inbox. Nothing. Nothing to break.
create_ticket
create_support_ticket
Creates a support ticket and routes it. Both names behave identically. Routing order is Zendesk, then Gleap, then the Assistable inbox; the first connected one wins. Nothing for the in-app route. Zendesk or Gleap only if you want the ticket to appear there. Falls down the chain to the Assistable inbox, which always works. A Zendesk API failure falls back silently to Gleap and then in-app, so a ticket may exist somewhere other than where you expected. Check the ticket's destination before concluding it vanished.
submit_feedback Saves a feedback record (kind, rating, scale, comment). If Gleap is connected it is mirrored there in the background. Nothing. Gleap optional. The feedback is still saved. A failed Gleap mirror is recorded against the record and logged; the visitor never sees an error.
ghl_contact Creates or updates a GoHighLevel contact from the email, phone and name fields, adds the configured tag, and attaches any remaining answers as a contact note. A GHL connection on the subaccount, at least one field mapped to email or phone, and the tag your GHL workflow triggers on. Fails with ghl_not_connected, or email_or_phone_required if nothing is mapped to email or phone. If the contact is created but the tag fails you get ghl_tag_failed: the contact exists but your automation never fired. Answers are saved either way.
webhook POSTs the mapped answers to the URL on the card, as {source, subAccountId, submittedAt, fields}. A public URL on port 80 or 443 that returns 2xx within 8 seconds and does not redirect. http:// is accepted as well as https://. Private and internal addresses are blocked. One attempt, no retries. The failure is logged and reported as not delivered; the answers are still saved. For guaranteed delivery use a workspace webhook subscription instead.
search_kb Searches the knowledge bases attached to the widget's assistant. A lookup: nothing is stored. An assistant with at least one knowledge base. Returns nothing. Caveat: the form screen does not display lookup results, so use a chat card for knowledge-base questions instead.
get_subscription_status Looks up the Stripe subscription for a given email. A lookup. A Stripe integration on the subaccount, and a field mapped to email. Fails with stripe_not_connected or subscription_not_found and the visitor sees a generic error. Same display caveat as above.
list_invoices Lists Stripe invoices for a given email. A lookup. As above. As above.
Never point a form at GHL casually

ghl_contact writes into a live customer CRM: it creates or updates a real contact and adds a tag that can trigger real automations (emails, texts, pipeline moves). Test it against a throwaway location, never against production.

Two dropdown labels are misleading

"Create support ticket (Zendesk)" does not require Zendesk; it routes to whichever helpdesk is connected and falls back to the Assistable inbox when none is. Likewise "Submit feedback (Gleap)" saves feedback locally first and only mirrors to Gleap if Gleap happens to be connected.

Saved and delivered are two separate facts

In the JSON that comes back from actions/submit these are the ok and delivered fields, with delivery_error alongside them when a forward failed.

They are separate so that a dead destination never makes a visitor retype answers you already have. The flip side is that a failed forward is invisible to the visitor. When someone reports "the form worked but nothing arrived", the delivered flag in the submit response is the first thing to check. The three lookups are the exception: they store nothing, so when they fail the visitor sees an error.

10. Where the data actually landed

This is the submission from the video above, read back from the database. The widget had no Zendesk and no active Gleap integration, which is the most common starting position.

The submission record

SELECT _id, "actionId", "actionTitle", tool, "contactName", "contactEmail",
       "contactId", "conversationId", "createdAt"
FROM "widgetFormSubmission"
WHERE "widgetId" = 'cmqj7kubf0001rua7841r0345'
ORDER BY "createdAt" DESC LIMIT 1;

_id            | cmsplrohu000alsrul13xlkrw
actionId       | bug-vsh3mt
actionTitle    | Report a bug
tool           | create_support_ticket
contactName    | Dana Whitfield
contactEmail   | dana.whitfield@northwind-demo.test
contactId      | cmspi54l00000e0rutazat78n
conversationId | cmsplrohb0008lsrui8gfrygg
createdAt      | 2026-08-12 04:42:13.314

The raw answers live on the same row, keyed by field id:

{
    "f-19tc": "Dana Whitfield",
    "f-a36o": "dana.whitfield@northwind-demo.test",
    "subject": "Checkout fails on the final step",
    "priority": "high",
    "description": "Adding a cordless drill to the basket works, but pressing
                    Pay returns 'order could not be created'. Reproduced in
                    Chrome and Safari."
}
This is what maps_to is for

subject, priority and description are readable because they came from a preset. The name and email fields were added by hand and kept their random ids f-19tc and f-a36o. That is fine here, because both have maps_to set (contact.name and contact.email), so the ticket still knows which is which. Had maps_to been left blank on a label the system cannot guess, that answer would have reached the ticket as f-19tc and been ignored.

The support ticket

_id            | cmsplv0d6000flsrufcv2r245
subject        | Checkout fails on the final step
priority       | high
status         | open
source         | home-action
requesterName  | Dana Whitfield
requesterEmail | dana.whitfield@northwind-demo.test
destination    | in-app
externalId     |
contactId      | cmspi54l00000e0rutazat78n
conversationId | cmsplv0ca000clsruej7v1bw4
submissionId   | cmsplv0co000elsrusu9b1qia

destination = in-app is the fallback working exactly as designed: no helpdesk was connected, so the ticket lives in Assistable and the team works it from the Inbox. With Zendesk or Gleap connected this would read zendesk or gleap and the row would also carry the external ticket id and URL.

And in the Inbox

_id             | cmsplrohb0008lsrui8gfrygg
lastChannel     | Live_Chat
lastSubjectLine | Checkout fails on the final step
contactEmail    | dana.whitfield@northwind-demo.test
previewText     | Adding a cordless drill to the basket works, but pressing
                | Pay returns 'order could not be created'. Reproduced in
                | Chrome and Safari.

One exception: a submission that is nothing but a rating, for example a bare NPS score with no comment, does not open a conversation. Those live in the submission and feedback records only. Ticket destinations are exempt from the exception: create_ticket and create_support_ticket always open a conversation, even from a bare rating. If you want NPS responses visible to your team, add an optional comment field to the survey.

11. Tabs and the bottom nav

Tabs & content, the Shown/Hidden switch on each card · visible_tabs

There are five tabs: Home, Messages, News, Roadmap and Help. Each card in the editor has a Shown/Hidden switch, and the counter at the top reads "N of 5 shown". You cannot hide the last remaining tab.

Moving between all five tabs.
The Tabs and content section showing the template picker and the five tab cards.
The five tab cards, each with its own Shown switch.
Three things about the nav
Widget with all five tabs in the bottom nav.
All five tabs shown.
Widget with only the Home tab and no bottom nav bar.
Only Home shown, so there is no nav bar.

12. The Messages tab

Tabs & content › Messages · visibility only, there is nothing to edit

Messages lists the visitor's past conversations with this assistant, newest first, up to 30. Each row shows who they were talking to, a preview, a timestamp, and a status chip: AI, LIVE when a human has taken over, or ENDED when the conversation was resolved.

The Messages tab empty state reading No messages yet with a Send us a message button.
The empty state. Send us a message starts a fresh conversation; with history present the button reads Start a new conversation.
A failed lookup looks exactly like "no history"

If the sessions request fails, the tab shows "No messages yet" rather than an error. History is also keyed on a per-browser visitor id, so clearing site data loses it unless the visitor's email was captured. If a customer says their visitors cannot see past chats, check the network tab for the /api/v1/widget/sessions call before assuming the history is gone.

13. The News tab

Tabs & content › News · news.heading, news.empty_message, news.items

A changelog for your visitors. Add items by hand, or paste an RSS feed URL and press Fetch to import them. Each item has a Title, Summary, Category, Image URL, Link and Published date; only the title is required.

The News tab with category chips and three update cards.
Category chips appear only when there is more than one category. "All" is always first; news renders as "News" and changelog as "Changelogs". Anything else is lower-cased with only its first letter capitalised, so "Product Updates" shows as "Product updates".
The News tab empty state.
The empty state, using the heading and empty message you set.
The News card in the editor with the RSS import box and the item builder.
The News card in the editor, with RSS import above the item list.
The published date is never shown

published_at is used only to sort the list newest first. It is not rendered anywhere in the widget, so "the date is missing from my update" is not a bug and there is no format to configure. Items with no date sort to the bottom. An item with no category is treated as news.

14. The Roadmap tab

Tabs & content › Roadmap · roadmap.heading, roadmap.empty_message, roadmap.items

What you are building. Each item has a Title, Description and Status: Considering, Planned, In progress or Shipped. Visitors get two dropdowns: sort by Most votes or Newest, and filter by status.

The Roadmap tab with four items, vote counts and status pills.
Four items sorted by votes.
The Roadmap tab empty state.
The empty state.
The Roadmap card in the editor with the item builder.
The Roadmap card in the editor. Each item has Move up, Move down and Remove buttons, and Add item at the bottom.
The vote arrow is not a button

The up-chevron beside each vote count looks clickable but is not wired to anything in the widget: it is a plain number with an arrow above it. Visitors cannot vote. Expect "voting is broken" reports and answer them with this. Vote counts only change if something else writes them.

The status dropdown only lists statuses that actually exist in your data, so "Shipped" does not appear as a filter until you have shipped something.

15. The Help tab

Tabs & content › Help · help.heading, help.empty_message, help.search_placeholder, help.articles

Help does two things at once. It shows the articles you pin (Title, Description, Article URL, optional Section), grouped by section. And, if the widget has an assistant, it searches your knowledge base live as the visitor types, showing matches under "From the knowledge base" that expand in place.

You can add articles by hand, paste one or more URLs and press Fetch to scrape their titles and descriptions, or Upload CSV / JSON.

The Help tab with a search box and two pinned articles.
Pinned articles. These two were imported by pasting URLs, which is why their descriptions read like scraped page text.
The Help tab with the word billing typed and a No results message.
A search with no matches, in a widget whose knowledge base has nothing on the subject: No results for "billing".
The Help tab empty state.
No articles and no knowledge base: the empty state.
The Help card in the editor with URL import, CSV upload and the article builder.
The Help card in the editor.
How the search behaves

16. The pre-chat form

Behavior › Pre-chat form, plus the name / email / phone checkboxes · pre_chat.form_first, pre_chat.fields

With this on, the visitor must give their details before they can send a first message. It is skipped automatically for visitors whose details you already have.

The pre-chat form asking for Name, Email and Phone with a Start chat button.
All three fields enabled.
The pre-chat form showing a red Name is required message.
Validation is one message at a time, in the order name, email, phone.
Two things to know

Every field you tick is mandatory. There is no way to ask for a phone number optionally: ticking Phone makes it required. Ticking fewer boxes is the only way to reduce friction.

There is no skip button. The only ways past the form are a valid submit, or already having contact details stored in the browser.

Where the field list comes from

The name / email / phone checkboxes are read from the server and win over the embed snippet. Only when the saved list is empty, or contains nothing the widget recognises, does it fall back to data-pre-chat-fields on the snippet, and failing that to name and email.

This used to work the other way round: bundles built before this was joined up ignored the dashboard checkboxes entirely. A site pinned to an old copy of chat-widget-v2.js will still need data-pre-chat-fields="name,email,phone" on the snippet.

17. The chat panel

A conversation: the intro message, the visitor typing, the typing indicator, a streamed reply, and a tool card. The widget is live; the assistant's words are a stubbed model response (see section 27).

The header

Appearance › Identity · display_name, brand_name, header_subline, show_online_indicator

Back arrow, avatar, then up to three lines of text: the display name, the company name, and either the header subline or the online row.

Chat header showing a display name, company name and a plain subline.
Header subline as plain text.
Chat header showing a green dot next to the status line.
With the online indicator on, a green dot appears and replaces the plain subline.

The online row needs something to say: it renders when a human has taken over ("Live agent connected") or when you have set a header subline. With neither, turning the indicator on changes nothing.

Intro message and suggested prompts

Assistant › Intro Message and Suggested Prompts · intro_message, prompts

The intro message is the first bubble in every new conversation. Below it, all your suggested prompts render as chips until the visitor sends their first message, then they disappear for good.

An empty chat showing the intro bubble and three prompt chips.
An empty conversation.

Messages and the typing indicator

Visitor messages are right-aligned in the brand colour; assistant messages are left-aligned in grey with the AI avatar. Assistant text is rendered as Markdown (bold, lists, links, tables, code), visitor text is not.

The chat showing three bouncing dots while the assistant composes a reply.
The typing indicator: three bouncing dots.
A completed exchange with a bold-formatted assistant reply.
A reply with Markdown bold applied.

Markdown headings are flattened: #, ## and ### all render as ordinary bold text, not at heading size. If an assistant's answers look unstructured, that is why.

The composer

Placeholder "Message…", or "Conversation ended" once a conversation is resolved. Alongside the send button there is a paperclip for attachments and, in browsers that support it, a microphone for dictation.

Attachments have a quirk: the paperclip accepts images, PDFs, Word, text, CSV, spreadsheets and JSON, but drag-and-drop and paste accept images only. "I can attach a PDF with the clip but not by dragging it" is expected.

Fallback message server

Assistant › Fallback Message · fallback_message

Shown as an assistant bubble when the AI cannot be reached. Note that the visitor sees two things in that situation: your fallback message, and a separate built-in card offering to take their email. The second one is not configurable.

A chat showing the fallback message bubble and an email capture card below it.
A real failure captured against the local API: the configured fallback bubble, then the built-in "leave your email" card.

AI disclaimer and branding server

Behavior › AI Disclaimer and Appearance › Company name · ai_disclaimer, show_branding, brand_name

The disclaimer is a small centred line under the composer, maximum 120 characters. The "Powered by" line sits below it and needs both the branding switch and a company name; with the name blank it silently renders nothing.

The bottom of a chat panel showing an AI disclaimer and a Powered by line.
Both lines under the composer.

Notification sound server

Behavior › Notification sound · notification_sound

Plays a short chime when a reply arrives while the widget is closed.

The six sound choices do nothing

Ping, Pop, Subtle, Futuristic, Attention and Bottle all save correctly, but the widget ignores the choice and plays one hard-coded tone. Only the on/off switch has an effect today.

Appointment banner

A one-line strip at the top of the message area reading "See you on your appointment at Monday, Aug 17 at 3:30 PM". It appears when the widget has been given an upcoming appointment with both a start time and a timezone. A missing timezone hides it entirely, with no local-time fallback, which is the usual reason it does not show. The wording is fixed and English-only.

A chat with a thin appointment reminder strip above the messages.
The banner. There is currently no dashboard field for this; it has to be supplied to the widget programmatically.

18. Human handoff and office hours

Behavior › Human handoff · handoff_mode, office_hours

The Behavior section with human handoff enabled, showing the Show it and Stay silent options, office hours and a Slack row.
Handoff switched on reveals the mode choice, office hours and the Slack notification row.

The dashboard stores handoff as an on/off switch plus a mode. The disabled value below is what the configuration endpoint reports when the switch is off; it is not a third choice in the editor.

SettingReported asWhat the visitor experiences
Handoff offdisabledNo handoff surface at all. The AI handles every conversation.
Show itsupportA "Talk to a human" chip appears in an empty chat, and when someone takes over the visitor sees a banner naming them. Intercom-style.
Stay silenttransparentAgent replies arrive as ordinary assistant bubbles. The visitor is never told a human joined, and there is no handoff button. Chatwoot-style.
An empty chat with a Talk to a human chip.
Mode "Show it": the chip in an empty conversation.
A chat showing a We're offline card with an email input and a Send button.
Outside office hours the chip is replaced by an email capture card.

Office hours

The office hours editor with a timezone, per-day time ranges, an offline heading, an offline message and a collect-email checkbox.
The office hours editor: timezone, a row per day, the closed heading and message, and whether to collect an email while closed.
Three rules that surprise people

The Notify your team on handoff row shows whether Slack is connected. It is a status display only; connect Slack from Portal › Integrations.

19. Voice calls

Behavior › Voice calling · voice_enabled

With voice on, the chat header gains a Chat / Voice switch. Voice puts the visitor on a live call with the same assistant, seeded with the last few turns of the chat so the agent already knows the context.

Switching to Voice and starting a call. On this local stack there is no voice agent reachable, so the call ends in the error state.
The voice view showing an avatar, Tap to start a voice call, and a Start voice call button.
Idle: "Tap to start a voice call".
The voice view showing Couldn't connect and an error message.
The error state, with the reason above the "Call again" button.
StateOn screen
Idle"Tap to start a voice call", one Start voice call button.
Connecting / ringing"Connecting…" then "Ringing…", with a mute button and a red hang-up button.
LiveThe call duration as mm:ss, replacing the status text. Mute and hang up.
Ended"Call ended", and the button becomes Call again.
Error"Couldn't connect", plus a red box with the reason (blocked microphone, no microphone, voice unavailable).
Two hard requirements and one trap

The switch appears when the Behavior toggle is on and the assigned assistant has a voice agent configured. The editor shows an amber warning on the toggle when the second condition is missing. The embed snippet cannot turn voice on by itself; only the server can.

The toggle is on by default. A widget whose Voice calling switch has never been touched counts as on, so the moment its assistant gains a voice agent the Chat / Voice switch appears without anyone having enabled it. If you do not want voice, turn the toggle off explicitly rather than assuming it starts off.

Switching back to Chat during a call hangs up. The call is not put on hold; it is torn down. Tell visitors to use the red hang-up button, not the Chat tab.

20. Tool cards

Integrations & tools · these toggles belong to the assistant, not the widget

When the assistant calls a tool, the result renders as a rich card in the conversation rather than as text. Tickets, feedback, Stripe subscriptions and invoices, bookings and availability, product carousels, orders, refunds, discounts and checkout all have their own card.

A chat showing a Ticket Created card with a ticket number, subject, priority and status.
A create_support_ticket result. The card is rendered by the widget; the model response behind it is stubbed (see section 27).
The Integrations and tools section listing Knowledge, Zendesk, Gleap and Stripe tools.
The tool list. Because these live on the assistant, turning one off here turns it off on every channel that assistant runs on.
Two things about tool output

You cannot hide tool result cards. A separate flag, show_tool_activity, governs the transient grey "Using create support ticket…" line while a tool runs. It is off by default and the configuration endpoint never sends it, so in practice that line does not appear at all. The finished card always renders and cannot be suppressed. Customers who ask to "hide the tool stuff" usually mean the cards.

An unrecognised tool renders nothing at all. If a custom tool has no card of its own, the visitor sees the assistant's text and no trace that anything ran. A failed tool, by contrast, always shows a red "Error" card.

21. The bug reporter

embed only add data-bug-report="true" to the snippet

A one-tap "Report a problem" entry on Home that takes a screenshot of the page automatically, lets the visitor describe what went wrong, and sends both.

The Home tab with a Report a problem card at the bottom.
The entry card, below the action cards.
The bug report screen showing a captured screenshot of the page, an Include screenshot checkbox and a description box.
The captured screenshot, an Include screenshot tick box, a Recapture link and the description box.
Worth knowing

22. Appearance: colour, theme, shape

Light and dark, the three corner styles, launcher size and position, all reflected immediately in the live preview.
The Theme block of the Appearance section with brand colour, teaser colour, mode, corner style, launcher size, position and auto-open.
The Theme block, with the live preview on the right.

Brand colour server

Appearance › Theme › Brand color · color

Used for the launcher, the send button, visitor message bubbles, the active tab, links inside assistant messages and a faint tint on the Home background. Pick a hex value; the swatches are shortcuts.

Use a six-digit hex. Some effects (the voice call's pulse ring, the shadow under the launcher) append transparency to the value and will silently look wrong with a named colour or an rgb() string.

Light and dark server

Appearance › Theme › Mode · dark_mode

A single fixed choice, not a follow-the-visitor's-system option.

The widget Home tab in dark mode.
Dark mode.
Dark mode is not complete

Look at the action cards above: they keep a light background in dark mode because their fill is hard-coded rather than themed. The chat composer box stays light for the same reason. Test dark mode before enabling it for customers.

Corner style server

Appearance › Theme › Corner style · Rounded / Soft / Sharp · theme

Controls the panel's corner radius: 20, 14 and 6 pixels respectively.

Widget panel with rounded corners.
Rounded
Widget panel with soft corners.
Soft
Widget panel with sharp corners.
Sharp

Names and avatars server

Appearance › Identity and Icons & avatars

The Identity block showing Display name, Company name, Header subline and an Online indicator switch.
The Identity block.
The Icons and avatars block showing launcher icon choices and two avatar URL fields.
The Icons & avatars block.
FieldKeyWhere it shows
Display namedisplay_nameThe bold name in the chat header and on the teaser.
Company namebrand_nameThe second line in the chat header, and the "Powered by" line.
Header sublineheader_sublineSmall text under the name in the chat header. Maximum 60 characters.
Header & bot avatarlogo_urlHeader, AI message bubbles, Home, and the closed launcher.
AI message avatarai_avatar_urlOverrides the above on AI bubbles only, so the bot can have a different face from the brand. Note the label is misspelled "AI messae avatar" in the dashboard.
Fallback iconicon no effectUsed by the older Floating Orb widget type. The chat widget never reads it.

23. The small ones (and the dead ones)

Settings that only come from the embed snippet

AttributeDefaultWhat it does
data-bug-report="true"offShows the "Report a problem" card on Home. No dashboard equivalent.
data-pre-chat-fields="name,email,phone"name,emailWhich pre-chat fields render when the dashboard checkboxes are empty. A saved dashboard list overrides this attribute.
data-pre-chat-heading, data-pre-chat-subheading"Before we start" / "Quick info so we can follow up."The pre-chat form's two lines of copy.
data-show-prompt="false"onA hard opt-out for the teaser. Unlike every other setting, the server cannot override this one back on.
data-enable-memory="false"onStops the widget remembering the visitor between visits.
data-voice-endpoint{api url}/v3/create-web-callPoints voice calls at a different endpoint. Rarely needed, and ignored once a chat session exists: a call started from inside an existing conversation always uses the default.

Switches that currently do nothing

These save correctly and appear in the configuration, but nothing in the running widget reads them. They are listed here so you do not spend an afternoon debugging one.

SettingWhere it appearsReality
Persist conversation
persist_history
BehaviorChat history is kept regardless. Turning it off does not stop it.
Notification sound choice
notification_sound_kind
Behavior, six buttonsOne hard-coded chime plays whatever you pick. The on/off switch does work.
Fallback icon
icon
AppearanceBelongs to the Floating Orb widget type, not this one.
prompts_sourcenot in the UIReported by the API so you can tell whether prompts came from the widget or the assistant. The widget ignores it.

The rating popup

Present in the product, currently unreachable

The widget contains a "How was your experience?" star-rating popup that is meant to appear when a visitor closes the panel after a conversation. In the current build nothing triggers it: the only close control available inside a conversation is the launcher, and that path skips the popup entirely. Do not promise customers a post-chat rating prompt. Use an NPS home-action card instead, which does work (see section 8).

Other small behaviours worth knowing

24. Allowed domains and other security settings

Behavior › Allowed Domains · one per line · allowed_domains

The Behavior section showing voice calling, GHL sync, handoff, pre-chat form, notification sound, persist conversation, AI disclaimer and allowed domains.
The whole Behavior section. Allowed Domains is the last box.
RuleBehaviour
Empty listAllows every domain. This is the default for a new widget, and it means an unconfigured widget can be embedded anywhere.
Exact hostnameexample.com matches only example.com.
Wildcard*.example.com matches app.example.com and deeper, but not the bare example.com. List both if you need both.
A blocked originThe API answers 403 origin_not_allowed.
What a blocked domain looks like

Not an error message. The configuration call is not gated, so the widget loads and looks completely normal; every message then fails and the visitor sees your fallback message. A misconfigured allowlist therefore presents as "the bot stopped answering", not as "the bot is blocked". Check the network tab for a 403 before chasing the AI.

SettingWhereWhat it does
Sync conversations to GoHighLevel
ghlSync
Behavior Mirrors widget conversations into the connected GHL location so they appear in the CRM's inbox. Off by default. Never shown in the public configuration.
Ticketing
ticketsEnabled
No UI Server-side switch, on unless explicitly set to false, that allows this widget to create support tickets. There is no dashboard control for it today.
Rate limits Not configurable Roughly 30 chat messages per minute per visitor, plus per-IP and per-widget ceilings. Exceeding them returns 429.

25. Full configuration reference

Every key the widget configuration returns, its default when unset, and where you change it. no effect marks keys the running widget ignores.

Appearance

KeyDefaultDashboard locationEffect
color#000000Appearance › Brand colorLauncher, buttons, visitor bubbles, active tab.
display_namethe widget's nameAppearance › Display nameBold name in the header and teaser.
brand_namethe subaccount nameAppearance › Company nameSecond header line; required for the "Powered by" footer.
logo_urlnoneAppearance › Header & bot avatarHeader, AI bubbles, Home, closed launcher.
icon no effectmessage-circleAppearance › Fallback iconFloating Orb only.
button_iconchatAppearance › Launcher iconLauncher glyph. One of chat, message, question, headset, sparkles.
ai_avatar_urlnoneAppearance › AI messae avatarOverrides the logo on AI bubbles.
teaser_color#1c1c1eAppearance › Teaser bubble colorTeaser background; text contrast auto-adjusts.
themeroundedAppearance › Corner stylePanel corner radius: rounded 20px, soft 14px, sharp 6px.
dark_modefalseAppearance › ModeDark palette.
auto_openfalseAppearance › Auto-open on page loadPanel opens on load.
notification_soundoffBehavior › Notification soundChime on a new reply while closed.
notification_sound_kind no effectnoneBehavior, six buttonsChoice is ignored; one fixed tone.

Messaging

KeyDefaultDashboard locationEffect
intro_messagefrom the assistantAssistant › Intro MessageFirst bubble of a new conversation.
idle_messagefrom the assistantAssistant › Popup MessageThe teaser's second line.
menu_header"How can we help?"Tabs & content › Home › HeaderHome heading.
menu_subheader"We typically reply in a few minutes."Tabs & content › Home › Sub-headerHome sub-heading.
fallback_messagea built-in apologyAssistant › Fallback MessageShown when the AI cannot be reached.
teaser_greetingfrom the assistantTabs & content › Launcher teaser › GreetingTeaser headline, max 80 chars.
teaser_suggestionsemptyTabs & content › Launcher teaser › Suggestion chipsUp to 6 chips, one per line.
promptsfrom the assistantAssistant › Suggested PromptsChips: 2 on Home (only when there are no action cards), all in an empty chat.
prompts_source no effectassistantnot in the UITells you whether prompts came from the widget or the assistant.
ai_disclaimernoneBehavior › AI DisclaimerSmall line under the composer, max 120 chars.

Layout and content

KeyDefaultDashboard locationEffect
visible_tabsHome + MessagesTabs & content, Shown switchesWhich tabs appear. One tab means no nav bar.
positionbottom-rightAppearance › PositionWhich corner the widget sits in.
launcher_sizemdAppearance › Launcher size48 / 60 / 72 pixels.
header_sublinenoneAppearance › Header sublineSmall line in the chat header, max 60 chars. Suppressed by the online indicator.
home_actionsfrom the templateTabs & content › Home › Home action cardsThe buttons on Home.
pre_chat.form_firstfalseBehavior › Pre-chat formGate the chat behind a contact form.
pre_chat.fieldsemptyBehavior, three checkboxesWhich pre-chat fields render. Overrides data-pre-chat-fields whenever it is non-empty.
news.heading / .empty_message / .items"News" / built-in copy / emptyTabs & content › NewsNews tab title, empty state, list. Max 50 items.
roadmap.heading / .empty_message / .items"Roadmap" / built-in copy / emptyTabs & content › RoadmapRoadmap tab title, empty state, list. Max 50 items.
help.heading / .empty_message / .search_placeholder / .articles"Help center" / built-in copy / "Search articles…" / emptyTabs & content › HelpHelp tab title, empty state, search box, pinned articles. Max 50 items.
show_prompttrueTabs & content › Launcher teaser › Show teaser bubbleWhether the teaser can show at all.
show_brandingfalsenot exposed today"Powered by {company name}" under the composer.
show_online_indicatorfalseAppearance › Online indicatorGreen dot in the chat header.
persist_history no effecttrueBehavior › Persist conversationHistory is kept either way.

Behaviour

KeyDefaultDashboard locationEffect
voice_enabledon — an untouched toggle counts as onBehavior › Voice callingChat / Voice switch. Only ever true when the assistant also has a voice agent.
handoff_modedisabledBehavior › Human handoffsupport, transparent or disabled.
office_hoursnoneBehavior › Office hoursTimezone, weekly ranges, offline heading and message, collect email.
allowed_domains not in the public configallow allBehavior › Allowed DomainsOrigin allowlist, enforced by the API.
ghlSync not in the public configoffBehavior › Sync conversations to GoHighLevelMirrors conversations into GHL.
ticketsEnabled not in the public configonno UIAllows this widget to create tickets.

26. Troubleshooting

First step for almost anything: open browser dev tools, go to the Network tab, reproduce the problem, and read the failing request. The widget deliberately shows generic messages; the response body carries the real reason.

SymptomLikely causeWhat to check and fix
Nothing renders at all The configuration call failed, or the identity check rejected it. Console will show widget_config_http_error, widget_config_timeout or widget_config_network_error. Confirm the widget is not archived, that it has an assistant assigned, and that data-api-url is reachable from the visitor's network.
The widget loads but every message fails The embedding domain is not on the allowed list, or the rate limit was hit. Look for 403 origin_not_allowed or 429 on the chat request. Remember a wildcard *.example.com does not cover the bare example.com. An empty allowlist allows everything, so this only bites once someone has filled it in.
Edits in the dashboard do not show on the site Caching, or an old widget script on the page. Wait a minute and hard-refresh: configuration is cached about 30 seconds in the browser and up to 5 minutes on the server. If a whole feature is missing rather than a setting, the page may be loading an old copy of the widget script.
The tabs are missing Only one tab is visible, or the visitor is inside a conversation. The nav bar hides itself when a single tab would show, and it is always hidden inside a conversation and the bug reporter. Turn on a second tab under Tabs & content.
All the action card icons look the same The icon names are not recognised, so every card falls back to the generic bubble. The Icon box is free text with no validation. Use lucide names in kebab-case: bug, lightbulb, smile, help-circle, alert-triangle, package, credit-card, calendar, star, zap. Watch the live preview: if the icon does not change as you type, the name is wrong.
An action card is missing from the widget Not saved, dropped as invalid, or cached. Did the save actually succeed? One broken card blocks the whole save. A card with no title is silently dropped when the configuration is served. Otherwise wait a minute and hard-refresh.
Suggested prompts vanished from Home You added an action card. Prompt chips only render on Home when there are no action cards at all, and only the first two of them. They still appear inside an empty chat.
The form says "Sorry, that didn't go through" The server rejected the submission. Read the response body of actions/submit. Missing required field: X means an empty required field or a stale config. action_not_form_mode or action_not_found means a cached config or a deleted card: wait a minute or re-save the widget. tool_not_allowed means the destination value is not one of the supported ones, usually a typo made in the JSON editor.
The form succeeded but nothing reached the other system Saved and delivered are separate. The forward failed after the save. Read the delivery error code. GHL: ghl_not_connected, email_or_phone_required (nothing mapped to email or phone), ghl_tag_failed (contact created, tag not added, so the workflow never fired). Webhook: one attempt, no retries, must be public HTTPS returning 2xx within 8 seconds with no redirect.
A ticket went missing, or landed in the wrong place Routing precedence and silent fallback. The order is Zendesk, then Gleap, then the Assistable inbox, and a Zendesk failure falls back silently. Check the ticket's destination. The dropdown label "(Zendesk)" is misleading: the destination works with nothing connected.
A second report from the same visitor never appeared Deduplication. There is one open ticket per conversation. A repeat request updates the existing ticket and appends to the conversation instead of filing a duplicate. A new ticket only opens once the previous one is resolved.
NPS or rating responses seem to vanish A submission that is only a rating creates no Inbox conversation, unless its destination is a support ticket. Add an optional comment field so submissions create Inbox threads, or subscribe to the widget.form.submitted webhook event.
Visitors cannot see their past conversations A failed sessions lookup looks identical to an empty history. Check /api/v1/widget/sessions in the network tab. History is keyed on a per-browser visitor id, so clearing site data loses it unless an email was captured. Only the 30 most recent are returned.
"Talk to a human" is not showing Handoff is off, is set to Stay silent, or the visitor already sent a message. Handoff must be on with mode Show it, and the chip only appears before the visitor's first message. Outside office hours it is replaced by the email capture card.
The widget says we are offline during working hours Wrong timezone, or a day left unticked. Office hours use the timezone in the editor, not the visitor's. A day with no ticked range counts as closed. Note the rules fail open, so an invalid timezone shows you as available rather than offline.
The Chat / Voice switch is not there Voice is off, or the assistant has no voice agent. Both must be true. The editor shows an amber warning on the Voice calling toggle when the assistant is missing a voice agent. The embed snippet cannot enable voice.
A call drops when the visitor goes back to Chat Expected. The call is torn down, not held. Tell visitors to use the red hang-up button.
Roadmap voting does not work It is not wired up. The arrow beside each count is decoration. Visitors cannot vote from the widget.
The published date is missing from News items It is never displayed. The date is used only to sort newest first. Put it in the summary if visitors need to see it.
Help search returns nothing Fewer than two characters, or the knowledge-base call is blocked. Knowledge-base search needs two characters and 300ms of quiet. It is the only widget call on the /api/v2/ path, so a proxy rule that allows only /api/v1/ breaks help search and nothing else.
Dark mode looks half-finished Known limitation. Home action cards and the chat composer keep light backgrounds in dark mode. Test before enabling.
The logo disappears when the chat opens Expected. The launcher only shows the logo while closed; open, it shows a chevron.
The teaser keeps coming back Expected. Dismissal is stored per browser tab session. To hide it permanently, clear the teaser greeting or add data-show-prompt="false" to the snippet.

27. How this guide was made, and what is not in it

Every screenshot and recording here was captured from a running stack: the Assistable v2 dashboard, the chat widget on an ordinary demo web page, and the API, all against a restored copy of production data. Nothing is a mock-up.

The first edition of this guide was written from a source reading that was never independently checked, and it shipped with errors, including an install snippet pointing at a host that serves no widget bundle. Every claim has since been re-verified against the code, the live configuration endpoint and the production database, and the corrections are folded in above. Where something could not be verified it now says so.

Two honest caveats