SSE streaming
On this page
Receive answers in real time
By default, the API waits until the complete answer has been generated before returning it. With streaming, you receive tokens as they’re generated. This technique cuts the wait users perceive and lets you display answers progressively, exactly as the Grok interface does.
How streaming works
Streaming uses the Server-Sent Events (SSE) protocol. Instead of a single HTTP response, the server sends a continuous stream of events. Each event contains a fragment of the answer, and the client assembles them to rebuild the complete text.
The stream: true parameter turns on this mode for any generation endpoint.
Streaming in Python with the OpenAI SDK
from openai import OpenAI
import os
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1"
)
stream = client.chat.completions.create(
model="grok-4.5",
messages=[
{"role": "user", "content": "Explain the SOLID principles in programming."}
],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
print() # Final line break
How the code works
stream=Trueturns on streaming- The response is an iterator of
chunkobjects (fragments) - Each chunk contains a
deltawith the new content end=""prevents line breaks between fragmentsflush=Trueforces immediate display
Streaming with the /v1/responses endpoint
stream = client.responses.create(
model="grok-4.5",
input="Describe the steps to deploy a web application.",
stream=True
)
for event in stream:
if hasattr(event, 'type') and event.type == 'response.output_text.delta':
print(event.delta, end="", flush=True)
print()
The /v1/responses endpoint uses typed events. The response.output_text.delta type contains the text fragments.
Streaming with cURL
cURL supports SSE streaming natively. Add "stream": true to the request body:
curl -N https://api.x.ai/v1/chat/completions \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-4.5",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'
The -N option turns off cURL’s buffering so events display as soon as they arrive.
Each line of the SSE stream starts with data: followed by a JSON object. The last event is data: [DONE], which signals the end of generation.
When to use streaming
The decision comes down to one question: is a person watching the answer arrive? If so (a chatbot, an assistant, a writing tool), streaming is all but mandatory: users see the text appear word by word instead of staring at a frozen screen, and on a long answer, the difference between “first word in 300 ms” and “all the text after 8 seconds” makes the whole perceived experience.
If nobody is watching, streaming adds nothing and complicates the code. A batch job that fills a database, an automated pipeline that has to parse the complete answer before acting, a call that returns only a few words: in all these cases, the classic call (one request, one complete response) remains simpler to write, test, and debug.
Error handling in streaming
In streaming mode, errors can occur in the middle of the stream. Your code has to handle those interruptions:
try:
stream = client.chat.completions.create(
model="grok-4.5",
messages=[{"role": "user", "content": "Test"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
except Exception as e:
print(f"\nError during streaming: {e}")
Key takeaways
- Add
stream=Trueto receive tokens as they’re generated - The protocol used is SSE (Server-Sent Events)
- In Python, iterate over the chunks and print
delta.content - With cURL, use
-Nto turn off buffering - Save streaming for cases where progressive display adds value