D4.6 · Prompt Engineering20% of CCA-F8 min read

Streaming.

Streaming returns tokens as they're generated for low-latency UX. A full deep-dive guide is coming soon.

Loading your plan…
Mental modelTreating the stream as finished once text appears, or parsing each tool-input fragment as JSON.
Streaming, hero illustration featuring Loop mascot in a warm gallery scene.
Share
On this page
01 · Summary

TLDR

Streaming returns tokens as they're generated for low-latency UX. A full deep-dive guide is coming soon.

low latency
Use case
D4
Exam domain
C
Coverage tier
stub
Status
research
Action
02 · The decision

What you are deciding

Streaming delivers a response as a sequence of events instead of one body. You accumulate the pieces, treat the stream as finished only at message completion, and handle an error event that arrives inside the stream.

Learner decision

Which event tells me a piece is complete, and what must my code do when the stream ends or fails?

03 · Definition

What it is

Streaming is the capability to receive Claude's response token-by-token as Server-Sent Events (SSE) rather than waiting for the entire response. Add stream=True to messages.create(), and instead of a single response object, you get an HTTP event stream where each event represents a chunk of text or metadata. The user sees text appear word by word, creating a responsive chat experience instead of a blank screen for 10-30 seconds.

What makes streaming realtime is that the connection stays open while the model writes. Each token is emitted as a ContentBlockDelta event within milliseconds, allowing the client to render incrementally. The alternative (non-streaming) waits for the full response and ships it all at once, creating artificial latency. Streaming is especially valuable for long-form responses.

The event stream contains seven main types: MessageStart, ContentBlockStart, ContentBlockDelta (the actual text chunks), ContentBlockStop, MessageDelta, MessageStop, and optional error events. Production handling requires three guarantees: (1) graceful reconnection on network drop, (2) correct handling of tool_use blocks (their input streams as partial JSON strings that must be accumulated before parsing), (3) cost tracking (you pay per token regardless).

The main risk is premature disconnection. If the client closes before completion, the request is still billed but you lose partial output. Mitigations: track stream state, buffer all received tokens, exponential backoff on reconnection, log connection drops. Secondary risk: treating streaming as cost optimization, it costs the same as non-streaming, use it for UX.

04 · By certification

How each certification frames it

CCD-F: How CCD-F tests streaming

  • CCDVF-D2-O3 Claude API Mechanics: Claude API behavior and mechanics, including messages, tools, streaming, vision, thinking, caching, invoking Claude through third-party vendors, Messages API data access patterns, batch API use, and tradeoffs between realtime and batch API selection

Streaming is one of the Claude API behaviors listed in the Developer guide's API mechanics objective, next to messages, tools, caching and batch use (PDF page 6, Domain 2). Items test how to handle events, not only what streaming is for.

Expect to reason about when a tool call's input is usable and what counts as a finished response.

05 · Mechanics

How it works

Request structure is identical to non-streaming, except stream=True. The SDK returns an iterator (Python) or async generator (TS) that yields events. for event in stream: process(event). Fundamentally synchronous from the caller's perspective: you block reading events until more arrive.

Event payload structure is JSON. ContentBlockDelta events contain a delta field with text. ContentBlockStart signals block type (text or tool_use). MessageStart carries the message shell with initial usage. MessageDelta carries the stop_reason and the usage counts, which are cumulative. MessageStop is the final end marker. Extract from ContentBlockDelta.delta.text, accumulate. Read the stop_reason and usage from `MessageDelta`, and treat MessageStop as the signal that the stream is complete.

For tool_use blocks, the stream works differently. The ContentBlockStart event announces the tool_use block, and its input then arrives as ContentBlockDelta events of type input_json_delta, each carrying a partial JSON string (the final input is an object). Accumulate the string incrementally, validate only after ContentBlockStop, then execute. Most common mistake: trying to execute halfway through the JSON stream.

Network handling is critical. Streaming uses a single HTTP response carrying Server-Sent Events; the connection stays open while the model writes. Wrap the loop in try/except: catch RequestException, log, decide retry or escalate. The SDK provides with client.messages.stream(...) as stream: context manager that auto-closes and handles cleanup.

Streaming mechanics, painterly diagram featuring Loop mascot.
06 · Worked example

Worked example: a streamed answer that ends in a tool call

Authored teaching example, not a bank question.

A chat screen streams Claude's reply. The reply starts with a sentence of text and then asks to call a lookup tool.

01
Start. A message_start event opens the message with empty content. Content then arrives as blocks, each with a start event, one or more delta events and a stop event, identified by an index.
02
Text block. Text arrives as text_delta events. Append each piece to the screen as it arrives.
03
Tool block. For a tool call, input arrives as input_json_delta events carrying partial JSON strings. They are fragments, not valid JSON on their own.
04
Accumulate, then parse. Concatenate the fragments and parse only when the content_block_stop event for that block arrives. The SDK streaming helpers can also do the accumulation.
05
Finish. message_delta events carry top-level changes, including stop_reason, and the final message_stop event ends the stream. A stop_reason of tool_use means run the tool and send the result.
06
Errors. An error can arrive as an event inside the stream, for example an overloaded_error during high usage. The handler must treat it as a failed response, not as a normal end.
EventWhat your code does
content_block_delta (text_delta)Append text to the display
content_block_delta (input_json_delta)Append to a per-block string; do not parse yet
content_block_stopParse the tool input for that block
message_deltaRead stop_reason; usage counts are cumulative
message_stopMark the response complete
errorFail the response and report it

The screen shows text immediately, the tool call runs only after its JSON is complete, and a mid-stream error surfaces to the user and the logs. Check afterwards with a test that feeds a truncated stream and an error event into the handler.

07 · Failure modes

How this decision goes wrong

Parsing incomplete JSON

Looks right: Each delta contains JSON, so parse each one as it arrives.

Why it fails: Anthropic documents tool input deltas as partial JSON strings, while the final input is an object. A fragment cannot be parsed alone.

Instead: Accumulate the string and parse at content_block_stop, or use the SDK helpers.

Treating the first token as completion

Looks right: Text is on screen, so the response is done and the UI can unlock.

Why it fails: Text can be followed by a tool call, more blocks and a final stop_reason. Acting early skips the tool step or cuts the reply.

Instead: Mark complete on message_stop and branch on stop_reason.

Losing an in-stream error

Looks right: The request was accepted, so a failure would have raised an exception.

Why it fails: The API may send an error as an event within the stream. If the loop only reads text events, the failure is silently dropped.

Instead: Handle the error event type explicitly, and apply the documented recovery approach for interrupted streams where it applies.

08 · In production

Where you'll see it

Real-time chat UI in Streamlit or Flask

Web app uses stream=True, emits each text chunk via SSE to the frontend. JavaScript EventSource API consumes SSE automatically. User perceives instant feedback; same cost as non-streaming.

Live code generation in IDE extensions

VS Code extension calls Claude. With streaming, user sees the function appear line-by-line. Real incremental generation, not a fake typewriter effect. Extension inserts text into editor buffer as events arrive.

Show 2 more examples

Streaming agentic loops with tool results

Refund agent loop streams text ("Let me check the order..."), then a tool_use block (its input streams as partial JSON and is parsed once the block stops). Harness executes, appends result. Next turn streams reasoning again. Streaming improves perceived responsiveness even in multi-turn flows.

Long-form document generation

Research assistant generates 5000-word report. Non-streaming = blank screen 20+ seconds. With streaming, user sees intro, sections, conclusions live. User can interrupt mid-generation without paying for full output.

09 · Implementation

Code examples

Streaming with full event handling
import anthropic
client = anthropic.Anthropic()

def stream_response(user_msg: str, tools: list = None):
    accumulated_text = ""

    with client.messages.stream(
        model="claude-opus-4-5",
        max_tokens=2048,
        system="You are a helpful assistant.",
        tools=tools or [],
        messages=[{"role": "user", "content": user_msg}],
    ) as stream:
        for event in stream:
            if event.type == "content_block_delta":
                if event.delta.type == "text_delta":
                    text = event.delta.text
                    accumulated_text += text
                    print(text, end="", flush=True)  # Real-time output

            elif event.type == "message_delta":
                # stop_reason and cumulative usage arrive on message_delta
                print(f"\n[Stop reason: {event.delta.stop_reason}]")

        final = stream.get_final_message()  # SDK helper: the accumulated Message
        for block in final.content:
            if block.type == "tool_use":
                print(f"[Tool: {block.name}]")

    return accumulated_text
Stream loop with text accumulation. stop_reason arrives on message_delta; get_final_message() returns the accumulated Message, including tool_use blocks whose partial JSON the SDK has already assembled. flush=True for real-time output.
10 · Distractor patterns

Looks right, isn't

Each row pairs a plausible-looking pattern with the failure it actually creates. These are the shapes exam distractors are built from.

01Streaming is cheaper than non-streaming.
× Looks right
Streaming is cheaper than non-streaming.
✓ What wins
Same cost.

You pay per token regardless. Streaming is purely UX, not cost optimization.

02If stream connection drops, retry
× Looks right
If stream connection drops, retry the entire request.
✓ What wins
Drop doesn't lose what was received.

Client retains buffered text. Retrying wastes tokens on duplicate work. Log error, decide based on context.

03Tool_use input is complete in
× Looks right
Tool_use input is complete in each delta; parse JSON as it arrives.
✓ What wins
Tool_use input arrives as chunked input_json_delta events, each a partial JSON string that must be fully accumulated and parsed at content_block_stop.

Parsing a fragment fails.

04Display each event to the
× Looks right
Display each event to the user immediately.
✓ What wins
Some events (MessageStart) are metadata, not displayable.

Filter: display only ContentBlockDelta.text. Meta events go to logging.

05Cancel a streaming request mid-stream
× Looks right
Cancel a streaming request mid-stream by closing connection.
✓ What wins
Closing stops receiving, but request is still processed server-side and billed.

Cancellation is not a cost-saving mechanism.

11 · Compare

Side-by-side

↔ scroll to compare
AspectStreamingNon-streamingPolling endpointWebSocket
Time to first token100-200msEntire response timeBatch delaySimilar to streaming
CostSame per tokenSame per tokenSameSame
ConnectionHTTP SSERequest/responseRepeated pollingPersistent TCP
UXReal-time, progressiveBatch, instant or long waitPolling jitterReal-time, lowest latency
ComplexityEvent loop, bufferSimplePoll interval tuningServer upgrade
Best forChat UIs, long-formQuick queries, APIsLegacy systemsHigh-frequency real-time
12 · When to use

Decision tree

01

Response >1000 tokens (likely >10 seconds)?

YesStream to show progressive output and reduce perceived latency.
NoNon-streaming fine; instant response either way.
02

User-facing chat or interactive interface?

YesStream. Improves UX dramatically.
NoNon-streaming acceptable for backend tasks.
03

Agentic loop with tool_use blocks?

YesStreaming still works; tool input arrives as partial JSON. Buffer until ContentBlockStop before parsing.
NoSimple text streaming.
04

Need to reconnect on network failures?

YesImplement exponential backoff on stream exception; buffer received tokens.
NoSingle-shot, no retry needed.
05

Bandwidth a constraint?

YesStreaming doesn't help. Same total bytes. Use compression or prompt caching.
NoStreaming is purely UX.
13 · Exam trap

The exam trap

Treating the stream as finished once text appears, or parsing each tool-input fragment as JSON. A tool call's input is parseable only after its content_block_stop event, the response is complete only at message_stop, and an error can still arrive as an event inside a stream that started normally.

Streaming exam trap, painterly cautionary scene featuring Loop mascot.
14 · On the exam

Question patterns

CCD-F practice questions

3 approved CCD-F questions for this topic. Tap an answer to check it, then read the rationale for every option.

Question 1 of 3 · D2Choose the best answer

A team marks their entire growing message list (every user and assistant turn so far) with cache_control: {"type": "ephemeral"} in a 15-turn agentic loop, expecting cost savings on every turn. Why does this fail to deliver the expected savings?

Practice this topic with CCD-F questions

CCA-F practice questions

3 approved CCA-F questions for this topic. Tap an answer to check it, then read the rationale for every option.

Question 1 of 3 · D4Choose the best answer

A customer-facing chatbot is wired to the Batch API to save money. What goes wrong in production?

Practice this topic with CCA-F questions

15 · FAQ

Frequently asked

Showing 12 of 12 questions

16 · Sources

Sources and next steps

CCD-F exam guide: Domain 2, Applications and Integration

Help someone pass

Share this concept.

One share is one less person stuck on the same question.

Last reviewed: ·Refresh cadence: monthly