Website integration
Give this document to the colleague who owns the website or frontend, or paste it into a coding assistant as full integration context.
Source docs/en/site/sdk-host-site.md
Give this document to the colleague who owns the website or frontend, or paste it into a coding assistant as full integration context.
Full third-party handbook (A/B choice, Cadau prep, path B minting, acceptance and troubleshooting): [README.md](/docs/sdk-host-embed).
Path A static walkthrough site:
examples/cadau-embed-site/.
Note: a version with a real token and the current site URL is produced in Cadau My agents → Manage → Website embed after you generate a token, then click “Copy full text”.
1. What you get
- A: public site support — any site loads a conversation overlay with three pieces (Cadau URL, agent ID, embed token); no host backend; knowledge lives on that agent / workspace; with live support on, the widget can offer “Live support”.
- B: host business system — register/assign + backend mint + must pass the signed-in user (
host_actor); you can switch agents by signed-in user (see §4.3 and the HR example). - Conversation always goes through Cadau (
POST /api/v1/chat/stream); tokens can be revoked at any time. - (Optional)
mindlink://action/in-reply navigation; see §5.
2. Access credentials (path A three-piece set)
Token not filled yet: in Cadau My agents → Manage → Website embed click “Generate new token”. The full token string is shown only at generate time.
| Item | Value |
|---|---|
| Cadau site URL | https://your-mindlink.example.com |
| Agent | Sample assistant · (fill after you pick the agent on Website embed) |
| Website-embed token | (fill after generate) |
Notes
- You need not put workspace ID, app id, or expiry on the page (workspace comes from the token; if you omit
app_idit defaults tomindlink-embed). - Do not commit tokens to a public repo; if leaked, revoke on Website embed and issue a new one.
- Short-lived and long-lived tokens are both supported; long-lived can still be revoked.
MINDLINK_BASE_URL=https://your-mindlink.example.com
MINDLINK_USER_AGENT_ID=(agent instance ID)
MINDLINK_EMBED_TOKEN=(fill after generate)
MINDLINK_WIDGET_SCRIPT=https://your-mindlink.example.com/embed/mindlink-widget.min.js
3. Script URL
| Item | URL |
|---|---|
| Widget script | https://your-mindlink.example.com/embed/mindlink-widget.min.js |
base_url | https://your-mindlink.example.com |
The widget derives the API prefix as {base_url}/api/v1 (you can also pass api_base_url explicitly). Prefer same origin for script and API.
4. Page init (path A)
<script src="https://your-mindlink.example.com/embed/mindlink-widget.min.js"></script>
<script>
window.MindLinkWidget.init({
base_url: "https://your-mindlink.example.com",
user_agent_id: "(agent UUID)",
auth: { token: "(website-embed token)" }
});
</script>
data-\* auto-mount (optional; required data-base-url / data-agent-id / data-token; optional data-app-id, data-theme, data-position, data-entry, data-title, data-greeting, data-welcome). When you copy the script from Cadau Website embed, you can pick the entry: corner button only, a greeting on first visit, or open the conversation as soon as the page loads. data-position: bottom-right (default) / bottom-left / middle-right (right edge) / center (middle).
<script
crossorigin
src="https://your-mindlink.example.com/embed/mindlink-widget.min.js"
data-base-url="https://your-mindlink.example.com"
data-agent-id="(agent UUID)"
data-token="(website-embed token)"
data-app-id="mindlink-embed"
data-theme="auto"
data-entry="greeting"
data-title="Site support"
data-greeting="Ask me anything"
></script>
Live support and tickets: turn them on under that agent’s Live support, and assign seats in this workspace or authorize a support team. Next to the widget input you then get:
- “Live support”: someone chats with the visitor now (at least one support person covering this workspace must be on duty — a seat in this workspace, or a member of an authorized team who clocked on at the team desk). The visitor’s request enters the workspace live support queue.
- “Submit a ticket”: no need to wait for a person right now; it enters the workspace ticket queue. When nobody is on duty, only this remains. While waiting, the visitor can “Don’t wait — submit a ticket instead”.
Who can see conversations / live support / tickets
- A (unsigned website visitor): isolated by this browser. Opening again in the same browser is the same visitor; a different browser or cleared site data is a new visitor.
- B (signed-in host user): isolated by the current signed-in user. Pass
host_actorintoinit(on user switch,updateHostActor). User A cannot see B’s history, in-progress live support, or tickets. The same account in another browser is still that person.
Support staff work in the Cadau support desk (left: live support / tickets / hours). They do not need to refresh the whole page. When one support group covers several customer workspaces, use a support team (the team creates the group → the customer authorizes → listed in the service scope). Members switch to the team desk on the right of the support desk to take work; they need not change the top-bar current workspace. In user-facing copy, do not call live help a “ticket”. Mechanism: Cadau docs/core-mechanisms/人工客服.md.
Theme: default theme: auto (data-theme may be auto / light / dark). In auto, follow the host page html[data-theme], html/body.dark, otherwise the system light/dark; when the host theme changes, the widget follows.
When the API returns unauthorized / embed_token_revoked, issue a new token. When several people ask the same embed assistant at once, overflow returns embed_generation_limit (HTTP 429) and the widget says “Too many people talking right now. Try again in a moment.” The cap is set on that agent Manage → Embed assistant concurrent replies (if unset, the server default is 20; agent value 0 falls back to the server default when that default is > 0, and does not mean unlimited).
4.1 Optional: Web Component
<mindlink-widget
base-url="https://your-mindlink.example.com"
user-agent-id="ua_123"
theme="auto"
position="bottom-right"
></mindlink-widget>
<script>
const el = document.querySelector("mindlink-widget");
el.auth = { token: "…" };
</script>
HTML can also override app-id, api-base-url, workspace-id, and similar; auth / host_actor must be set in JS.
4.2 Optional: inline mount
window.MindLinkWidget.init({
base_url: "https://your-mindlink.example.com",
user_agent_id: "…",
auth: { token: "…" },
position: "inline",
container: "#my-assistant-host",
entry: { auto_open: true }
});
If a legacy host wants the entry in its own top bar / toolbar instead of a floating corner button:
const widget = window.MindLinkWidget.init({
/* …same credentials as above… */
position: "bottom-right",
entry: { hide_launcher: true },
});
document.querySelector("#host-assistant-btn")?.addEventListener("click", () => {
widget.open();
});
4.3 Path B: backend minting (business systems)
For a real business system, after the user is signed in the host backend should:
- Check host-side permissions and agent assignment;
- Call
POST /api/v1/user-agents/{id}/embed-tokenwith the Cadau integration account, putting the signed-in user’shost_actorin the body (written into the token registration; the browser cannot impersonate someone else); - Issue
access_tokenand the samehost_actorvia embed-session; - Browser
initmust passhost_actor(you may also passapi_base_url/app_id/workspace_id/expires_at). On signed-in user switch,updateHostActororinitagain.
Live support / tickets are the same as path A: the minted embed token is enough for the widget entries; do not build a support desk on the host. Turn live support on for the agent you are actually embedding (having it on for a static marketing site does not mean the business-system assistant has it). Assign seats in this workspace or authorize a support team, and have covering support on duty. Walkthrough: HR embed example §10.4.
Examples: HR embed example, examples/hr-multi-tenant/.
5. In-reply navigation (clickable links in AI replies)
5.1 How it works
- In the agent’s knowledge documents, agree: when a reply needs a jump, use a Markdown link plus the custom protocol
mindlink://action/. - After the user clicks, the embed widget emits an
actionevent to the host page (emit_event,kind: mindlink_action). - The host page whitelists the action name and query params in
executeHostAction, opens the matching page, and applies filters.
5.2 Link syntax
`link label`
- Action name: a business action you register on the host page; prefer
page.<module>ormodule.<module>. - Filter params: a standard URL query string, passed through to the host page after click (for example
status,id,q,tenant_id).
Examples (put in knowledge documents so the agent can copy them):
- `Open pending orders`
- `View customer detail`
- `Go to org chart`
- `Open dashboard filtered to this month`
Optional param label: for link copy or analytics only; the host page may ignore it.
5.3 Host-page whitelist (required)
Keep an action table on the host page and only run registered actions. Unknown actions should say “not supported yet”.
const HOST_ACTIONS = {
"page.orders": (params) => {
hostApp.navigate("/orders", {
status: params.status || "",
customer_id: params.customer_id || "",
});
hostApp.refreshList("orders");
},
"page.customer": (params) => {
hostApp.openCustomerDrawer(params.id);
},
"page.org": (params) => {
hostApp.navigate("/org", { tab: params.tab || "tree" });
},
"module.dashboard": (params) => {
hostApp.navigate("/dashboard", { range: params.range || "week" });
},
};
function executeHostAction(action, params) {
const fn = HOST_ACTIONS[action];
if (!fn) {
hostApp.toast("This navigation is not supported yet: " + (params.label || action));
return;
}
fn(params);
}
HR multi-tenant example: examples/hr-multi-tenant/web/src/mindlinkHostActions.ts (hash routes page.*).
5.4 Make the agent return navigation reliably
In Cadau, mount knowledge documents on that agent and include (writing spec: Host knowledge writing):
- List of pages that can be opened (page name, action name, available filter params and what they mean).
- Reply rules: when the user asks “where do I look / open this for me”, put 1–3
mindlink://action/links at the end of the body, with params matching the current context (for example the order id just mentioned). - Do not use unsafe protocols such as
javascript:.
Built-in Cadau main-site actions (main site only; host pages must map their own): module.workspace, module.chat, chat.new-session, and similar — see Help action links in the repo.
5.5 Structured actions (reserved, not delivered)
Widget event types include open_url / open_module / emit_event; the §4 samples can leave handlers for them. Current implementation: only mindlink://action/ in Markdown body fires action (emit_event + mindlink_action). The backend has not delivered structured action cards on the SSE stream (see Embed contract §5.4, §6.3).
5.6 Auto-navigation when the user clearly asks to open something
entry.auto_execute_navigation defaults to true. When the user message matches “open / jump / go to…” intent, after the assistant reply finishes streaming, the widget automatically runs the first mindlink://action/ link that is clickable on the embed surface in the body (skips main-site-only actions, same filter as a manual click; still goes through the host-page whitelist).
- Knowledge documents must say: when the user clearly asks to open something, still output 1–3 registered links, and the first host-executable link must be the most relevant target.
- To require a manual click, set
entry: { auto_execute_navigation: false }. - Host-side
widget.on("action", …)must already be implemented (§4), or auto-navigation does nothing.
6. Integration checklist
- The host page can load the widget and complete a first turn (
readyevent, streaming reply works). app_id, token,user_agent_id,workspace_idmatch “Access credentials” on this page.- (B)
host_actoris passed; two signed-in users cannot see each other’s history, live support, or tickets. (Host data-query isolation:Host agent run and data scope.) - (A) two website visitors cannot see each other’s history, live support, or tickets.
- Two visitors can ask the same embed assistant at once and each get a reply (they need not wait for each other); when overloaded the widget says “Too many people talking right now. Try again in a moment.”
- When the agent reply contains
mindlink://action/links, a click triggers host-page jump / overlay / list filter. - When the user says “open xx page for me”, after the reply the host receives
actionand runs it (auto_execute_navigationnot turned off). - (Optional) live support is on: the widget has “Live support” (someone must be on duty) and “Submit a ticket”; the support desk sees new items without a full page refresh. Seats in this workspace or an authorized support team can take work; the team desk does not change the top-bar current workspace.
- Unknown actions have a friendly message; arbitrary scripts are not run.
- After token expiry,
updateAuthrestores; after revoke, old tokens returnembed_token_revoked. - (Production) tokens are minted on the server; static frontend pages do not contain long-lived plaintext tokens.
7. More of the contract
Event names, TypeScript types, error codes, and security bounds: same directory Embed contract (V1.5.12).