Embed an Agent on Your Own Site

A hired AI agent does not have to live on a page SpiderPublish serves. It runs just as well on your own site — a React, Next or Vite app, or a hand-written HTML page on your own domain. That is what we call BYOS: Bring Your Own Site.

There are two ways in, and they produce the same agent:

Path

Use it when

You install

React SDK

your site is a React, Next or Vite app

@spideriq/agent-react from our npm registry

Script tag

anything else — plain HTML, WordPress, Webflow, a template you don't control

one <script> and one <div>, nothing to build

Both mount the same in-DOM web component. Neither uses an iframe.

Before you start

You need three things, in this order.

1. A hired agent, and its flow id. Agents are hired from the terminal — there is no "create an agent" screen in the dashboard, by design. See The CLI for the full flow; the short version is:

spideriq agent roster                      # agents you already own — re-embedding one is free
spideriq agent hire <id> --roster --origin https://your-site.com
spideriq agent list                        # your agents + the flow id for each

2. Your site's origin on the agent's allowed list. This is the single most common reason a correct-looking embed never says anything — see Allow your origin below.

3. The snippet, from the tool that owns it. Never hand-write the embed markup:

spideriq agent embed-snippet <flow_id> --mode inline

Path 1 — the React SDK

Point npm at our registry

@spideriq/agent-react is published to the SpiderIQ registry, not to public npm. Add a scope line to your project's .npmrc before installing, or the install fails with a 404 that looks like the package doesn't exist:

@spideriq:registry=https://npm.spideriq.ai

Then install. React 18 or newer is a peer dependency; the handshake package comes along automatically.

npm install @spideriq/agent-react

Mount it

import { SpiderAgent } from "@spideriq/agent-react";

export function Support() {
  return (
    <SpiderAgent
      flowId="…your agent flow id…"
      apiUrl="https://spideriq.ai"
      mode="inline"
    />
  );
}

That is the whole integration. The component renders a plain host <div> on the server and does every piece of browser work inside an effect, so Next.js and any other server-rendered framework are safe out of the box — no dynamic(..., { ssr: false }) wrapper needed.

Props

Prop

Type

What it does

flowId

string

The agent flow id. Required.

apiUrl

string

Origin the agent's configuration is fetched from — https://spideriq.ai unless you were told otherwise. Required.

mode

"inline" or "concierge"

inline fills the element you place it in and opens straight away. concierge is a floating launcher that opens a slide-over, anchored to the page rather than to your layout. Defaults to inline.

theme

object

Colour and shape tokens — see Theming below.

title

string

Heading inside the chat card.

subtitle

string

Sub-heading inside the chat card.

hideHeaders

boolean

Drop the in-card header entirely.

pageContext

boolean or string

Let the agent read the page it is on. Off unless set — see Page-Grounding.

className / style

Applied to the host wrapper element.

onReady

function

Called once the agent element is in the page, before the connection settles.

onError

function

Called with binding_unavailable or session_failed if the agent could not start. Render your own fallback here.

Changing flowId, apiUrl or mode starts a fresh agent. theme, title, subtitle and hideHeaders are read once when the agent mounts — change the component's key if you need to swap them live.

Bring your own interface

If you want the conversation but not our chat card, useSpiderAgent() gives you transport and state only. It mounts a hidden agent that renders nothing.

import { useSpiderAgent } from "@spideriq/agent-react";

function Chat() {
  const { state, ready, error, send } = useSpiderAgent({
    flowId: "…your agent flow id…",
    apiUrl: "https://spideriq.ai",
  });

  if (error) return <p>The assistant is unavailable right now.</p>;

  return (
    <>
      {state?.messages.map((m, i) => <Bubble key={i} msg={m} />)}
      <Composer disabled={!ready} onSubmit={send} />
    </>
  );
}

You get back state (the messages and whether a reply is in flight), ready, error, send, respondToWidget and getState. send does nothing until ready is true, so wiring a form to it early is harmless.

Path 2 — the script tag

Paste the snippet where you want the agent, and load the script once anywhere on the page:

<div data-spiderflow-flow="…your agent flow id…"
     data-spiderflow-kind="agent"
     data-spiderflow-mode="inline"></div>
<script src="https://embed.spideriq.ai/v1/loader.js" async></script>

The loader finds every element carrying data-spiderflow-flow and mounts it. One script tag serves any number of agents on a page.

For a floating assistant instead of an in-page panel, change the mode — the element can then live anywhere, since the agent anchors itself to the page:

<div data-spiderflow-flow="…your agent flow id…"
     data-spiderflow-kind="agent"
     data-spiderflow-mode="concierge"
     data-spiderflow-title="Ask us anything"></div>
<script src="https://embed.spideriq.ai/v1/loader.js" async></script>

Attributes

Attribute

What it does

data-spiderflow-flow

The agent flow id. Required.

data-spiderflow-kind

Must be agent. Without it the loader treats the element as a form and the agent never mounts.

data-spiderflow-mode

inline or concierge. popup is for forms and is rejected for agents.

data-spiderflow-title

Heading inside the chat card.

data-spiderflow-subtitle

Sub-heading inside the chat card.

data-spiderflow-hide-headers

Present to drop the in-card header.

data-spiderflow-page-context

Let the agent read the page — see Page-Grounding.

data-spiderflow-api

Only if you were told to point at a different API origin.

Allow your origin

The agent will only open a conversation for a browser on an origin you have registered. On any other origin the request to start a session is refused, and the visitor sees an agent that mounts and then stays silent.

Register the origin when you hire:

spideriq agent hire <id> --roster --origin https://your-site.com

Points worth knowing before you debug something else:

  • One origin is one scheme://host[:port] — no path. https://www.example.com and https://example.com are two origins, and so is http://localhost:5173.

  • Add your local development origin too, or the agent will work in production and appear broken on your machine.

  • Sites you host on SpiderPublish with a verified domain are already covered; this step is for domains we don't serve.

Theming

Pass colour and shape tokens and they are applied to the agent before it starts, so your values win over whatever the agent was configured with:

<SpiderAgent
  flowId="…"
  apiUrl="https://spideriq.ai"
  theme={{ primary: "#e11d48", radius: "12px" }}
/>

Short names are the token names without their prefix — primary becomes --opvs-agent-primary. A full custom property name is used exactly as you wrote it, so you can hand it any variable the agent understands.

Because the agent renders in your page rather than in an iframe, it inherits your fonts and sits in your stacking context. That is the point of the in-DOM mount: it looks like part of your site instead of a rectangle bolted onto it.

Where the session token lives

The short-lived session token the agent uses is held in a JavaScript closure and passed straight to the agent element. It is never written into an attribute, into the DOM, into React state or props, or into storage — so it cannot appear in your server-rendered HTML, in a React devtools tree, or in a DOM snapshot. Nothing you paste into your page contains a credential.

The configuration the embed fetches is filtered server-side before it is sent, so it carries identifiers and URLs only.

Check it on your own site

Do these in order — each one rules out the layer below it.

  1. Does the agent appear? If nothing renders, open the console. A 404 on the loader or the package means the script URL or the .npmrc registry line is wrong.

  2. Does it answer? Send a message and wait for a reply. Silence after a clean mount almost always means the origin is not on the allowed list — check the browser's network tab for the refused session request.

  3. **Does it answer as your agent?** Ask it something only your agent should know. If it answers generically, you are talking to a different flow id than you think.

  4. Does it work on the real domain? Test on the deployed site, not only on localhost — they are different origins, and the allowlist treats them that way.

Good to know

  • The same agent can sit on several sites. Add each origin; the flow id stays the same.

  • Re-embedding an agent you already own is free. spideriq agent roster lists them; hiring a new one is the billed path.

  • The agent is not in an iframe. It renders inside your page in a shadow root, which is why it can pick up your typography — and why Page-Grounding can let it read the page at all.

  • Never hand-compose the embed markup. Get it from spideriq agent embed-snippet — a hand-written attribute that is subtly wrong mounts nothing and reports nothing.

Next steps

  • Page-Grounding — let the agent read the page a visitor is looking at.

  • The CLI — hire an agent, allow a domain, list your agents.

  • MCP Setup — the same actions from an MCP-capable agent.

  • Agent Embed Protocol — the HTTP calls underneath both install paths, for a native app, a server-side proxy, or debugging.

Publish