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 — CopilotKit handles the agent communication.
Prerequisites#
- A CopilotKit runtime endpoint (self-hosted or cloud)
- 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#
npm install @copilotkit/react-nativepnpm add @copilotkit/react-nativeyarn add @copilotkit/react-nativeAdd 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";Wrap your app with CopilotKitProvider#
import { CopilotKitProvider } from "@copilotkit/react-native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { ChatScreen } from "./src/ChatScreen";
export default function App() {
return (
<SafeAreaProvider>
<CopilotKitProvider runtimeUrl="https://your-server/api/copilotkit">
<ChatScreen />
</CopilotKitProvider>
</SafeAreaProvider>
);
}Build your chat UI#
Hooks from the web SDK work identically in React Native. Here's 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 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={messages.filter(
(m) => m.role === "user" || (m.role === "assistant" && m.content),
)}
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 app#
npx react-native run-iosnpx react-native run-androidStart chatting!#
Your React Native app is now connected to CopilotKit. 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
- Existing polyfill conflicts: Use the granular imports instead of the barrel
polyfillsimport - Make sure the runtime endpoint URL is reachable from your device/emulator (use your machine's IP, not
localhost, for physical devices)
What's included#
| Export | Description |
|---|---|
CopilotKitProvider | Lightweight provider — no DOM, CSS, or web framework deps |
useAgent, useFrontendTool, etc. | Re-exported hooks from @copilotkit/react-core |
@copilotkit/react-native/polyfills | ReadableStream, TextEncoder, crypto, DOMException, location |
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
