React Native
Get started with CopilotKit in React Native.
@copilotkit/react-native provides a lightweight, headless wrapper around CopilotKit's React hooks for React Native apps. You build the UI, and a Copilot Runtime endpoint handles agent communication from your server.
Prerequisites#
- An OpenAI API key (or another model provider supported by Model Selection)
- React Native 0.70+ (bare CLI or Expo)
- Node.js 20+
Getting started#
Create your React Native app#
If you don't have one already:
npx @react-native-community/cli@latest init MyCopilotApp
cd MyCopilotAppInstall CopilotKit#
Install the React Native frontend package and @copilotkit/runtime for your local Copilot Runtime server:
npm install @copilotkit/react-native @copilotkit/runtime
npm install -D tsx typescript @types/nodepnpm add @copilotkit/react-native @copilotkit/runtime
pnpm add -D tsx typescript @types/nodeyarn add @copilotkit/react-native @copilotkit/runtime
yarn add -D tsx typescript @types/nodeAdd polyfills#
React Native's JS runtime (Hermes) lacks several Web APIs that CopilotKit depends on. Import the polyfills before any other code in your entry point:
import "@copilotkit/react-native/polyfills";
import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";
AppRegistry.registerComponent(appName, () => App);Granular polyfills
If you already polyfill some of these APIs (e.g. ReadableStream), you can import only what you need instead:
import "@copilotkit/react-native/polyfills/streams";
import "@copilotkit/react-native/polyfills/encoding";
import "@copilotkit/react-native/polyfills/crypto";
import "@copilotkit/react-native/polyfills/dom";
import "@copilotkit/react-native/polyfills/location";Create the Copilot Runtime#
Add a small Node server that hosts Copilot Runtime at /api/copilotkit and registers a default built-in agent:
import { createServer } from "node:http";
import { BuiltInAgent, CopilotRuntime } from "@copilotkit/runtime/v2";
import { createCopilotNodeListener } from "@copilotkit/runtime/v2/node";
const runtime = new CopilotRuntime({
agents: {
default: new BuiltInAgent({
model: "openai:gpt-5-mini",
prompt: "You are a helpful assistant for a React Native app.",
}),
},
});
const port = Number(process.env.PORT ?? 8200);
createServer(
createCopilotNodeListener({
runtime,
basePath: "/api/copilotkit",
cors: true,
}),
).listen(port, () => {
console.log(
`Copilot Runtime listening at http://localhost:${port}/api/copilotkit`,
);
});Wrap your app with CopilotKitProvider#
Point the provider at the runtime endpoint. Android emulators reach the host machine at 10.0.2.2; iOS simulators can use localhost.
import { CopilotKitProvider } from "@copilotkit/react-native";
import { Platform } from "react-native";
import { ChatScreen } from "./src/ChatScreen";
const runtimeUrl =
Platform.OS === "android"
? "http://10.0.2.2:8200/api/copilotkit"
: "http://localhost:8200/api/copilotkit";
export default function App() {
return (
<CopilotKitProvider runtimeUrl={runtimeUrl}> {}
<ChatScreen />
</CopilotKitProvider>
);
}Testing on a physical device
Replace localhost or 10.0.2.2 with your development machine's LAN IP address, for example http://192.168.1.23:8200/api/copilotkit.
Build your chat UI#
Hooks from the web SDK work identically in React Native. Below is a minimal chat screen using useAgent and useCopilotKit:
import { useCallback, useRef, useState } from "react";
import {
FlatList,
KeyboardAvoidingView,
Platform,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import { useAgent, useCopilotKit } from "@copilotkit/react-native";
export function ChatScreen() {
const [inputText, setInputText] = useState("");
const flatListRef = useRef<FlatList>(null);
const { copilotkit } = useCopilotKit();
const { agent } = useAgent({ agentId: "default" });
const messages = agent?.messages ?? [];
const isLoading = agent?.isRunning ?? false;
const chatMessages = messages.flatMap((message) => {
if (
(message.role === "user" || message.role === "assistant") &&
typeof message.content === "string" &&
message.content.length > 0
) {
return [
{
id: message.id,
content: message.content,
},
];
}
return [];
});
const handleSend = useCallback(async () => {
const text = inputText.trim();
if (!text || isLoading || !agent) return;
setInputText("");
agent.addMessage({
id: `user-${Date.now()}`,
role: "user",
content: text,
});
await copilotkit.runAgent({ agent });
}, [inputText, isLoading, agent, copilotkit]);
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
<FlatList
ref={flatListRef}
data={chatMessages}
renderItem={({ item }) => (
<View style={{ padding: 12, maxWidth: "80%" }}>
<Text>{item.content}</Text>
</View>
)}
keyExtractor={(item, i) => item.id ?? String(i)}
onContentSizeChange={() =>
flatListRef.current?.scrollToEnd({ animated: true })
}
/>
<View style={{ flexDirection: "row", padding: 8 }}>
<TextInput
style={{ flex: 1, borderWidth: 1, borderRadius: 8, padding: 8 }}
value={inputText}
onChangeText={setInputText}
placeholder="Type a message..."
/>
<TouchableOpacity onPress={handleSend} style={{ padding: 8 }}>
<Text>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}Headless by design
@copilotkit/react-native is headless. It provides hooks, not UI components. You have full control over your chat interface using standard React Native components.
Run the runtime and app#
Start Copilot Runtime in one terminal:
export OPENAI_API_KEY=sk-...
npx tsx server.tsRun the React Native app in another terminal:
npx react-native run-iosnpx react-native run-androidStart chatting!#
Your React Native app is now connected to Copilot Runtime. Hooks from the web SDK work identically:
useAgent- connect to an agent and manage messagesuseFrontendTool- let the agent call functions in your appuseHumanInTheLoop- add approval flows for agent actionsuseCopilotKit- access the CopilotKit instance directly
Troubleshooting
- Metro can't resolve modules: Clear the cache with
npx react-native start --reset-cache. - Streaming not working: Make sure polyfills are imported before any CopilotKit code in your entry point.
- No response from the runtime: Confirm the runtime server is running,
http://localhost:8200/api/copilotkit/inforeturns thedefaultagent, and the device can reachruntimeUrl. For physical devices, use your machine's LAN IP instead oflocalhost. - Model auth errors: Confirm
OPENAI_API_KEYis set in the terminal runningnpx tsx server.ts. - Existing polyfill conflicts: Use the granular imports instead of the barrel
polyfillsimport.
What's included#
| Export | Description |
|---|---|
CopilotKitProvider | Lightweight provider that points React Native at Copilot Runtime |
useAgent, useFrontendTool, etc. | Re-exported hooks from @copilotkit/react-core |
@copilotkit/react-native/polyfills | ReadableStream, TextEncoder, crypto, DOMException, location |
@copilotkit/runtime | Server-side runtime used to host your default agent |
Known limitations#
- No pre-built UI components - you build the chat interface with React Native components
- Markdown rendering - assistant messages with markdown render as plain text; bring your own renderer (e.g.
react-native-markdown-display) - Voice -
@copilotkit/voicehas not been adapted for React Native yet