Tool calling
There are two ways to integrate tool calling with Runway Characters. Both let the model decide when to invoke a named tool during a realtime Session. They differ in where the handler runs and how results participate in the conversation.
- React SDK (
@runwayml/avatars-react) — client events, hooks, and examples - Node RPC (
@runwayml/avatars-node-rpc) — backend tool handlers over the realtime Session
Client events (browser)
Section titled “Client events (browser)”Client events are one-way, fire-and-forget signals from the Avatar into your frontend. You declare tools when you create the Session; the Avatar can invoke them during the call. Invocations arrive over the WebRTC data channel, and your app reacts—for example updating React state or showing a UI overlay. No return value is sent back into the conversation.
Good for driving local UI: captions, trivia boards, highlights, game state, or any on-device effect that doesn’t need a server round trip.
// Shared tool definitions — import the same module on server and clientimport { clientTool, type ClientEventsFrom } from '@runwayml/avatars-react/api';
export const showCaption = clientTool('show_caption', { description: 'Show a short caption overlay', args: {} as { text: string },});
export const tools = [showCaption];export type AppEvents = ClientEventsFrom<typeof tools>;
// Server: pass tools when creating the Sessionawait client.realtimeSessions.create({ model: 'gwm1_avatars', avatar: { type: 'custom', avatarId }, tools,});
// Client: subscribe inside AvatarCall / AvatarSessionimport { useClientEvent } from '@runwayml/avatars-react';
function CaptionOverlay() { const caption = useClientEvent<AppEvents, 'show_caption'>('show_caption'); return caption ? <p>{caption.text}</p> : null;}See the nextjs-client-events example for a full working demo.
Backend RPC (Node)
Section titled “Backend RPC (Node)”Backend RPC is for tools whose implementation runs on your server and whose return values should feed back into the conversation—so the model can speak from real data rather than only from what runs in the browser. Use it when you need server-side auth, access to private systems, or structured results that shape what the Avatar says next.
The @runwayml/avatars-node-rpc package joins the Session as a hidden participant and routes incoming tool requests to your handler functions.
import { createRpcHandler } from '@runwayml/avatars-node-rpc';
const handler = await createRpcHandler({ apiKey: process.env.RUNWAYML_API_SECRET!, sessionId, tools: { fetch_order_status: async (args) => { const order = await db.orders.find(String(args.orderId)); return { status: order.status, eta: order.eta }; }, }, onConnected: () => console.log('Connected'), onDisconnected: () => console.log('Disconnected'), onError: (err) => console.error(err),});
await handler.close();Create a Session the same way as in Building your integration, then attach the RPC handler with your API key and Session ID (or pre-fetched credentials—see the package README).
Choosing an approach
Section titled “Choosing an approach”| Client events | Backend RPC | |
|---|---|---|
| Runs in | Browser (React SDK) | Your Node server process |
| Typical use | Local UI, overlays, on-device effects | Authenticated backends; results that shape the conversation |
| Result handling | One-way signals into your UI | Return values are sent back so the model can use them on the next turn |
You can combine both: client events for immediate surface updates, and backend RPC when the Avatar needs trusted data before it speaks.
Related documentation
Section titled “Related documentation”- Building your integration — Session creation, WebRTC, and the React SDK
- Knowledge base — static knowledge attached to an Avatar (separate from tool calling)