> ## Documentation Index
> Fetch the complete documentation index at: https://cntillion.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat bubble controls

> Open, close and reset the website chat, override its display options, and listen for events

The [website embed script](https://cntillion.com/docs/channels/website.md) exposes `window.centillion`.
Use it to connect your own buttons to the chat or change its presentation for
the current page. Use the snippet from **Channels → Install → Website widget**,
with `embed.js?v=10` or newer.

## Open, close and reset

```javascript theme={null}
window.centillion.open();
window.centillion.close();
window.centillion.resetChat();
```

`close()` preserves the conversation and unsent text. `resetChat()` clears the
conversation, draft and attachments, ends any active voice call, and starts a
new session. It preserves the visitor's identity and runtime overrides,
including custom initial messages. It does not delete stored conversation
records or tickets.

A published conversation stays on the release where it started. Resetting it
reloads the chat iframe and starts a conversation using the current
[release traffic allocation](https://cntillion.com/docs/agents/releases-and-workflows.md), including that
release's saved greeting and appearance. The embed script reapplies runtime
overrides after the iframe reloads.

If [A/B testing](https://cntillion.com/docs/channels/website.md#ab-testing) excludes the visitor, `open()`,
auto-open and runtime options leave the widget hidden. Resetting the chat does
not change the visitor's assignment. Use **100%** or disable testing in
**Display → A/B testing** to include every visitor while checking your controls.

### Open with a message

```javascript theme={null}
window.centillion.open({ message: "How do I track my order?" });
```

The chat opens and sends the message. Messages must be non-empty strings of at
most 12,000 characters. Only one message can be in progress at a time.

For proactive help, hide the prompt until an answer arrives:

```javascript theme={null}
window.centillion.open({
  message: "Offer help choosing a plan for this pricing page.",
  hideMessage: true,
});
```

The prompt stays in the agent's conversation history but is hidden from the
visitor. A closed bubble opens when the answer becomes available. Closing or
resetting the bubble while waiting cancels that automatic opening. Failed
requests leave the bubble closed and emit an `error` event. `hideMessage` has
no effect without `message`.

## Runtime options

```javascript theme={null}
window.centillion.setOptions({
  displayName: "Acme Support",
  bubbleText: "Need help?",
  footer: "Support from Acme",
  messagePlaceholder: "Ask us anything…",
  dismissibleNotice: "Chats may be recorded for quality purposes.",
  initialMessages: ["Hi!", "How can I help you today?"],
  suggestedMessages: ["Track my order", "Talk to a human"],
  dictationOnly: true,
  dictationTimeout: 1000,
  hideActionsMenu: true,
  dictationWaveformColor: "#FF0000",
});
```

All fields are optional. Overrides affect this page load only. They never save
changes to your agent. Reloading the host page clears them.

| Option | Accepted value and behavior |
| - | - |
| `displayName` | String, up to 100 characters. Changes the chat title, frame title and launcher accessibility label. Empty restores the title fallback. |
| `bubbleText` | String, up to 40 characters. Non-empty text shows even if the dashboard hides launcher text. An empty string hides the label, leaving a usable icon button. Text clips on narrow screens and follows its own reading direction. The dashboard still controls icon placement. |
| `footer` | String, up to 1,000 characters. Replaces the custom footer. An empty string removes it. The Centillion attribution is separate. |
| `messagePlaceholder` | String, up to 100 characters. Replaces the message input placeholder, including an empty string. |
| `dismissibleNotice` | String, up to 500 characters. Replaces the notice. An empty string removes it. Visitors can dismiss the new notice. |
| `initialMessages` | Array of non-empty strings, at most 1,000 characters total. Applies immediately before a conversation starts, or after the next reset. An empty array suppresses greetings. |
| `suggestedMessages` | Up to four non-empty strings, at most 200 characters each. Replaces dashboard suggestions. An empty array removes them. Suggestions returned by an action still take precedence. |
| `dictationOnly` | Boolean. Hides typing, send, attachments and the voice-call button. Dictated messages send automatically when dictation stops. If dashboard dictation is off, the composer disappears. Messages and suggestions remain available. |
| `dictationTimeout` | Positive safe integer in milliseconds. Stops dictation after silence following speech. It never starts the silence countdown before the visitor speaks. Without this option, dictation stops manually or at the two-minute limit. |
| `hideActionsMenu` | Boolean. Hides the header's ticket menu, reset and delete-conversation controls. The JavaScript methods remain available. |
| `dictationWaveformColor` | Three- or six-digit hex color, such as `#F00` or `#FF0000`. Colors the speech activity indicator while dictating. The default is gray. |

Invalid fields log a `console.error` and leave their previous values intact.
Valid fields in the same call still apply. `setOptions()` rejects oversized
values instead of truncating them.

### Reset overrides

```javascript theme={null}
// Clear every runtime override and use the agent's defaults.
window.centillion.resetOptions();

// Restore only these fields; keep the other overrides.
window.centillion.resetOptions({ displayName: true, footer: true });
```

Resetting options does not reset the conversation. Runtime-only options revert
to their defaults. Changes to initial messages appear in the next fresh chat
if a conversation has already started.

### Individual setters

```javascript theme={null}
window.centillion.setDisplayName("Acme Support");
window.centillion.setBubbleText("Need help?");
window.centillion.setFooterText("Support from Acme");
window.centillion.setMessagePlaceholder("Ask us anything…");
window.centillion.setDismissibleNotice("Chats may be recorded.");
window.centillion.setSuggestedMessages(["Track my order", "Talk to a human"]);
window.centillion.setInitialMessages(["Hi!"]);
window.centillion.setDictationOnly(true);
window.centillion.setDictationTimeout(1000);
window.centillion.setHideActionsMenu(true);
window.centillion.setDictationWaveformColor("#FF0000");
```

Each setter behaves like `setOptions()` for that field, with one exception.
`setInitialMessages()` truncates the array's text to 1,000 characters in order.
`setOptions({ initialMessages })` rejects an oversized array. Both methods write
the same override, so the last valid call wins.

### Dictation and voice calls

Dictation uses the browser's speech recognition, separate from a live voice
call with the agent. Enable **Voice to text (Dictation)** under **Display**.
Visitors start recording themselves and grant microphone permission. In the
normal composer, the transcript goes into the message box for review. With
`dictationOnly: true`, stopping dictation sends it as a chat message.

Browser speech recognition support varies. Unsupported browsers show
"Dictation is unavailable in this browser." They can still use the normal text
composer unless you hide it with `dictationOnly`. Microphone permission errors
appear beside the dictation button. Inline frames need `allow="microphone"`.
A reset discards unfinished dictation and releases the microphone.

## Events

```javascript theme={null}
function onOptionsChanged(event) {
  console.log("Options are rendered", event.data.options);
}

window.centillion.addEventListener("optionsChanged", onOptionsChanged);
window.centillion.setDictationOnly(true);

// Later, when your component unmounts:
window.centillion.removeEventListener("optionsChanged", onOptionsChanged);
```

Every callback receives `{ type, data }`. Register listeners before the
operation you want to observe. Reapplying an unchanged value emits no change.
Updates React renders together produce one `optionsChanged` event with the
resulting overrides.

| Event | When it fires and its data |
| - | - |
| `ready` | The iframe first accepts controls. It loads when opened or when a control needs it. This host API event does not repeat after a reset. |
| `opened`, `closed` | The bubble changes visibility through its controls. |
| `optionsChanged` | After the chat renders runtime options. `data.options` contains active overrides. |
| `chatReset` | The reset control starts a reset. It does not confirm that a reloaded iframe is ready. |
| `user-message` | A message is accepted to send. `data` contains `{ content }`. A later send failure emits `error`. |
| `assistant-message` | An assistant answer finishes displaying. `data` contains `{ content }`. Greetings and restored history emit nothing. |
| `tool-result` | A custom action returns its result while the request is running. `data` contains `{ name, result, toolCallId, type: "tool-result" }`. |
| `error` | A message request fails. `data.message` describes the failure. |

Hidden prompts are visible to your event listeners. Avoid writing sensitive
message content to analytics or console logs.

### Reset after inactivity

```javascript theme={null}
let inactivityTimer;
function restartTimer() {
  clearTimeout(inactivityTimer);
  inactivityTimer = setTimeout(() => window.centillion.resetChat(), 5 * 60 * 1000);
}
window.centillion.addEventListener("user-message", restartTimer);
window.centillion.addEventListener("assistant-message", restartTimer);
```

Give visitors time to read the final response before resetting. For a reset after
a booking or another action, listen for `tool-result`, check `event.data.name`
and `event.data.result`, then schedule the reset.

### Custom buttons and navigation

```javascript theme={null}
document.getElementById("help-button").addEventListener("click", () => {
  window.centillion.open();
});
document.querySelectorAll(".faq-question").forEach((item) => {
  item.addEventListener("click", () => {
    window.centillion.open({ message: item.dataset.question });
  });
});

// Call from your SPA router's navigation callback when a fresh chat is useful.
function onSupportRouteEntered() {
  window.centillion.resetChat();
}
```

Debounce repeated message triggers, and respect a visitor's dismissal instead
of immediately reopening the bubble.

## Calls before the script loads

The API queues controls while its settings and iframe load. If your application
runs before the embed script itself, install this queue first:

```html theme={null}
<script>
  window.centillion = window.centillion || function () {
    (window.centillion.q = window.centillion.q || []).push(Array.from(arguments));
  };
  window.centillion("setOptions", { displayName: "Acme Support" });
  window.centillion("open");
</script>
<script src="https://app.cntillion.com/embed.js?v=10"
        data-centillion-agent="YOUR_AGENT_ID" defer></script>
```

After loading, both `centillion("open", options)` and
`centillion.open(options)` work. Existing `centillion("registerTools", tools)`
and the separate `Centillion("identify", identity)` API keep working.
Use one agent's embed script per page.

## Plain iframe controls

Without the embed script, `window.centillion` does not exist. Wait for the
iframe's `iframeReady` event, then post controls to its origin. Verify both the
sender window and origin before handling responses.

```javascript theme={null}
const agentUrl = new URL("https://app.cntillion.com/embed/YOUR_AGENT_ID");
const agentOrigin = agentUrl.origin;
const iframe = document.createElement("iframe");
iframe.title = "Support chat";
iframe.allow = "microphone";
iframe.style.cssText = "width:100%;height:700px;border:0";
iframe.style.visibility = "hidden";

window.addEventListener("message", (event) => {
  if (event.source !== iframe.contentWindow || event.origin !== agentOrigin) return;
  if (event.data?.type === "iframeReady") {
    iframe.contentWindow.postMessage({
      type: "setOptions",
      params: { dictationOnly: true },
    }, agentOrigin);
  }
  if (event.data?.type === "optionsChanged") {
    iframe.style.visibility = "visible";
  }
});
iframe.src = agentUrl.href;
document.getElementById("support-chat").append(iframe);
```

Use the same method names for `type`, and the method argument for `params`.
For example, post `{ type: "resetChat" }` to reset, or
`{ type: "open", params: { message: "Help me choose a plan" } }` to send a message.
`close` hides the chat content, and `open` shows it again. The parent page owns
the inline iframe's size and placement, including the space left when hidden.
Register the message listener before assigning the iframe's `src` or inserting
it into the page so you do not miss readiness. Messages sent before readiness
are not queued by a plain iframe.

A published chat reset reloads the iframe. Keep handling each `iframeReady`
event and resend your options after every reload. The listener above stays on
the host page and reapplies `dictationOnly` to the new conversation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.