All docs

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.

ItemValue
Cadau site URLhttps://your-mindlink.example.com
AgentSample 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_id it defaults to mindlink-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

ItemURL
Widget scripthttps://your-mindlink.example.com/embed/mindlink-widget.min.js
base_urlhttps://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_actor into init (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:

  1. Check host-side permissions and agent assignment;
  2. Call POST /api/v1/user-agents/{id}/embed-token with the Cadau integration account, putting the signed-in user’s host_actor in the body (written into the token registration; the browser cannot impersonate someone else);
  3. Issue access_token and the same host_actor via embed-session;
  4. Browser init must pass host_actor (you may also pass api_base_url / app_id / workspace_id / expires_at). On signed-in user switch, updateHostActor or init again.

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

  1. In the agent’s knowledge documents, agree: when a reply needs a jump, use a Markdown link plus the custom protocol mindlink://action/.
  2. After the user clicks, the embed widget emits an action event to the host page (emit_event, kind: mindlink_action).
  3. 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> or module.<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):

  1. List of pages that can be opened (page name, action name, available filter params and what they mean).
  2. 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).
  3. 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 (ready event, streaming reply works).
  • app_id, token, user_agent_id, workspace_id match “Access credentials” on this page.
  • (B) host_actor is 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 action and runs it (auto_execute_navigation not 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, updateAuth restores; after revoke, old tokens return embed_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).