[metadata]
apple-mobile-web-app-title: OpenRouter | Documentation
application-name: OpenRouter | Documentation
generator: Mintlify
msapplication-TileColor: #7624F4
msapplication-config: /docs/_mintlify/favicons/openrouter-d02e98a0/EmhfYwFO2tvnkuV-/_generated/favicon/browserconfig.xml
og:description: Learn how to implement streaming responses with OpenRouter's API. Complete guide to Server-Sent Events (SSE) and real-time model outputs.
og:image: https://openrouter.ai/dynamic-og?title=API%20Streaming&description=Real-time%20model%20response%20streaming
og:image:height: 630
og:image:width: 1200
og:site_name: OpenRouter Documentation
og:title: API Streaming - Real-time Model Response Integration
og:type: website
og:url: https://openrouter.ai/docs/api_reference/streaming
twitter:card: summary_large_image
twitter:description: Learn how to implement streaming responses with OpenRouter's API. Complete guide to Server-Sent Events (SSE) and real-time model outputs.
twitter:image: https://openrouter.ai/dynamic-og?title=API%20Streaming&description=Real-time%20model%20response%20streaming
twitter:image:height: 630
twitter:image:width: 1200
twitter:title: API Streaming - Real-time Model Response Integration
viewport: width=device-width, initial-scale=1, viewport-fit=cover

[canonical-links]
https://openrouter.ai/docs/api_reference/streaming

[document-links]
/docs/llms.txt: /docs/llms.txt
API Changelog: /docs/changelog
API Reference: /docs/api_reference/overview
API Versioning: /docs/api_reference/versioning
Agent SDK: /docs/agent-sdk/overview
Apps: https://openrouter.ai/apps
Authentication: /docs/api_reference/authentication
Benchmarks: https://openrouter.ai/benchmarks
Chat: https://openrouter.ai/chat
Client SDKs: /docs/client-sdks/overview
Cookbook: /docs/cookbook/get-started/quickstart
Docs: /docs/quickstart
Docs: https://openrouter.ai/docs
Embeddings: /docs/api_reference/embeddings
Errors and Debugging: /docs/api_reference/errors-and-debugging
Limits: /docs/api_reference/limits
Models: https://openrouter.ai/models
OpenAI SDK: https://www.npmjs.com/package/openai
OpenRouter | Documentation home page: https://openrouter.ai
Overview: /docs/api_reference/overview
Parameters: /docs/api_reference/parameters
Rankings: https://openrouter.ai/rankings
SSE specs: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
Streaming: /docs/api_reference/streaming
Vercel AI SDK: https://www.npmjs.com/package/ai
eventsource-parser: https://github.com/rexxars/eventsource-parser

[structured-data]
{"@context":"https://schema.org","@graph":[{"@id":"https://openrouter.ai/#organization","@type":"Organization","logo":{"@type":"ImageObject","url":"https://mintcdn.com/openrouter-d02e98a0/ksNSeB_K7gD-BUDh/assets/logo-v2-light.svg?fit=max&auto=format&n=ksNSeB_K7gD-BUDh&q=85&s=690e45873843519efe02bcbe45795dac"},"name":"OpenRouter | Documentation","url":"https://openrouter.ai"},{"@id":"https://openrouter.ai/docs#website","@type":"WebSite","name":"OpenRouter | Documentation","publisher":{"@id":"https://openrouter.ai/#organization"},"url":"https://openrouter.ai/docs"},{"@id":"https://openrouter.ai/docs/api_reference/streaming#webpage","@type":"WebPage","breadcrumb":{"@id":"https://openrouter.ai/docs/api_reference/streaming#breadcrumb"},"dateModified":"2026-08-21T00:21:09.542Z","isPartOf":{"@id":"https://openrouter.ai/docs#website"},"name":"Streaming","url":"https://openrouter.ai/docs/api_reference/streaming"},{"@id":"https://openrouter.ai/docs/api_reference/streaming#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","item":"https://openrouter.ai/docs/api_reference/overview","name":"API Guides","position":1},{"@type":"ListItem","item":"https://openrouter.ai/docs/api_reference/streaming","name":"Streaming","position":2}]},{"@id":"https://openrouter.ai/docs/api_reference/streaming#article","@type":["Article","TechArticle"],"dateModified":"2026-08-21T00:21:09.542Z","headline":"Streaming","image":"https://openrouter.ai/dynamic-og?title=API%20Streaming&description=Real-time%20model%20response%20streaming","isPartOf":{"@id":"https://openrouter.ai/docs#website"},"mainEntityOfPage":{"@id":"https://openrouter.ai/docs/api_reference/streaming#webpage"},"name":"Streaming","publisher":{"@id":"https://openrouter.ai/#organization"},"url":"https://openrouter.ai/docs/api_reference/streaming"}]}

[content]
API Streaming - Real-time Model Response Integration
Documentation Index
Fetch the complete documentation index at:
/docs/llms.txt
Use this file to discover all available pages before exploring further.
Skip to main content
OpenRouter | Documentation
home page
Search...
⌘
K
Ask Assistant
Models
Benchmarks
Chat
Rankings
Apps
Docs
Search...
Navigation
API Guides
Streaming
Docs
API Reference
Client SDKs
Agent SDK
Cookbook
API Guides
Overview
Streaming
Embeddings
Limits
Authentication
Parameters
Errors and Debugging
Responses API
Versioning
API Versioning
API Changelog
API Reference
Analytics
TTS
STT
OAuth
Benchmarks
BYOK
Chat
Classifications
Credits
Datasets
Embeddings
Endpoints
Generations
Guardrails
Images
API Keys
Anthropic Messages
Models
Observability
Organization
Presets
Providers
Rerank
Responses
SCIM
Video Generation
Workspaces
On this page
Additional information
Stream cancellation
Handling errors during streaming
Errors before any tokens are sent
Errors after tokens have been sent (mid-stream)
Code examples
API-specific behavior
API Guides
Streaming
Copy page
Copy page
Copy page
Copy page
The OpenRouter API allows streaming responses from
any model
. This is useful for building chat interfaces or other applications where the UI should update as the model generates the response.
To enable streaming, you can set the
stream
parameter to
true
in your request. The model will then stream the response to the client in chunks, rather than returning the entire response at once.
Here is an example of how to stream a response, and process it:
​
Additional information
For SSE (Server-Sent Events) streams, OpenRouter occasionally sends comments to prevent connection timeouts. These comments look like:
: OPENROUTER PROCESSING
Comment payload can be safely ignored per the
SSE specs
. However, you can use it to improve UX as needed, e.g. by showing a dynamic loading indicator.
If you parse the stream by hand, skip lines that start with
:
before calling
JSON.parse
. Passing a comment line like
: OPENROUTER PROCESSING
to
JSON.parse
throws, and unhandled it will crash your stream loop. The snippets above handle this.
A spec-compliant parser such as
eventsource-parser
handles comments, multi-line
data:
fields, and buffering for you:
eventsource-parser
import
{
createParser
}
from
'eventsource-parser'
;
const
response
=
await
fetch
(
'https://openrouter.ai/api/v1/chat/completions'
, {
method:
'POST'
,
headers:
{
Authorization:
`Bearer
${
process
.
env
.
OPENROUTER_API_KEY
}
`
,
'Content-Type'
:
'application/json'
,
},
body:
JSON
.
stringify
({
model:
'openai/gpt-4o'
,
messages:
[{
role:
'user'
,
content:
'Hello'
}],
stream:
true
,
}),
});
// Errors that occur before streaming starts are plain JSON, not SSE
if
(
!
response
.
ok
) {
const
error
=
await
response
.
json
();
throw
new
Error
(
error
.
error
.
message
);
}
const
parser
=
createParser
({
onEvent
(
event
) {
if
(
event
.
data
===
'[DONE]'
)
return
;
try
{
const
chunk
=
JSON
.
parse
(
event
.
data
);
const
content
=
chunk
.
choices
?.[
0
]?.
delta
?.
content
;
if
(
content
) {
console
.
log
(
content
);
}
}
catch
{
// Ignore invalid JSON
}
},
});
const
reader
=
response
.
body
!
.
getReader
();
const
decoder
=
new
TextDecoder
();
while
(
true
) {
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
parser
.
feed
(
decoder
.
decode
(
value
, {
stream:
true
}));
}
See all 43 lines
A parser only handles the SSE framing. Errors that occur mid-generation still arrive as regular
data:
events with an
error
field. See
Handling Errors During Streaming
below.
The generation ID is returned in the
X-Generation-Id
response header for all endpoints (chat completions, completions, responses, and messages), which can be useful for debugging and correlating requests.
Some SSE client implementations might not parse the payload according to spec, which leads to an uncaught error when you
JSON.stringify
the non-JSON payloads. We recommend the following clients:
eventsource-parser
OpenAI SDK
Vercel AI SDK
​
Stream cancellation
Streaming requests can be cancelled by aborting the connection. For supported providers, this immediately stops model processing and billing.
Provider Support
Supported
OpenAI, Azure, Anthropic
Fireworks, Mancer, Recursal
AnyScale, Lepton, OctoAI
Novita, DeepInfra, Together
Cohere, Hyperbolic, Infermatic
Avian, XAI, Cloudflare
SFCompute, Nineteen, Liquid
Friendli, Chutes, DeepSeek
Not Currently Supported
AWS Bedrock, Groq, Modal
Google, Google AI Studio, Minimax
HuggingFace, Replicate, Perplexity
Mistral, AI21, Featherless
Lynn, Lambda, Reflection
SambaNova, Inflection, ZeroOneAI
AionLabs, Alibaba, Nebius
Kluster, Targon, InferenceNet
To implement stream cancellation:
Cancellation only works for streaming requests with supported providers. For non-streaming requests or unsupported providers, the model will continue processing and you will be billed for the complete response.
​
Handling errors during streaming
OpenRouter handles errors differently depending on when they occur during the streaming process:
​
Errors before any tokens are sent
If an error occurs before any tokens have been streamed to the client, OpenRouter returns a standard JSON error response with the appropriate HTTP status code. This follows the standard error format:
{
"error"
: {
"code"
:
400
,
"message"
:
"Invalid model specified"
}
}
Common HTTP status codes include:
400
: Bad Request (invalid parameters)
401
: Unauthorized (invalid API key)
402
: Payment Required (insufficient credits)
429
: Too Many Requests (rate limited)
502
: Bad Gateway (provider error)
503
: Service Unavailable (no available providers)
​
Errors after tokens have been sent (mid-stream)
If an error occurs after some tokens have already been streamed to the client, OpenRouter cannot change the HTTP status code (which is already 200 OK). Instead, the error is sent as a Server-Sent Event (SSE) with a unified structure:
data: {"id":"cmpl-abc123","object":"chat.completion.chunk","created":1234567890,"model":"openai/gpt-4o","provider":"openai","error":{"code":"server_error","message":"Provider disconnected unexpectedly"},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}
Key characteristics of mid-stream errors:
The error appears at the
top level
alongside standard response fields (id, object, created, etc.)
A
choices
array is included with
finish_reason: "error"
to properly terminate the stream
The HTTP status remains 200 OK since headers were already sent
The stream is terminated after this unified error event
​
Code examples
Here’s how to properly handle both types of errors in your streaming implementation:
​
API-specific behavior
Different API endpoints may handle streaming errors slightly differently:
OpenAI Chat Completions API
: Returns
ErrorResponse
directly if no chunks were processed, or includes error information in the response if some chunks were processed
OpenAI Responses API
: May transform certain error codes (like
context_length_exceeded
) into a successful response with
finish_reason: "length"
instead of treating them as errors
Overview
Embeddings
⌘
I
Assistant
Responses are generated using AI and may contain mistakes.
