Skip to main content
Lesson 10 of 14 · Grok API quickstart

SSE streaming

Lesson 10 of 14 Updated July 30, 2026 Developer
On this page
  1. Receive answers in real time
  2. How streaming works
  3. Streaming in Python with the OpenAI SDK
  4. Streaming with the /v1/responses endpoint
  5. Streaming with cURL
  6. When to use streaming
  7. Error handling in streaming
  8. Key takeaways

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=True turns on streaming
  • The response is an iterator of chunk objects (fragments)
  • Each chunk contains a delta with the new content
  • end="" prevents line breaks between fragments
  • flush=True forces 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=True to 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 -N to turn off buffering
  • Save streaming for cases where progressive display adds value