CertSafari
    CLAUDE-CERTIFIED-DEVELOPER-FOUNDATIONS-CCDV-F · Lessons

    Domain 5 · Lesson 13/25

    Streaming Claude Responses with Server-Sent Events

    Technical Fundamentals

    7 min read
    4.2% of exam
    4 sources
    Published 29 Sep 2026
    Docs as of 26 Sep 2026

    What you will be able to do

    • Explain why Claude streaming uses server-sent events over HTTP, and what the sources do and don't say about websockets
    • Choose between stream=True and the SDK stream helper for a given memory or convenience need
    • Walk through the order of stream events and assemble content blocks by index
    • Rebuild a tool's input from partial_json deltas and handle error events that arrive mid-stream

    1.Streaming is SSE on a REST call, not a websocket

    When you stream from the Claude API, you are still making an ordinary HTTP request. You set "stream": true on a Messages request, and the response comes back as a sequence of server-sent events (SSE) over the same connection. The Python and TypeScript SDK docs both describe their streaming support as SSE.

    This matters for integration design. SSE sends data in one direction only, from server to client, over a single request. The client doesn't send anything more on that connection. The next turn is a new request carrying the full message history.

    Sources123

    2.Two ways to stream with an SDK

    The Python and TypeScript SDKs each give you two options. client.messages.create(..., stream=True) returns the raw events as an iterable. It uses less memory because it never builds a final message object for you. client.messages.stream(...) is a helper with extra conveniences: it accumulates the text and can return the finished message at the end.

    Raw event iteration versus the stream helper
    ApproachWhat you getTrade-off
    client.messages.create(..., stream=True)An iterable of the events in the streamUses less memory; you build the final message yourself
    client.messages.stream(...)Helpers such as text_stream and get_final_message()Accumulates the complete Message object for you

    The helper also matters when you don't need the text as it arrives. With a large max_tokens, a non-streaming request can run into HTTP timeouts, so the SDKs require streaming. The helper lets you stream internally and still get back the same complete Message object that .create() would return.

    Streaming internally for a large max_tokens request, then reading the complete Messagepython
    with client.messages.stream(
        max_tokens=128000,
        messages=[{"role": "user", "content": "Write a detailed analysis..."}],
        model="claude-opus-5-5",
    ) as stream:
        message = stream.get_final_message()

    In TypeScript the equivalent call is .finalMessage(). To cancel a TypeScript stream, break out of the loop or call stream.controller.abort().

    An engineering team maintains a custom SSE event handler for the Messages API. After an Anthropic API update, their handler throws an unhandled exception whenever it encounters an event type it does not recognize, causing the entire stream connection to be dropped. According to Anthropic's guidance on the event stream, what should the handler do instead?

    Sources31

    3.The event flow of one stream

    Every stream follows the same sequence. It opens with message_start, which carries a Message object with empty content. Then each content block arrives as a content_block_start, one or more content_block_delta events, and a content_block_stop. After that come one or more message_delta events with top-level changes to the Message, and finally message_stop. ping events can appear anywhere in the stream.

    Stream events in order
    EventMeaning
    message_startA Message object with empty content
    content_block_start / content_block_delta / content_block_stopOne content block, built up by deltas; index matches its position in the final content array
    message_deltaTop-level changes to the final Message object
    message_stopEnd of the stream
    pingMay appear any number of times

    Sources1

    4.Reassembling tool_use input from partial JSON

    Text blocks stream as text_delta fragments that you join together. Tool calls work differently. The deltas for a tool_use block are input_json_delta events, and each one carries a partial_json string. Those fragments are not valid JSON by themselves, and only the finished tool_use.input is an object.

    A tool_use delta carries a fragment of JSON, not an objecttext
    event: content_block_delta
    data: {"type": "content_block_delta","index": 1,"delta": {"type": "input_json_delta","partial_json": "{\"location\": \"San Fra"}}}

    The correct approach is to collect the string fragments for that block's index and parse them once content_block_stop arrives. The alternatives are a partial-JSON parser such as Pydantic, or the SDK helpers that give you parsed values as they come in. Current models emit one complete key and value from the input at a time, so a tool block can go quiet for a while before a burst of deltas.

    A team monitoring their Claude API streaming integration notices periodic ping events interspersed with content_block_delta events in their SSE logs, with no impact on the assembled message content. What is the correct handling for these events?

    Sources1

    5.Errors that arrive after a 200

    The page on HTTP errors explained status-code handling, but a stream breaks that model. The API has already returned 200 before the first event is sent, so a failure after that point arrives as an error event inside the stream. For example, under heavy load you can get an overloaded_error event, which in a non-streaming call would have been an HTTP 529.

    An error delivered inside an SSE streamtext
    event: error
    data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}

    Sources14

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Each input_json_delta contains a usable input object, so you can pass each one to the tool as it arrives.Why is that wrong?

      The deltas are fragments of a JSON string. Concatenate them for the block and parse once content_block_stop arrives. Only the final tool_use.input is an object.

      Covered in Reassembling tool_use input from partial JSON

    2. 2.Once a streaming request returns HTTP 200, the rest of the response is guaranteed to succeed.Why is that wrong?

      Errors can arrive after the 200 as error events inside the SSE stream, and they don't go through normal HTTP error handling.

      Covered in Errors that arrive after a 200

    3. 3.If you need the complete Message object, you can't stream and have to make a plain non-streaming call, even with a very large max_tokens.Why is that wrong?

      The SDK stream helper streams internally and returns the same complete Message. For large max_tokens values, the SDKs require streaming to avoid HTTP timeouts.

      Covered in Two ways to stream with an SDK

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “When creating a Message, you can set "stream": true to incrementally stream the response using server-sent events (SSE).”
      ↩︎ Streaming is SSE on a REST call, not a websocket
      “This is especially useful for requests with large max_tokens values, where the SDKs require streaming to avoid HTTP timeouts.”
      ↩︎ Two ways to stream with an SDK
      “Each content block has an index that corresponds to its index in the final Message content array.”
      ↩︎ The event flow of one stream
      “new event types may be added, and your code should handle unknown event types gracefully.”
      ↩︎ The event flow of one stream
      “You can accumulate the string deltas and parse the JSON once you receive a content_block_stop event”
      ↩︎ Reassembling tool_use input from partial JSON
      “during periods of high usage, you may receive an overloaded_error, which would normally correspond to an HTTP 529 in a non-streaming context”
      ↩︎ Errors that arrive after a 200
      “the deltas are partial JSON strings, whereas the final tool_use.input is always an object.”
      ↩︎ Exam trap 1
      “This is especially useful for requests with large max_tokens values, where the SDKs require streaming to avoid HTTP timeouts.”
      ↩︎ Exam trap 3
    2. 2.
      “The Claude API is a RESTful API at https://api.anthropic.com that provides programmatic access to Claude models and Claude Managed Agents.”
      ↩︎ Streaming is SSE on a REST call, not a websocket
    3. 3.
      “The SDK provides support for streaming responses using Server-Sent Events (SSE).”
      ↩︎ Streaming is SSE on a REST call, not a websocket
      “Alternatively, you can use client.messages.create(..., stream=True) which only returns an iterable of the events in the stream and uses less memory”
      ↩︎ Two ways to stream with an SDK
    4. 4.
      “When receiving a streaming response over server-sent events (SSE), an error can occur after the API returns a 200 response.”
      ↩︎ Errors that arrive after a 200
      “When receiving a streaming response over server-sent events (SSE), an error can occur after the API returns a 200 response.”
      ↩︎ Exam trap 2

    Ready to test yourself?

    Practise the 20 questions on this subdomain.