# Getting Started URL: /docs/react-native Build AI chat interfaces for iOS and Android with @assistant-ui/react-native. Quick Start \[#quick-start] The fastest way to get started with assistant-ui for React Native. Create a new project \[#create-a-new-project] ```sh npx assistant-ui@latest create --example with-expo my-chat-app cd my-chat-app ``` Configure API endpoint \[#configure-api-endpoint] Create a `.env` file pointing to your chat API: ``` EXPO_PUBLIC_CHAT_ENDPOINT_URL="http://localhost:3000/api/chat" ``` Start the app \[#start-the-app] ```sh npx expo start ``` Manual Setup \[#manual-setup] If you prefer to add assistant-ui to an existing Expo project, follow these steps. Install dependencies \[#install-dependencies] ```sh npx expo install @assistant-ui/react-native @assistant-ui/react-ai-sdk ``` Setup Backend Endpoint \[#setup-backend-endpoint] Create a backend API route using the Vercel AI SDK. This is the same endpoint you'd use with `@assistant-ui/react` on the web: <> ```ts title="app/api/chat/route.ts" import { openai } from "@ai-sdk/openai"; import { convertToModelMessages, streamText } from "ai"; export const maxDuration = 30; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: openai("gpt-4o-mini"), messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` ```ts title="app/api/chat/route.ts" import { anthropic } from "@ai-sdk/anthropic"; import { convertToModelMessages, streamText } from "ai"; export const maxDuration = 30; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: anthropic("claude-sonnet-4-20250514"), messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` ```ts title="app/api/chat/route.ts" import { google } from "@ai-sdk/google"; import { convertToModelMessages, streamText } from "ai"; export const maxDuration = 30; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: google("gemini-2.0-flash"), messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` This is the same backend you'd use with `@assistant-ui/react` on the web. If you already have an API route, you can reuse it as-is. Set up the runtime \[#set-up-the-runtime] ```tsx title="hooks/use-app-runtime.ts" import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/react-ai-sdk"; const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000"; export function useAppRuntime() { return useChatRuntime({ transport: new AssistantChatTransport({ api: `${API_URL}/api/chat`, }), }); } ``` Use it in your app \[#use-it-in-your-app] Wrap your app with `AssistantRuntimeProvider` and build your chat UI: ```tsx title="app/index.tsx" import { AssistantRuntimeProvider, useAuiState, useAui, } from "@assistant-ui/react-native"; import type { ThreadMessage } from "@assistant-ui/react-native"; import { View, Text, TextInput, FlatList, Pressable, KeyboardAvoidingView, Platform, } from "react-native"; import { useAppRuntime } from "@/hooks/use-app-runtime"; function MessageBubble({ message }: { message: ThreadMessage }) { const isUser = message.role === "user"; const text = message.content .filter((p) => p.type === "text") .map((p) => ("text" in p ? p.text : "")) .join("\n"); return ( {text} ); } function Composer() { const aui = useAui(); const text = useAuiState((s) => s.composer.text); const isEmpty = useAuiState((s) => s.composer.isEmpty); return ( aui.composer().setText(t)} placeholder="Message..." multiline style={{ flex: 1, borderWidth: 1, borderColor: "#ddd", borderRadius: 20, paddingHorizontal: 16, paddingVertical: 10, maxHeight: 120, }} /> aui.composer().send()} disabled={isEmpty} style={{ marginLeft: 8, backgroundColor: !isEmpty ? "#007aff" : "#ccc", borderRadius: 20, width: 36, height: 36, justifyContent: "center", alignItems: "center", }} > ); } function ChatScreen() { const messages = useAuiState( (s) => s.thread.messages, ) as ThreadMessage[]; return ( m.id} renderItem={({ item }) => } /> ); } export default function App() { const runtime = useAppRuntime(); return ( ); } ``` What's Next? \[#whats-next]