CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Stop Waiting for the Full Response: Stream Claude Replies Token-by-Token With messages.stream()

Stop Waiting for the Full Response: Stream Claude Replies Token-by-Token With messages.stream()

Chris Harper

2 min read

Jul 17, 2026 · 04:05 UTC

AI
Workflow
Claude Code
Best Practices

Replace messages.create() with messages.stream() — users see the first token in under 100ms instead of waiting 3–5 seconds for a full reply, with almost no code change.

Every call to messages.create() blocks until Claude finishes generating. For a 300-word reply, that's 3–5 seconds of silence before your UI shows anything. Streaming prints each token as it's generated — users see the response start immediately.

The two-line change

import anthropic

client = anthropic.Anthropic()

# Before — blocks until the full response is ready
response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain gradient descent."}],
)
print(response.content[0].text)

# After — streams tokens as they arrive
with client.messages.stream(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain gradient descent."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

stream.text_stream is a generator that yields each text delta as Claude produces it. The with block closes the connection when done.

Store the complete message after streaming

with client.messages.stream(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain gradient descent."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

    # After the loop exits, the full message is available
    final = stream.get_final_message()
    # Same shape as messages.create() — use for storage, conversation history, etc.
    print(f"\nTokens used: {final.usage.input_tokens} in, {final.usage.output_tokens} out")

Async version (FastAPI, WebSockets, SSE)

async def stream_to_client(prompt: str):
    client = anthropic.AsyncAnthropic()
    async with client.messages.stream(
        model="claude-opus-4-8",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    ) as stream:
        async for text in stream.text_stream:
            yield text   # forward to your SSE or WebSocket handler

Streaming with tool calls

Use raw stream events when you need to handle tool calls alongside text:

with client.messages.stream(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=[{"name": "get_weather", "description": "...", "input_schema": {...}}],
    messages=[{"role": "user", "content": "What's the weather in NYC?"}],
) as stream:
    for event in stream:
        if event.type == "content_block_start" and event.content_block.type == "tool_use":
            print(f"\n[Tool call: {event.content_block.name}]")
        elif event.type == "content_block_delta" and event.delta.type == "text_delta":
            print(event.delta.text, end="", flush=True)

When streaming matters

Use caseStreaming?
User-facing chat UIYes — first token under 100ms
Background batch jobNo — create() is simpler
Agent inner loopOptional — use for live progress
CI pipelineNo — final result is all that matters

Sources: Streaming messages — Claude Platform Docs · Anthropic Python SDK