Client tools
Client tools let your backend agent delegate work to the browser. When the agent calls a client tool, ChatKit pauses the response until your UI resolves
onClientTool
.
Use this option to reach APIs that only exist in the browser (local storage, UI state, hardware tokens, etc.) or when client views need to update in step with server-side changes. Return a JSON-serializable payload back to the server after you’re done.
Lifecycle overview
Section titled “Lifecycle overview”- Configure the same client tool names on your backend agent and in ChatKit.
- ChatKit receives a tool call from the agent and invokes
onClientTool({ name, params })
. - Your handler runs in the browser and returns an object (or
Promise
) describing the result. ChatKit forwards that payload to your backend. - If the handler throws, the tool call fails and the assistant gets the error message.
Register the handler in your UI
Section titled “Register the handler in your UI”import { ChatKit, useChatKit } from '@openai/chatkit-react';import type { ChatKitOptions } from '@openai/chatkit';
type ClientToolCall = | { name: 'send_email'; params: { email_id: string } } | { name: 'open_tab'; params: { url: string } };
export function SupportInbox({ clientToken }: { clientToken: string }) { const { control } = useChatKit({ api: { clientToken }, onClientTool: async (toolCall) => { const { name, params } = toolCall as ClientToolCall;
switch (name) { case 'send_email': const result = await sendEmail(params.email_id); return { success: result.ok, id: result.id }; case 'open_tab': window.open(params.url, '_blank', 'noopener'); return { opened: true }; default: throw new Error(`Unhandled client tool: ${name}`); } }, } satisfies ChatKitOptions);
return <ChatKit control={control} className="h-[600px] w-[320px]" />;}
const chatkit = document.getElementById('chatkit');
chatkit.setOptions({ api: { clientToken }, async onClientTool({ name, params }) { if (name === 'get_geolocation') { const position = await new Promise<GeolocationPosition>((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject); }); return { latitude: position.coords.latitude, longitude: position.coords.longitude, }; }
throw new Error(`Unknown client tool: ${name}`); },});
Returning values
Section titled “Returning values”- Return only JSON-serializable objects. They are sent straight back to your backend.
- Async work is supported—
onClientTool
can return a promise. - Throwing an error surfaces the message to the agent and halts the tool call.
- If a tool does not need to return data, return
{}
to mark the invocation as success.