Quickstart
Two paths. Pick the one that fits your situation.
| Path A — RAIS Cloud | Path B — Self-hosted | |
|---|---|---|
| Own AI provider accounts? | Not needed | Required (Groq, OpenAI, or Anthropic) |
| Setup time | ~2 min after key arrives | ~5 min |
| Best for | Getting started fast | Full control, no third-party dependency |
Path A — RAIS Cloud (recommended for most people)
You need a RAIS API key. Without it, the gateway returns 401 and nothing works.
Get your key
- Go to react-ai-stream-playground.vercel.app/cloud (opens in a new tab)
- Enter your email in the waitlist form
- Wait for the approval email — it contains your
ras_test_...key
Keys look like ras_test_a1b2c3d4e5f6... (free) or ras_live_... (paid). Keep it secret — it authorizes all your requests.
Install packages
npm install @react-ai-stream/react @react-ai-stream/uiAdd a proxy API route (keeps your key off the browser)
export const runtime = 'nodejs'
export async function POST(req: Request) {
const body = await req.json()
const upstream = await fetch(
'https://react-ai-stream-gateway.vercel.app/api/v1/chat',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.RAIS_API_KEY}`,
},
body: JSON.stringify(body),
}
)
return new Response(upstream.body, {
headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },
})
}Add to .env.local:
RAIS_API_KEY=ras_test_your_key_hereAdd the chat UI
'use client'
import { useAIChat } from '@react-ai-stream/react'
import { Chat } from '@react-ai-stream/ui'
import '@react-ai-stream/ui/styles'
export default function Page() {
const { messages, sendMessage, loading, stop } = useAIChat({
endpoint: '/api/chat',
})
return (
<div style={{ height: '80vh' }}>
<Chat messages={messages} onSend={sendMessage} onStop={stop} loading={loading} />
</div>
)
}Run it
npm run devOpen http://localhost:3000. You have streaming AI chat — Groq by default, with automatic fallback to OpenAI and Anthropic.
No provider account. No API key juggling. RAIS Cloud handles Groq, OpenAI, Anthropic, and Gemini on its side.
Your ras_test_... key is the only credential your app needs.
See full RAIS Cloud docs →
Path B — Self-hosted (you manage your own provider keys)
Use this when you want zero external dependencies beyond the AI provider itself.
Install packages
npm install @react-ai-stream/react @react-ai-stream/uiGet a provider API key
This example uses Groq (opens in a new tab) — free tier, instant sign-up. Add to .env.local:
GROQ_API_KEY=gsk_your_key_hereCreate a streaming API route
import { NextRequest } from 'next/server'
export const runtime = 'edge'
export async function POST(req: NextRequest) {
const { messages } = await req.json()
const upstream = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.GROQ_API_KEY}`,
},
body: JSON.stringify({
model: 'llama-3.3-70b-versatile',
messages,
stream: true,
}),
})
const stream = new ReadableStream({
async start(controller) {
const enc = new TextEncoder()
const send = (data: object) =>
controller.enqueue(enc.encode(`data: ${JSON.stringify(data)}\n\n`))
const reader = upstream.body!.getReader()
const decoder = new TextDecoder()
let buf = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buf += decoder.decode(value, { stream: true })
const parts = buf.split('\n\n')
buf = parts.pop() ?? ''
for (const part of parts) {
for (const line of part.split('\n')) {
if (!line.startsWith('data: ')) continue
const data = line.slice(6).trim()
if (data === '[DONE]') { send({ type: 'done' }); controller.close(); return }
try {
const ev = JSON.parse(data)
const text = ev.choices?.[0]?.delta?.content
if (text) send({ type: 'text', text })
} catch { /* skip */ }
}
}
}
send({ type: 'done' })
controller.close()
},
})
return new Response(stream, {
headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },
})
}Use the hook in your component
'use client'
import { useAIChat } from '@react-ai-stream/react'
import { Chat } from '@react-ai-stream/ui'
import '@react-ai-stream/ui/styles'
export default function Page() {
const { messages, sendMessage, loading, stop } = useAIChat({
endpoint: '/api/chat',
})
return (
<div style={{ height: '80vh' }}>
<Chat
messages={messages}
onSend={sendMessage}
onStop={stop}
loading={loading}
/>
</div>
)
}Done
You have a streaming AI chat backed by your own Groq account.
Bring your own UI
Both paths work without @react-ai-stream/ui. The hook has no UI dependency:
'use client'
import { useState } from 'react'
import { useAIChat } from '@react-ai-stream/react'
export default function Page() {
const { messages, sendMessage, loading, stop } = useAIChat({
endpoint: '/api/chat',
})
const [input, setInput] = useState('')
return (
<div>
<div>
{messages.map((m) => (
<p key={m.id}><b>{m.role}:</b> {m.content}</p>
))}
</div>
<form onSubmit={(e) => { e.preventDefault(); sendMessage(input); setInput('') }}>
<input value={input} onChange={(e) => setInput(e.target.value)} disabled={loading} />
{loading
? <button type="button" onClick={stop}>Stop</button>
: <button type="submit">Send</button>}
</form>
</div>
)
}Next steps
- RAIS Cloud full guide → — key management, providers, rate limits, error codes
- useAIChat API reference → — all options and return values
- Providers → — Anthropic, OpenAI, Groq, or your own backend
- Custom UI example → — wire the hook to your design system
- Hook architecture → — how isolated message stores work