Client SDK·续
const data = await response.json();
// POST request with body const response = await agentFetch( { agent: "DataAgent", name: "instance-1", host: "my-worker.workers.dev", }, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "process" }), }, );
```ts
import { agentFetch } from "agents/client";
// GET request
const response = await agentFetch({
agent: "DataAgent",
name: "instance-1",
host: "my-worker.workers.dev",
});
const data = await response.json();
// POST request with body
const response = await agentFetch(
{
agent: "DataAgent",
name: "instance-1",
host: "my-worker.workers.dev",
},
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "process" }),
},
);
When to use agentFetch vs WebSocket:
Use agentFetch |
Use useAgent/AgentClient |
|---|---|
| One-time requests | Real-time updates needed |
| Server-to-server calls | Bidirectional communication |
| Simple REST-style API | State synchronization |
| No persistent connection needed | Multiple RPC calls |
MCP server integration
If your agent uses MCP (Model Context Protocol) servers, you can receive updates about their state:
const agent = useAgent({
agent: "AssistantAgent",
name: "session-123",
onMcpUpdate: (mcpServers) => {
// mcpServers is a record of server states
for (const [serverId, server] of Object.entries(mcpServers)) {
console.log(`${serverId}: ${server.connectionState}`);
console.log(`Tools: ${server.tools?.map((t) => t.name).join(", ")}`);
}
},
});
const agent = useAgent({
agent: "AssistantAgent",
name: "session-123",
onMcpUpdate: (mcpServers) => {
// mcpServers is a record of server states
for (const [serverId, server] of Object.entries(mcpServers)) {
console.log(`${serverId}: ${server.connectionState}`);
console.log(`Tools: ${server.tools?.map((t) => t.name).join(", ")}`);
}
},
});
Error handling
Connection errors
const agent = useAgent({
agent: "MyAgent",
onError: (error) => {
console.error("WebSocket error:", error);
},
onClose: () => {
console.log("Connection closed, will auto-reconnect...");
},
});
const agent = useAgent({
agent: "MyAgent",
onError: (error) => {
console.error("WebSocket error:", error);
},
onClose: () => {
console.log("Connection closed, will auto-reconnect...");
},
});
RPC errors
try {
const result = await agent.call("riskyMethod", [data]);
} catch (error) {
// Error thrown by the agent method
console.error("RPC failed:", error.message);
}
try {
const result = await agent.call("riskyMethod", [data]);
} catch (error) {
// Error thrown by the agent method
console.error("RPC failed:", error.message);
}
Streaming errors
await agent.call("streamingMethod", [data], {
onChunk: (chunk) => handleChunk(chunk),
onError: (errorMessage) => {
// Stream-specific error handling
console.error("Stream error:", errorMessage);
},
});
await agent.call("streamingMethod", [data], {
onChunk: (chunk) => handleChunk(chunk),
onError: (errorMessage) => {
// Stream-specific error handling
console.error("Stream error:", errorMessage);
},
});
Best practices
1. Use typed stubs
// Prefer this:
const user = await agent.stub.getUser(id);
// Over this:
const user = await agent.call("getUser", [id]);
// Prefer this:
const user = await agent.stub.getUser(id);
// Over this:
const user = await agent.call("getUser", [id]);
2. Reconnection is automatic
The client auto-reconnects and the agent automatically sends the current state on each connection. Your onStateUpdate callback will fire with the latest state — no manual re-sync is needed. If you use an async query function for authentication, the cache is automatically invalidated on disconnect, ensuring fresh tokens are fetched on reconnect.
3. Optimize query caching
// For auth tokens that expire hourly:
useAgent({
query: async () => ({ token: await getToken() }),
cacheTtl: 55 * 60 * 1000, // Refresh 5 min before expiry
queryDeps: [userId], // Refresh if user changes
});
// For auth tokens that expire hourly:
useAgent({
query: async () => ({ token: await getToken() }),
cacheTtl: 55 * 60 * 1000, // Refresh 5 min before expiry
queryDeps: [userId], // Refresh if user changes
});
4. Clean up connections
In vanilla JS, close connections when done:
const client = new AgentClient({ agent: "MyAgent", host: "..." });
// When done:
client.close();
const client = new AgentClient({ agent: "MyAgent", host: "..." });
// When done:
client.close();
React's useAgent handles cleanup automatically on unmount.
React hook reference
UseAgentOptions
type UseAgentOptions<State> = {
// Required
agent: string; // Agent class name
// Optional
name?: string; // Instance name (default: "default")
host?: string; // Custom host
path?: string; // Custom path prefix
// Query parameters
query?: Record<string, string> | (() => Promise<Record<string, string>>);
queryDeps?: unknown[]; // Dependencies for async query
cacheTtl?: number; // Query cache TTL in ms (default: 5 min)
// Callbacks
onStateUpdate?: (state: State, source: "server" | "client") => void;
onMcpUpdate?: (mcpServers: MCPServersState) => void;
onOpen?: () => void;
onClose?: () => void;
onError?: (error: Event) => void;
onMessage?: (message: MessageEvent) => void;
};
Return value
The useAgent hook returns an object with the following properties and methods:
| Property/Method | Type | Description |
|---|---|---|
agent |
string |
Kebab-case agent name |
name |
string |
Instance name |
setState(state) |
void |
Push state to agent |
call(method, args?, options?) |
Promise |
Call agent method |
stub |
Proxy |
Typed method calls |
send(data) |
void |
Send raw WebSocket message |
close() |
void |
Close connection |
reconnect() |
void |
Force reconnection |
Vanilla JS reference
AgentClientOptions
type AgentClientOptions<State> = {
// Required
agent: string; // Agent class name
host: string; // Worker host
// Optional
name?: string; // Instance name (default: "default")
path?: string; // Custom path prefix
query?: Record<string, string>;
// Callbacks
onStateUpdate?: (state: State, source: "server" | "client") => void;
};
AgentClient methods
| Property/Method | Type | Description |
|---|---|---|
agent |
string |
Kebab-case agent name |
name |
string |
Instance name |
setState(state) |
void |
Push state to agent |
call(method, args?, options?) |
Promise |
Call agent method |
send(data) |
void |
Send raw WebSocket message |
close() |
void |
Close connection |
reconnect() |
void |
Force reconnection |
The client also supports WebSocket event listeners:
client.addEventListener("open", () => {});
client.addEventListener("close", () => {});
client.addEventListener("error", () => {});
client.addEventListener("message", () => {});
client.addEventListener("open", () => {});
client.addEventListener("close", () => {});
client.addEventListener("error", () => {});
client.addEventListener("message", () => {});
Chat from a non-React client
An AgentClient connection can drive an AI SDK chat UI in any framework. agents/chat/transport exports WebSocketChatTransport, which requires no React peer dependency:
import { AgentClient } from "agents/client";
import { WebSocketChatTransport } from "agents/chat/transport";
const transport = new WebSocketChatTransport({
agent: new AgentClient({
agent: "ChatAgent",
name: "user-123",
host: window.location.host,
}),
});
import { AgentClient } from "agents/client";
import { WebSocketChatTransport } from "agents/chat/transport";
const transport = new WebSocketChatTransport({
agent: new AgentClient({
agent: "ChatAgent",
name: "user-123",
host: window.location.host,
}),
});
Refer to Non-React clients for the behaviors this transport does and does not cover.
Agent-tool events
If your chat UI renders retained child runs from Agents as tools, use useAgentToolEvents() alongside useAgent() and useAgentChat(). The hook subscribes to the parent connection, replays retained child timelines, and groups runs by parent tool call ID.
import { useAgent, useAgentToolEvents } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });
import { useAgent, useAgentToolEvents } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });
Next steps
Routing
URL patterns and custom routing options.
Callable methods
RPC over WebSocket for client-server method calls.
Cross-domain authentication
Secure WebSocket connections across domains.
Build a chat agent
Complete client integration with AI chat.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/#page","headline":"Client SDK","description":"Connect to Cloudflare Agents from browsers or server runtimes using useAgent, AgentClient, and agentFetch.","url":"https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/communication-channels/chat/client-sdk/og.png?v=13b590d29d3efa8a","dateModified":"2026-09-15","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Connect agents to email so they can send outbound messages, process inbound mail, and handle follow-up replies. title: Email image: https://developers.cloudflare.com/agents/communication-channels/email/og.png?v=77c3698c2ed916ae
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt
Use this file to discover all available pages before exploring further.
Docs