Connect
Build your UI or bot
Flary provides the agent backend. Your application owns the screen, bot, or channel that people use. Start with the React console or Web Component, or use the typed client from your own UI. The Worker exposes HTTP, WebSocket, and SSE interfaces.
Use the client API
Choose Agent backend in flary create. The deployed Worker provides typed HTTP, WebSocket, and
SSE APIs. You do not write a route for each agent action.
Use the typed client from a trusted server:
import { flary } from "flary/client";
import type { functions } from "../worker/src/index";
const api = flary<typeof functions>({
baseUrl: "https://my-agent.example.workers.dev",
headers: () => ({ authorization: `Bearer ${token}` }),
});
Do not place a personal backend token in public browser code. Use your application session, a trusted server route, or the dashboard’s secure cookie.
Use the ready React console
Flary ships the same WebSocket console that the dashboard starter uses. It includes thread creation and deletion, replay, reconnect, optimistic messages, one ordered activity rail, tool details, approvals, interruption, and the composer.
import { flary } from "flary/client";
import { FlaryAgentConsole } from "flary/react";
import type { functions } from "../worker/src/index";
const api = flary<typeof functions>({
baseUrl: "/api/flary",
headers: getApplicationSessionHeaders,
});
export function AgentPanel() {
return <FlaryAgentConsole agent={api.support} title="Support agent" />;
}
The component does not copy the session into application storage. Flary stays the session authority. The browser stores only the newest replay cursor.
Embed the Web Component
The starter can serve a small custom element for an existing HTML page:
<flary-chat title="Support assistant"></flary-chat>
<script src="https://YOUR-WORKER.workers.dev/widget.js"></script>
The generated /widget.js script creates threads and sends messages through the deployed Worker.
The starter widget uses a temporary visitor identity for its demo. Add your application identity, an
origin allowlist, rate limits, or Turnstile before you expose it to high-traffic users. Do not put a
personal backend token or provider key in the page.
Style the outer shell or build your own view from the same hook:
import { useFlaryThread } from "flary/react";
const state = useFlaryThread({ thread });
// state.turns, state.send(), state.interrupt(), state.approve()
Build your own web UI
Store two values in the UI:
- The Flary thread ID.
- The last event cursor that the UI received.
Open the saved thread, send a message, and resume after the saved cursor:
const thread = await api.support.threads.open({ threadId });
await thread.send({
message: form.message,
idempotencyKey: form.requestId,
});
for await (const event of thread.stream({ after: savedCursor })) {
render(event);
saveCursor(event.cursor);
}
Use thread.connect() when the UI needs bidirectional WebSocket control. The connection uses one
short-lived ticket, resumes from a durable cursor, and can sleep with its Thread Control Durable
Object. SSE is the read-only fallback.
Telegram, Discord, CMS, or webhook
The adapter is small:
- Authenticate the incoming user or service.
- Map the external conversation to a Flary thread ID.
- Send the message with an idempotency key.
- Save the newest durable cursor.
- Deliver public events back to the channel.
Do not store model or tool credentials in the channel. The Flary Worker resolves them after it validates the tenant identity.
Read Threads and realtime clients for all thread controls and HTTP API and events for route-level integration.