react-native-ai-stream
v0.1.1
Published
Stream AI responses and live updates in React Native. Server-Sent Events (SSE) and NDJSON with POST support, auto-reconnect, cancellation, and hooks for OpenAI, Anthropic and Ollama. A maintained EventSource alternative. Zero dependencies, works with Expo
Downloads
234
Maintainers
Readme
react-native-ai-stream
Stream AI responses and live updates in React Native.
A maintained Server-Sent Events (SSE) and NDJSON client for React
Native and Expo — the EventSource that React Native never shipped. Stream
ChatGPT-style responses token by token from OpenAI, Anthropic,
Gemini, Groq or a local Ollama model, or replace polling with live
order tracking, progress bars and notifications.
React Native has no EventSource, and its fetch buffers the whole response
before handing it to you, so there is no built-in way to receive data as it
arrives. This is that — with reconnection, cancellation and React hooks.
const { messages, send, isStreaming, stop } = useChatStream({
url: 'https://api.openai.com/v1/chat/completions',
headers: { Authorization: `Bearer ${key}` },
});
// text appears word by word, the stop button works, it reconnects on a blipThe problem
Your app needs live updates — an AI answer appearing word by word, an order moving from Preparing to Out for delivery, a progress bar.
Most apps solve it by asking, over and over:
setInterval(() => fetch('/order/123'), 5000); // 720 requests an hourThat drains battery, hammers your server, and the update still arrives up to five seconds late.
Server-Sent Events invert it: the client opens one connection and the server pushes when something actually happens. One connection, instant updates, near zero traffic while idle.
The catch on React Native:
| | Browser | React Native |
|---|---|---|
| EventSource | ✅ built in | ❌ missing |
| Streaming fetch body | ✅ | ❌ buffers the whole response |
| POST with headers + body | ❌ EventSource is GET-only | — |
That last row matters more than it looks. Every AI completion endpoint is a
POST with an Authorization header and a JSON body. The browser's own
EventSource cannot do that either — which is why a plain polyfill is not
enough, and why this library speaks the wire format over fetch instead.
Install
npm install react-native-ai-streamNo runtime dependencies. No native modules — works in Expo Go.
📖 Full guide — plain-language explanation, recipes for chat, order tracking, progress bars and notifications, server setup, platform notes and troubleshooting.
AI chat
import { useChatStream } from 'react-native-ai-stream/react';
export function Chat() {
const { messages, send, isStreaming, stop, error } = useChatStream({
url: 'https://api.openai.com/v1/chat/completions',
headers: { Authorization: `Bearer ${process.env.OPENAI_KEY}` },
model: 'gpt-4o-mini',
});
return (
<View>
{messages.map((m) => (
<Text key={m.id}>
{m.content}
{m.streaming ? '▋' : ''}
</Text>
))}
<Button title="Ask" onPress={() => send('Explain SSE simply')} />
{isStreaming && <Button title="Stop" onPress={stop} />}
{error ? <Text>{String(error)}</Text> : null}
</View>
);
}Anthropic, or a local model — one line changes:
// Anthropic
useChatStream({
url: 'https://api.anthropic.com/v1/messages',
headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
adapter: 'anthropic',
});
// Ollama and other local model servers, which stream NDJSON rather than SSE
useChatStream({
url: 'http://192.168.1.10:11434/api/chat',
adapter: 'ollama',
format: 'ndjson',
model: 'llama3',
});⚠️ Do not ship an API key in your app. Point
urlat your own backend and keep the key on the server — the hook does not care what it is talking to.
Live updates — anything that is not chat
import { useEventStream } from 'react-native-ai-stream/react';
function OrderStatus({ orderId }) {
const { data, connected } = useEventStream(`/api/orders/${orderId}/stream`);
return (
<Text>
{data?.status ?? 'Loading…'}
{!connected && ' (reconnecting…)'}
</Text>
);
}Order tracking, job progress, notifications, live prices, presence, build logs — same hook.
What your server sends
Plain HTTP. No special server, no separate protocol, works through nginx and CDNs:
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.write(`data: ${JSON.stringify({ status: 'Out for delivery' })}\n\n`);data: , your payload, then two newlines.
Without React
import { EventStream } from 'react-native-ai-stream';
const stream = new EventStream('https://api.example.com/events', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: { channel: 'orders' },
onEvent: (e) => console.log(e.event, e.data),
onError: (err, willRetry) => console.warn(err, willRetry),
});
await stream.connect();
stream.close();What it handles for you
| | |
|---|---|
| Chunk boundaries | An event split across two network reads is buffered and reassembled |
| Reconnection | Exponential backoff with jitter, so a fleet of devices does not stampede your server |
| Resume | Last-Event-ID is replayed so the server can send what you missed |
| Server pacing | A retry: field from the server overrides the computed delay |
| Cancellation | stop() aborts the request; partial text is kept |
| Keep-alives | : comment lines ignored |
| Multi-line data | Joined with newlines, per spec |
| CRLF | Normalised |
| Two wire formats | SSE, and NDJSON for Ollama and local model servers |
API
useChatStream(options)
| Option | Default | |
|---|---|---|
| url | required | Completion endpoint |
| headers | — | Auth and provider headers |
| adapter | 'openai' | 'openai', 'anthropic', 'ollama', 'text', or your own |
| format | 'sse' | 'sse' for text/event-stream, 'ndjson' for one JSON object per line |
| model | 'gpt-4o-mini' | Used by the default body builder |
| buildBody | OpenAI shape | Build the request body yourself |
| initialMessages | [] | Seed the conversation |
| onFinish / onError | — | Callbacks |
Returns { messages, send, stop, isStreaming, error, reset }.
⚠️ A chat completion does not auto-retry. A dropped connection mid-answer would replay the whole prompt and bill you twice, so failures surface instead.
useEventStream(url, options)
{ enabled, parse, retry, headers, method, body, onEvent } →
{ data, events, state, connected, error, close }
new EventStream(url, options)
{ method, headers, body, retry, signal, fetchImpl, onEvent, onOpen, onDone, onError, onStateChange }
retry is { maxAttempts, baseDelayMs, maxDelayMs, jitter } — default
{ 10, 500, 30_000, 0.3 }.
Custom adapter
Any provider, in a few lines:
const gemini: ChunkAdapter = (event) => {
if (event.data === '[DONE]') return { done: true };
const t = JSON.parse(event.data)?.candidates?.[0]?.content?.parts?.[0]?.text;
return t ? { text: t } : null;
};Compared to the alternatives
| | |
|---|---|
| react-native-sse | A low-level EventSource polyfill. No React hooks, no provider parsing, no AbortController. Last published March 2024 |
| @ai-sdk/react | Excellent — if you are on the web. Use it there |
| Hand-rolling it | ~80 lines of parsing, state and reconnection, in every project |
Supported endpoints
| | |
|---|---|
| SSE (default) | OpenAI, Anthropic, Gemini, Groq, Together, OpenRouter, Mistral, your own backend |
| NDJSON (format: 'ndjson') | Ollama and other local model servers |
| ❌ Not supported | ordinary REST (use fetch), WebSocket, GraphQL subscriptions |
Unsure? curl -N -H "Accept: text/event-stream" <url> — if you see repeating
data: lines it is SSE; one JSON object per line is NDJSON.
Use @ai-sdk/react on the web. This is the React Native side.
Examples
npm run demo # real local SSE server, no simulator neededExercises token streaming, an event split across network writes, cancellation,
reconnection with backoff, and non-chat live updates. See
example/ for the React Native chat screen.
Development
npm install
npm test
npm run typecheck
npm run buildContributing
Issues and pull requests are welcome — see CONTRIBUTING.md.
Most useful right now: adapters for more providers (Gemini, Cohere, Bedrock — an adapter is a few lines), failing tests for streams this mishandles, and reports of how it behaves on your React Native version.
git clone https://github.com/ARBAB1/react-native-ai-stream.git
cd react-native-ai-stream && npm install && npm testAuthor
Syed Arbab Ali Shah — github.com/ARBAB1
Built after hitting the same problem on several React Native apps: streaming an AI response, or a live order status, with no maintained way to do it.
License
MIT © Syed Arbab Ali Shah
