Building your integration
This guide walks through building a complete Avatar integration using Next.js App Router. The same patterns apply to other React frameworks.
Architecture overview
Section titled “Architecture overview”Avatar Sessions require a server component to keep your API key secure. The client never sees your Runway API secret.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Client │ │ Your Server │ │ Runway API ││ (React App) │ │ (Next.js) │ │ │└────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │ │ │ 1. Request Session │ │ │ POST /api/avatar/session │ │ │ ─────────────────────────►│ │ │ │ │ │ │ 2. Create Session │ │ │ POST /v1/realtime_sessions │ │ ─────────────────────────►│ │ │ │ │ │ 3. Poll until ready │ │ │ GET /v1/realtime_sessions/:id │ │ ─────────────────────────►│ │ │ │ │ │ 4. Consume credentials │ │ │ POST /v1/realtime_sessions/:id/consume │ │ ─────────────────────────►│ │ │ │ │ 5. Return credentials │◄───────────────────────── │ │◄───────────────────────── │ │ │ │ │ │ 6. WebRTC connection │ │ │ ─────────────────────────────────────────────────────►│ │ │ │Installation
Section titled “Installation”Install both the server SDK and React components:
npm install @runwayml/sdk @runwayml/avatars-reactServer setup
Section titled “Server setup”Create an API route that handles Session creation. This endpoint receives an Avatar ID from the client, creates a Session with Runway, polls until it’s ready, consumes the credentials, and returns them to the client.
The client can also pass optional personality and startScript fields to override the Avatar’s defaults for this session — useful for injecting user-specific context like the caller’s name.
import RunwayML from '@runwayml/sdk';
const client = new RunwayML();
export async function POST(request: Request) { const { avatarId, personality, startScript } = await request.json();
// 1. Create session const { id: sessionId } = await client.realtimeSessions.create({ model: 'gwm1_avatars', avatar: { type: 'custom', avatarId }, personality, startScript, });
// 2. Poll until ready let sessionKey: string | undefined; for (let i = 0; i < 60; i++) { const session = await client.realtimeSessions.retrieve(sessionId);
if (session.status === 'READY') { sessionKey = session.sessionKey; break; } if (session.status === 'FAILED') { return Response.json({ error: session.failure }, { status: 500 }); } await new Promise(r => setTimeout(r, 1000)); }
if (!sessionKey) { return Response.json({ error: 'Session timed out' }, { status: 504 }); }
// 3. Consume session to get connection credentials const consumeResponse = await fetch( `${client.baseURL}/v1/realtime_sessions/${sessionId}/consume`, { method: 'POST', headers: { Authorization: `Bearer ${sessionKey}`, 'X-Runway-Version': '2024-11-06', }, } ); const credentials = await consumeResponse.json();
return Response.json({ sessionId, serverUrl: credentials.url, token: credentials.token, roomName: credentials.roomName, });}Set your API key as an environment variable:
RUNWAYML_API_SECRET=your_api_key_hereClient integration
Section titled “Client integration”Simple: AvatarCall
Section titled “Simple: AvatarCall”The simplest way to add an Avatar is with the AvatarCall component. It handles WebRTC connection and renders a default UI.
'use client';
import { AvatarCall } from '@runwayml/avatars-react';import '@runwayml/avatars-react/styles.css';
export default function Home() { return ( <AvatarCall avatarId="customer-service" connectUrl="/api/avatar/session" onEnd={() => console.log('Call ended')} onError={(error) => console.error('Error:', error)} /> );}To use a custom Avatar created in the Developer Portal, replace "customer-service" with your Avatar ID.
Webcam and screen sharing
Section titled “Webcam and screen sharing”During a call, the Avatar can use your webcam and/or your screen as visual context—for example walkthroughs, slides, or showing something in frame. Enable that with @runwayml/avatars-react; webcam and screen share are part of the same realtime Session as audio (the usual WebRTC call).
Minimal example with the default control bar and screen sharing enabled:
// app/page.tsx — webcam (default) + optional screen share UI'use client';
import { AvatarCall, AvatarVideo, ControlBar, ScreenShareVideo,} from '@runwayml/avatars-react';import '@runwayml/avatars-react/styles.css';
export default function Home() { return ( <AvatarCall avatarId="customer-service" connectUrl="/api/avatar/session"> <AvatarVideo /> <ScreenShareVideo /> <ControlBar showScreenShare /> </AvatarCall> );}Fully custom: hooks
Section titled “Fully custom: hooks”For complete control over the UI, use AvatarSession with hooks. This example shows how to build a custom interface with useAvatarSession for Session state and useLocalMedia for mic and webcam controls:
'use client';
import { AvatarSession, AvatarVideo, UserVideo, useAvatarSession, useLocalMedia,} from '@runwayml/avatars-react';import type { SessionCredentials } from '@runwayml/avatars-react';
function CallUI() { const { state, end } = useAvatarSession(); const { isMicEnabled, toggleMic } = useLocalMedia();
return ( <div className="relative w-full h-screen"> <AvatarVideo className="w-full h-full object-cover" /> <UserVideo className="absolute bottom-4 right-4 w-48 rounded-lg" />
<div className="absolute bottom-4 left-4 flex gap-2"> <button onClick={toggleMic}> {isMicEnabled ? 'Mute' : 'Unmute'} </button> <button onClick={end}>End</button> </div>
{state === 'connecting' && <div>Connecting...</div>} </div> );}
export function CustomAvatar({ credentials }: { credentials: SessionCredentials }) { return ( <AvatarSession credentials={credentials} audio video> <CallUI /> </AvatarSession> );}For more components, hooks, and examples—including the full Webcam & Screen Sharing section—see the React SDK README. For client events (UI tool calls) and backend RPC (server-side tools with return values), see Tool calling.
Browser support
Section titled “Browser support”The Avatars SDK uses WebRTC for real-time communication:
| Browser | Minimum Version |
|---|---|
| Chrome | 74+ |
| Firefox | 78+ |
| Safari | 14.1+ |
| Edge | 79+ |
Users must grant microphone permissions when prompted. Webcam access is required if the user’s video is enabled.