Skip to main content

Embedding Agents as Widgets

Xagent can expose an agent through an embeddable widget flow for website or product integration.

How widgets work

The widget flow is guest-oriented. A client:
  1. Authenticates a guest against a specific agent
  2. Receives a guest chat token
  3. Uploads files if needed
  4. Creates a widget chat task
  5. Continues the session over the public chat runtime
This is different from owner chat and different from public share links, even though all three rely on the same core task execution system.

Agent-level widget controls

Agents now expose widget-related settings:
  • widget_enabled
  • allowed_domains
That means widget access is not global. It is controlled per agent.

Domain allowlist

The widget authentication flow validates the request origin against the agent’s allowed domains. Use this to restrict where the widget can be embedded:
  • Exact domains
  • Subdomains
  • * for unrestricted access, only if you deliberately want that behavior
For production use, prefer a strict allowlist. For a production widget agent:
  • Use a focused prompt
  • Keep tools narrow and predictable
  • Add safe suggested prompts
  • Restrict allowed domains
  • Test guest file uploads and session continuity

Opening the chat from your page

The widget script, widget.js, adds a chat button and a chat panel to your page. Once it has loaded, your own page code can open that panel, and can optionally start a new conversation with a message you choose. A typical use is a button such as “Ask about pricing” that hands a prepared question to the agent.

Example

The page below embeds the widget and has two buttons. The first opens the chat with a prepared question. The second only opens the chat.
Use the embed snippet from the agent’s widget settings for the widget.js tag. The tag above shows only the attributes needed for this example.

Calling XagentWidget.open

options is optional. It is an object with one key:
  • message (string, optional): the text to send as the first message of a new conversation.
The call returns nothing, and it behaves as follows:
  • XagentWidget.open() opens the chat panel and sends nothing.
  • XagentWidget.open({ message }) opens the chat panel and starts a new conversation. If a conversation is already in progress, it is left behind and the new conversation starts instead. message is sent as the first message of the new conversation, and the agent starts answering it.
  • Every call takes effect, including when the panel is already open. The panel does not need to be closed first. If a visitor clicks a second button while the chat is open, the panel stays open and the second message starts another new conversation. Calls that arrive close together are covered under “Repeated and overlapping calls” below.
XagentWidget exists only after widget.js has loaded, so code that runs before the script has loaded cannot call it. Calling open from click handlers, as in the example, avoids this. If the page has no active widget, for example because the embed tag is missing its widget key, open does nothing except write a warning to the browser console.

Message rules

Leading and trailing whitespace is removed from message. What remains must not be empty and must not be longer than 2000 characters. If message is given but does not meet these rules, or is not a string, the panel still opens, no message is sent, and the browser console shows this warning:
A call with no message, or with message set to undefined, only opens the panel and shows no warning. Options other than message are ignored and are named in a browser console warning. Passing something that is not an object also opens the panel without sending a message, with a console warning.

Repeated and overlapping calls

  • Each call with a valid message starts a new conversation. The conversation that was replaced is not stopped: if the agent was still answering in it, the answer is completed in the background. The visitor cannot return to the earlier conversation from the chat panel.
  • Each call with a valid message also starts a new agent run, which counts toward usage in the same way as a conversation the visitor starts in the panel. The widget itself does not limit how often open can be called.
  • If the chat has not finished loading, the message is held and sent as soon as the chat is ready. When several calls are made before that, only the last message is sent.
  • If the chat is busy, for example because an earlier call is still starting its conversation or a message the visitor typed is still being sent, the message waits for its turn. Only one message can wait. A newer call replaces the one that is waiting, so when a visitor clicks several buttons quickly, the messages in between are skipped.
  • open does not retry a message. If the chat cannot start the new conversation or cannot deliver the message, the message is dropped. The chat then shows the same error notice it shows when the visitor’s own attempt fails in the same way, and a warning is written to the browser console.
  • Starting a new conversation discards any text the visitor typed into the chat input but did not send.
  • After open has been called with a valid message, that widget no longer sends the message set with its data-initial-message attribute. Calling open without a message leaves it unchanged. If the widget had already sent the data-initial-message text to the chat, for example because the panel opened a moment earlier or open() was called without a message just before, that text is not withdrawn: the chat starts a conversation with it as usual, and the message from open then starts a new conversation that replaces it.
  • If the page has more than one widget, the call goes to the most recently initialized one that is still on the page.
message is sent as if the visitor had typed it. Pass only text that you wrote into the page. Do not build it from URL parameters or any other input that a visitor can control. Call open only in response to a visitor action such as a click, and not when the page loads or from code that re-runs on every render, because every call with a message starts a new conversation and a new agent run.
Use a widget when:
  • The agent is embedded into your product or site
  • You need origin checks
  • The conversation is part of a product experience
Use a share link when:
  • You want a public standalone entry point
  • The interaction is link-driven rather than embedded