Use useChat from @tanstack/ai-react with xhrHttpStream() and an absolute URL. XHR progress events carry the stream when fetch streaming is missing.
Your backend returns the stream with toHttpResponse():
// server route: POST /chat/http
import { chat, chatParamsFromRequest, toHttpResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
export async function POST(request: Request) {
const { messages, threadId, runId } = await chatParamsFromRequest(request);
const stream = chat({
adapter: openaiText("gpt-6.1-sol"),
messages,
threadId,
runId,
});
return toHttpResponse(stream);
}Put the backend address in a public Expo variable:
EXPO_PUBLIC_TANSTACK_AI_BASE_URL=http://127.0.0.1:8787Use a URL that your runtime can reach:
import { Button, Text, View } from "react-native";
import { useChat, xhrHttpStream } from "@tanstack/ai-react";
const baseUrl =
process.env.EXPO_PUBLIC_TANSTACK_AI_BASE_URL ?? "http://127.0.0.1:8787";
export function ChatScreen() {
const { messages, sendMessage } = useChat({
connection: xhrHttpStream(`${baseUrl}/chat/http`),
threadId: "support-chat",
});
return (
<View>
{messages.map((message) => (
<Text key={message.id}>
{message.parts.map((part) =>
part.type === "text" ? part.content : "",
)}
</Text>
))}
<Button title="Send" onPress={() => void sendMessage("Hello")} />
</View>
);
}Tap Send in the simulator. The reply streams into messages as the model writes it.
For a full mobile walkthrough with a Hono server and a text input, see Quick Start: React Native.
Mobile connections drop often. If the server adds a durability adapter, both XHR transports reconnect and support joinRun. See Resumable Streams.
If your server returns text/event-stream with toServerSentEventsResponse() (see Server-Sent Events), use xhrServerSentEvents():
import { xhrServerSentEvents } from "@tanstack/ai-react";
const baseUrl =
process.env.EXPO_PUBLIC_TANSTACK_AI_BASE_URL ?? "http://127.0.0.1:8787";
export const connection = xhrServerSentEvents(`${baseUrl}/chat/sse`);Pass this connection to useChat.
fetchHttpStream() works only if your React Native runtime has all of these:
The server still returns newline-delimited JSON with toHttpResponse():
import { fetchHttpStream } from "@tanstack/ai-react";
const baseUrl =
process.env.EXPO_PUBLIC_TANSTACK_AI_BASE_URL ?? "http://127.0.0.1:8787";
export const connection = fetchHttpStream(`${baseUrl}/chat/http`);If one of these APIs is missing, fetchHttpStream() throws UnsupportedResponseStreamError. A polyfill that buffers the response does not help, because the transport needs incremental bytes. Use xhrHttpStream() or xhrServerSentEvents().
The XHR transports take headers and body, like the fetch transports. For cookies, they use withCredentials, not credentials. See Request Options.
Keep provider SDKs and server helpers on your backend. Import only hooks and connection adapters in the React Native bundle. Do not import these: