Skip to main content
The widget is the zero-code way to put your agent on a website. A <fish-agent> custom element renders the complete experience — a floating launcher that expands into a voice-first chat card with live transcript, typing during the call, and inline tool activity — and a single script tag registers it. Under the hood it runs the same sessions as the Web SDK, so everything downstream (history, analysis, webhooks) works unchanged.

Prerequisites

  • An agent with a published version.
  • Public access enabled on the agent, with your site’s origin on the allowed-origins list — see Public agents. localhost and 127.0.0.1 count as different origins.
  • To keep the agent private instead, skip public access and supply session tokens from your backend with sessionTokenProvider.

Two-line embed

Add the element and the script anywhere on the page:
@fishaudio/agent-widget-embed is the widget pre-bundled as one IIFE file that registers <fish-agent> on load.

Install from npm

Bundlers can install the element instead: npm install @fishaudio/agent-widget, then call registerWidget() once. Importing the package has no side effects — registration happens only when you call it.

React

React apps get a real component: <FishAgentWidget> registers and renders the element with camelCase props, object props serialized for you, and the page events as callback props — clientTools is just a prop:
Every attribute below has a camelCase prop; dynamicVariables and textContents take objects, and onCall(options) still runs last for anything else. Importing the entry also types the raw <fish-agent> element in JSX, for pages that use the CDN script and install the package only for its types.

Attributes

Private agents

Keep the agent non-public and set sessionTokenProvider instead of an agent-id. It’s a JS property on the element (functions can’t be attributes), called before every session start: fetch the session token from your backend — with whatever auth headers, payload, or credentials the request needs — and return the JSON; it’s used verbatim.
React apps pass the same function as a prop:
Your backend holds the API key and creates the session with POST /v1/agent/sessions; origin checks, user auth, and rate limiting on that endpoint are yours. See Authentication for the token flow and a backend example.

Theming

Set CSS custom properties on the element. The widget’s internals live in a shadow root — page CSS can’t leak in, but every --fish-* token is public:
Also available: --fish-accent-text, --fish-bg, --fish-text, --fish-text-secondary, --fish-border, --fish-bubble-agent-bg/-text, --fish-bubble-user-bg/-text, --fish-danger, --fish-live, --fish-fab-size, --fish-font.

Page events

The element dispatches CustomEvents (bubbling, composed): Inbound: dispatch fish-agent:expand on the element or document to open the panel programmatically. Registering client tools is just the :call event (React apps pass the clientTools prop instead — same injection, wrapped):

Console settings and precedence

On load, the widget anonymously fetches the agent’s console widget settings from GET /v1/agent/agents/{agent_id}/widget — the same public-plus-origin gate as session creation, so it only answers for public agents to allowed origins. Settings resolve with a fixed precedence: HTML attribute > console widget config > built-in default. The endpoint being unreachable never breaks the widget — it renders from attributes and defaults.

Going further

Public agents

The public switch, origin allowlist, and rate limits behind the widget.

Authentication

The session-token flow your sessionTokenProvider implements.

Web SDK

The AgentSession API underneath the widget, for building your own UI.

Client tools

Let the agent trigger actions on the embedding page.