Embed guide
The widget is a single script tag that mounts an isolated chat panel on your page. This page lists every attribute it accepts and every method it exposes.
The script tag
<script src="https://your-dashboard-origin/widget.js" data-agent="your-agent-public-key" async ></script>
Copy it from the Deploy tab rather than typing it: the tab fills in your agent's public key, a 32-character hex string, and points src at the origin serving your dashboard.
The widget renders inside a <div id="midnight-chat-widget"> with an open shadow root. Your page's CSS cannot leak in and the widget's cannot leak out, so it looks the same on a Tailwind site and a 2009 stylesheet.
Attributes
Only data-agent is required. Without it the widget logs an error and does not mount.
| Attribute | Value | Default |
|---|---|---|
data-agent | Your agent's public key. | Required |
data-api | Origin of the chat API. | Baked into the bundle at build time. Only set this if you self-host the API. |
data-open | Set to true to open the panel on load. | Closed |
data-accent | Any CSS colour for the launcher and buttons. | Your agent's configured accent, else #6366F1 |
data-locale | One of en, es, pt, de, fr, hi, ar. | Your agent's configured locale, else the browser's language, else English |
data-proactive | Seconds to wait before showing a teaser bubble. | Off |
Arabic renders right-to-left automatically. An unrecognised locale falls back to English rather than failing.
data-name, data-message, and data-branding attributes, but they exist for previews and demos — do not use them in production, where they only drift from the dashboard.JavaScript API
The script defines a global midnightchat() function taking a command name and arguments.
midnightchat("open"); // open the panel
midnightchat("close"); // close it
midnightchat("identify", { /* traits */ }); // see Identity verification
midnightchat("on", "message_sent", (data) => {
console.log("visitor asked:", data.text);
});Calls made before the bundle finishes loading are not lost. Queue them and they replay on load:
window.midnightchat = window.midnightchat || function () {
// Push a real array, not `arguments` — the widget replays each queued
// entry with .slice(), which an arguments object does not have.
(window.midnightchat.q = window.midnightchat.q || []).push([...arguments]);
};
midnightchat("open"); // safe even if widget.js hasn't loaded yetEvents
Subscribe with midnightchat("on", event, handler). An exception thrown inside your handler is swallowed and will not break the widget.
| Event | Payload | Fires when |
|---|---|---|
open | — | You called midnightchat("open"). |
close | — | You called midnightchat("close"). |
opened | — | The visitor opened the panel themselves. |
closed | — | The visitor closed the panel themselves. |
message_sent | { text } | The visitor sent a message. |
message_answered | — | The agent finished answering. |
message_error | { code } | The message failed. |
identify_verified | the traits you passed, including user_hash | An identify call was accepted. |
identify_rejected | the traits you passed, including user_hash | An identify call was rejected. |
lead_submitted | — | The visitor submitted the lead form. |
lead_error | { code } | The lead form failed. |
identify_verified and identify_rejected receive the traits you passed, which include user_hash. That value is a credential — do not forward these payloads wholesale to analytics or logging. Read the fields you need instead.open and close fire only for your own programmatic calls. opened and closed fire when the visitor clicks. They are not aliases, so analytics that listens only to open will miss every real visitor. Subscribe to both.Sharing without embedding
Every agent also has a hosted page at /a/<public-key> with the widget already open — useful for testing, for sharing with a colleague, or as a support link when you have nowhere to paste a script tag. Enable it with the share setting on the agent.
Troubleshooting
| Symptom | Cause |
|---|---|
| Nothing renders, console says missing data-agent | The script tag has no data-agent attribute, or the key was truncated when pasted. |
Panel opens, first message fails with origin_not_allowed | Your domain is not on the agent's allow-list. Add it, including the exact scheme and port used in development. |
Errors mentioning token_origin_mismatch | The session token was issued to a different origin than the one now calling. This usually means the page moved between origins, for example a redirect from apex to www. |
| Works locally, fails when deployed | The deployed origin is a different one. Allow-list entries accept bare hosts, wildcards such as *.example.com, or full origins. |