Embedding: an agent on your own site
Put a chat with an Agentfy agent on a page you own. The visitor needs no account here, installs nothing, and never leaves your site.
This section is written for the person doing the installing — someone with a website and an agent, not someone with this repository.
What embedding actually is
Three participants, and only the middle one is new:
visitor's browser ──► the hub ──► the agent
your page one port runs a turn
one <script> WebSocket answers back- The visitor's browser loads a small widget from a script tag on your page.
- The hub is the one address that browser talks to. By default the hub is the Agentfy api itself, on a port of its own — so a normal installation needs no second service. See What you need on the server.
- The agent is yours: the same agent you talk to in the cabinet, with the same instructions and the same knowledge.
The connection is a WebSocket, and the answer arrives token by token — the visitor watches the reply appear rather than waiting for it.
Three ways in
All three talk to the same hub and the same agent. They differ only in how much of the interface is yours.
1. A script tag, and a floating bubble
One block pasted into your page template. A button appears in the bottom-right corner; pressing it opens the chat. Nothing to build, nothing to install — this works on a WordPress theme and on hand-written HTML alike.
<script>
(function () {
var sdk = document.createElement('script')
sdk.src = 'https://bridle.cleanslice.org/sdk/latest.js'
sdk.onload = function () {
window.Bridle.init({
apiUrl: 'https://hub.example.com',
agentId: 'agent-…',
token: '<the ticket from the cabinet>',
mode: 'floating',
title: 'Support',
})
}
document.head.appendChild(sdk)
})()
</script>Copy it from the cabinet, not from here
The cabinet assembles this block for you — the agent's screen «Сайт», the Copy button. What it gives you is slightly longer: it adds the function that exchanges the page's ticket for a per-visitor one, so that two people who open your site do not end up in one conversation. That difference matters and is explained under Two kinds of ticket.
2. A package in your build
If your site has a build — Vite, Next, Nuxt, Webpack — the widget installs as a package and is called from code. That buys you two things the script tag cannot give: the chat can be mounted into a specific place on the page instead of hanging in a corner, and the token can be a function, which is asked again on every reconnect.
npm i @cleanslice/bridleimport { init } from '@cleanslice/bridle'
init({
apiUrl: import.meta.env.VITE_HUB_URL,
agentId: 'agent-…',
token: () => fetch('/api/agent-token').then((r) => r.json()).then((t) => t.token),
mount: '#chat',
mode: 'inline',
title: 'Support',
})3. Your own interface, over the client
You can skip the shipped widget entirely. The client gives you a connection and events — typing, a piece of the answer arrived, the answer is finished — and what it all looks like is your markup. This is how a chat goes into an interface that is already designed: a support panel, a product card, a mobile app.
import { BridleClient } from '@cleanslice/bridle'
const client = new BridleClient({ apiUrl, agentId, token })
client.on('typing', () => showTypingIndicator())
client.on('stream', (m) => renderPartial(m.text))
client.on('stream_end', (m) => commit(m.text))
client.on('message', (m) => commit(m.text))
client.on('error', (e) => showError(e.code))
await client.connect()
client.send('Hello')All three run side by side on one page in the demo.
What the visitor sees
A chat window with your agent's name on it. They type; a typing indicator appears; the answer streams in. Nothing identifies them to us, and nothing about them is asked for.
What they do not see is as deliberate as what they do:
- not the reasoning, and not the steps the agent took;
- not the tools it called, nor what those tools returned;
- not the agent's other conversations — theirs is a thread of its own.
The widget renders inside a shadow root, so your site's CSS cannot leak into it and its CSS cannot leak into your site.
What it will not do, and why
An external conversation is deliberately narrower than the owner's own. By default the agent answering your visitors has no hands, writes nothing to its long-term memory, and cannot re-time its own scheduled work. Every one of those can be lifted, one at a time, by the agent's owner — and each is worth understanding before it is.
That is Boundaries and rights, and it is the page to read before you open anything.