Docs
cxthread Website Widget
Add a support widget with one script tag, then tune live chat, business-hour fallback, and theme styling from your app.
Quick start
Start in Admin → Inboxes → choose inbox → Widget setup.
- 1) Generate or rotate a dedicated widget token.
- 2) Pick live chat behavior and business hours.
- 3) Copy the embed snippet into your website template.
- 4) Place the script before </body>.
- 5) Open your site and confirm the launcher appears.
Minimal embed
This is the smallest valid installation.
<script
src="https://YOUR_CXTHREAD_DOMAIN/cxthread-widget.js"
data-widget-token="cxwt_REDACTED"
></script>The widget runs in a hosted iframe to avoid CSS and JavaScript collisions with your site code.
Recommended embed (theme + runtime identity)
Use this when you have signed-in users and want full styling control.
<script>
window.cxtConfig = {
theme: {
themeMode: "auto",
primary: "#4a3dd6",
textOnPrimary: "#ffffff",
launcherLabel: "Support",
launcherCloseLabel: "Close",
borderRadius: 16,
frameBorderRadius: 16,
width: 380,
height: 640,
offsetX: 16,
offsetY: 16,
position: "right",
zIndex: 2147483000
}
};
</script>
<script
src="https://YOUR_CXTHREAD_DOMAIN/cxthread-widget.js"
data-widget-token="cxwt_REDACTED"
data-title="Support"
data-mode="auto"
></script>
<script>
window.cxt?.identify?.({
email: "signed-in@customer.com",
name: "Signed In Customer",
id: "customer_123"
});
</script>Mode behavior
data-mode="auto"
Uses workspace availability + business hours to decide between live chat and form fallback.
data-mode="form"
Always uses async ticket form behavior, even when agents are online.
Config precedence
- 1) Runtime API calls (for example window.cxt.setTheme()) take immediate precedence.
- 2) Script attributes (data-*) override matching config keys.
- 3) window.cxtConfig is the base config.
Keep static defaults in window.cxtConfig, then use runtime APIs when page state changes.
Script attributes
Required
- data-widget-token: widget token for the inbox.
Optional
- data-title: header title override.
- data-primary: primary hex color.
- data-mode: auto or form.
- data-position: left or right.
- data-open: set to true to start open.
- data-theme: JSON or URI-encoded JSON.
- data-theme-mode: auto, dark, or light.
- data-user-email, data-user-name, data-user-id: user prefill.
data-api-key is accepted as a legacy alias, but new installs should use data-widget-token.
Theme and styling
Theme values can be set from script attributes, config object, or runtime API.
Branding
- themeMode: auto/system, forced dark, or forced light.
- primary: launcher + primary action color (hex only, #RRGGBB).
- textOnPrimary: text on primary surfaces.
- launcherLabel: closed launcher text.
- launcherCloseLabel: open launcher text.
Shape and placement
- borderRadius: launcher radius (8–32).
- frameBorderRadius: frame radius (8–32).
- width: 280–720 px.
- height: 360–960 px.
- offsetX/offsetY: 0–72 px.
- position: left or right.
- zIndex: 1–2147483647.
Example theme payload:
window.cxtConfig = {
theme: {
themeMode: "auto",
primary: "#4a3dd6",
textOnPrimary: "#ffffff",
launcherLabel: "Need help?",
launcherCloseLabel: "Close",
borderRadius: 18,
frameBorderRadius: 16,
width: 380,
height: 640,
offsetX: 16,
offsetY: 16,
position: "right",
zIndex: 2147483000
}
};Runtime API
Use runtime methods when your app needs to open, close, or retheme the widget dynamically.
window.cxt.open();
window.cxt.close();
window.cxt.toggle();
window.cxt.isOpen();
window.cxt.getState();
window.cxt.setThemeMode("dark"); // "auto" | "dark" | "light"
window.cxt.setTheme({ primary: "#5b4bff" });
window.cxt.setPosition("left");
window.cxt.setUser({ email: "user@example.com", name: "User", id: "u_123" });
window.cxt.identify({ email: "user@example.com", name: "User", id: "u_123" }); // alias
window.cxt.clearUser();
const unsubscribe = window.cxt.onStateChange((state) => console.log(state));State changes also emit cxthread:widget:state on window.
window.addEventListener("cxthread:widget:state", (event) => {
console.log(event.detail);
});Late identity pattern
Use this when user identity is resolved after page load.
// Safe pre-load queue (before widget script is loaded):
window.cxt = window.cxt || {};
window.cxt.q = window.cxt.q || [];
window.cxt.q.push([
"identify",
{ email: "signed-in@customer.com", name: "Signed In Customer", id: "customer_123" }
]);
// Or after widget is loaded:
window.cxt?.identify?.({ email: "signed-in@customer.com", id: "customer_123" });identify, setIdentity, and setUser all map to the same behavior.
User identity and session
If you know the signed-in user, pass identity so tickets map back to real customers.
window.cxtConfig = {
user: {
email: currentUser.email,
name: currentUser.fullName,
id: currentUser.id
}
};- Session state is stored in a signed cookie for resume across page loads.
- Identity updates via setUser() apply on the next interaction/open cycle.
- First live-chat message requires email unless you prefill one from your app.
Live chat behavior
- Live chat is available when the widget is enabled, mode is auto, and workspace availability allows it.
- If “Require identity before first message” is enabled in Admin, visitors are prompted for name then email in-chat before the first message is routed.
- When live chat is not available, the widget uses async ticket-form flow.
- Live stream reconnects automatically after transient failures.
- Messages stay attached to one ticket thread by ticket token + widget session ID.
Slack integration
- Widget inbound messages post to the ticket Slack thread.
- Admin ticket live-chat sends are mirrored to both widget and Slack.
- cxthread Slack actions are mirrored to widget for widget-linked tickets.
- Internal notes are never sent to widget visitors.
Troubleshooting
Widget does not render
Verify the script is loaded and data-widget-token is present.
Invalid token errors
Regenerate the widget token in Admin and update your site embed.
Theme not applying
Confirm color values are six-digit hex and data-theme is valid JSON.
Current limitations
- No typing indicators yet.
- No launcher unread badge yet.
- File upload in widget chat is not implemented yet.
- Generic manual Slack thread replies are not auto-mirrored unless sent through cxthread actions.
Security notes
Widget tokens are browser-visible by design. Rotate tokens if they are leaked or abused.
For stricter control, call the server-side API from your backend instead of direct browser widget calls.