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

Client SDK·续 - 图1Docs

{"@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


Skip to content

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.