Product documentation
Updated September 27, 2026

Testing Server-Sent Events (Streaming) Responses

Test endpoints that answer with text/event-stream: see each event in the response viewer, assert on events, and stream with limits on events, duration and idle time.

View as Markdown

Applies to: All editions · Web app and Desktop app

Overview

Some endpoints do not return one response body. They answer with text/event-stream and send a series of events over time — an AI model streaming its answer word by word, a live feed of updates, or an MCP server replying over Streamable HTTP. These are Server-Sent Events (SSE).

Shift-Left Studio reads these streams into a numbered list of events that you can see in the response viewer and assert on. You can check how many events arrived, what any or the final event contained, what the whole stream said once joined together, and a field inside any event's JSON.

For most streams you do not need to configure anything: Studio notices the event-stream response and parses it automatically. If you also need to measure how quickly the first event arrived, or to stop reading a long stream on your own terms, you can turn on streaming mode for a test.

Key concepts

TermMeaning
EventOne message in the stream. It has a payload (the data), and optionally a type (event) and an id.
Buffered modeThe default. Studio reads the whole response, then parses the events. Every SSE assertion except first-event latency works.
Streaming modeOpt-in per test. Studio reads the events as they arrive, which lets it measure first-event latency and stop the stream deliberately.
SentinelA marker that ends a stream, such as [DONE] at the end of many AI completions.
Whole streamThe payloads of every event joined together. Needed when text is split across events.

Before you begin

  • The endpoint must respond with the content type text/event-stream.
  • SSE options and assertions apply to REST tests. SOAP and GraphQL tests do not offer them, and WebSocket-RPC is not an HTTP response at all. JSON-RPC and MCP replies that arrive as an event stream are unwrapped automatically — you assert on them with the JSON-RPC assertions.
  • You need permission to edit tests.

Step 1 — Run the test and look at the events

  1. Open the test and run it as usual.
  2. Open the response. An event-stream response is shown as a numbered event list instead of raw text: each event shows its number, its type (message if none was given), its id if present, and its payload, pretty-printed where it is JSON.
  3. The header shows how many events arrived, for example 42 events.
  4. Click Raw to see the original stream text; click Auto to return to the event list.

If Studio kept only part of a very large stream, a Truncated for storage badge appears, and individual events that were cut short are marked clipped. The event count still reflects the full stream, so a count assertion is never fooled by the storage limit.

Step 2 — Add SSE assertions

  1. Open the test's assertions and add a new assertion.
  2. Choose from the Streaming (SSE) category.
  3. Enter the expected value and save the test.

Examples:

GoalAssertionValue
The model finished its answerSSE: Final Event Contains[DONE]
The answer mentions the order numberSSE: Whole Stream ContainsOrder 1042
At least one progress update arrivedSSE: Event Count Greater Than0
The first chunk identifies the speakerSSE: Event Field Equalschoices[0].delta.role equals assistant
An error event appeared somewhereSSE: Any Event Contains"error"

Tip: For AI completions, reach for SSE: Whole Stream Contains. A model streams "Hello" and " world" as separate events, so no single event contains "Hello world" — only the joined stream does.

Step 3 — Turn on streaming mode (optional)

Turn on streaming mode when you need either of these:

  • First-event latency — whether the service started responding promptly. Total duration cannot tell you this: a stream that answers instantly and then runs for 30 seconds takes as long as one that stalls for 29 seconds and then sends everything at once.
  • Deliberate termination — stop reading on a sentinel, after a number of events, after a time limit, or when the stream goes quiet, instead of waiting for the connection to time out.

To turn it on:

  1. Open the test in the test editor and go to its request configuration.

  2. Tick Stream the response (Server-Sent Events).

  3. Optionally set the stop conditions. Leave a field empty to use its default:

    OptionDefaultEffect
    Max events200Stop after this many events.
    Max duration (ms)60000Hard limit on how long the stream is read.
    Idle timeout (ms)15000Stop if the stream goes quiet for this long.
    Stop when an event contains—End the read as soon as an event's payload contains this text, for example [DONE].
  4. Add SSE: First Event Within (ms) with your latency target, for example 2000.

  5. Save and run.

Note: In streaming mode, the test's request timeout covers only the wait for the response to start. How long the stream itself is read is controlled by Max duration (ms), so you do not need to raise the request timeout for long streams.

Every streaming run records why reading stopped — the stream ended on its own, a stop phrase was found, the event limit or duration limit was reached, the stream went idle, or an error occurred. This lets you tell a complete short stream apart from one that was cut off.

Assertion reference

AssertionWhat it checksMode
SSE: Event Count EqualsThe stream delivered exactly this many events.Both
SSE: Event Count Greater ThanThe stream delivered more than this many events.Both
SSE: Any Event ContainsAt least one event's payload contains the text.Both
SSE: Final Event ContainsThe last event contains the text (for example [DONE]).Both
SSE: Whole Stream ContainsAll event payloads joined together contain the text.Both
SSE: Event Field EqualsSome event's JSON payload has a field at this path equal to a value. Use brackets for array positions, for example choices[0].delta.role.Both
SSE: First Event Within (ms)The first event arrived within this many milliseconds.Streaming only

If you add an SSE assertion to a test whose response is not an event stream, it fails with a clear message rather than passing silently. SSE: First Event Within (ms) on a buffered test tells you to turn on streaming mode. Dynamic tokens such as {{row.EXPECTED_EVENTS}} work in SSE assertion values, so data-driven tests can expect a different stream per row.

Generated tests

Test generation never adds SSE assertions automatically, for any protocol. API specifications do not mark an endpoint as streaming, so generated SSE checks would fail on endpoints that do not stream. Add them by hand to tests for streaming endpoints.

Worked example — an AI chat completion

A POST /v1/chat/completions endpoint streams a model's reply and ends with data: [DONE].

  1. Run the test once and confirm the response viewer shows an event list.
  2. Tick Stream the response (Server-Sent Events) and set Stop when an event contains to [DONE].
  3. Add these assertions:
    • SSE: First Event Within (ms): 3000 — the model starts answering within three seconds.
    • SSE: Event Field Equals: choices[0].delta.role equals assistant.
    • SSE: Whole Stream Contains: the phrase the answer must include.
    • SSE: Final Event Contains: [DONE] — the stream finished rather than being cut off.
  4. Save and run.

Troubleshooting

SymptomWhy it happensWhat to do
The response shows raw data: lines instead of an event listYou are in Raw view, or the response is not text/event-stream.Click Auto; check the response content type.
An SSE assertion fails with Response is not a text/event-streamThe endpoint did not stream for this request.Check the request (some APIs stream only when asked, for example with a stream: true flag).
SSE: First Event Within (ms) fails asking for streamingThe test runs in buffered mode.Tick Stream the response (Server-Sent Events).
The test hangs until timeoutThe stream never ends on its own.Turn on streaming mode and set Stop when an event contains or Max duration (ms).
SSE: Any Event Contains fails on text you can seeThe text is split across events.Use SSE: Whole Stream Contains.
Truncated for storage badge appearsThe stream exceeded what Studio keeps per run.Counts stay accurate; for content checks, stop earlier with Max events.
The streaming option is missingThe test is SOAP, GraphQL or WebSocket-RPC.SSE options apply to REST tests.

Best practices

  • Pair a content check with SSE: Final Event Contains so a stream cut off halfway is not mistaken for a complete one.
  • Set Stop when an event contains for streams that end with a sentinel; it makes runs faster and more predictable.
  • Use first-event latency, not total duration, to judge whether an AI endpoint is responsive.
  • Assert on fields in structured events with SSE: Event Field Equals rather than searching for text.

For administrators (self-hosted installations)

SettingDefaultWhat switching it does
SSE_STREAMING_ENABLEDtrueSet to false to turn off event-stream parsing and streaming mode.
SSE_MAX_STORED_EVENTS200Maximum events kept per response.
SSE_MAX_EVENT_BYTES8192Maximum bytes kept per event payload.
SSE_MAX_TOTAL_BYTES262144Maximum bytes kept across all events in one response.

Related articles

Next steps

Still stuck?

Tell us what you’re trying to accomplish and we’ll point you to the right setup—installation, auth, or CI/CD wiring.