Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gatling/gatling.io-doc/llms.txt

Use this file to discover all available pages before exploring further.

Gatling’s Server-Sent Events (SSE) support is an extension to the HTTP SDK that lets you load test streaming APIs that push real-time updates to clients. SSE is a unidirectional protocol: the server continuously sends events over a persistent HTTP connection, and the client only reads. Gatling models this as a separate branch within your scenario—running in parallel with regular HTTP actions—making it ideal for testing notification systems, live dashboards, stock feeds, and other push-based applications. The entry point for all SSE actions is sse("actionName").

Multiple SSE Streams Per User

When a virtual user must maintain more than one SSE stream at the same time, assign a distinct name to each stream and reference it on every subsequent action:
Java
sse("connect prices").sseName("prices").get("/prices/stream")
sse("connect news").sseName("news").get("/news/stream")

// later...
sse("close prices").sseName("prices").close()
If each user opens only one SSE stream, the sseName call is optional.

Connecting

Open an SSE stream with get (for GET requests) or post (for POST requests). Gatling automatically sets the Accept: text/event-stream and Cache-Control: no-cache headers required by the SSE specification. Both GET and POST are supported:
Java
// GET (most common for SSE)
exec(sse("subscribe updates").get("/updates"))

// POST with a request body
exec(sse("subscribe filtered").post("/events").body(StringBody("{\"filter\": \"#{category\"}"))))
Scala
// GET
exec(sse("subscribe updates").get("/updates"))

// POST
exec(sse("subscribe filtered").post("/events").body(StringBody("""{"filter": "#{category"}""")))
Gatling automatically adds Accept: text/event-stream and Cache-Control: no-cache headers—you do not need to set them manually.

close

Close the SSE stream when you no longer need it:
Java
exec(sse("close stream").close())

Checks

SSE checks validate incoming stream events. Gatling currently supports only blocking checks: the virtual user pauses until a matching event arrives or the timeout expires.

How Events Are Represented

When a check is applied, Gatling parses the raw SSE event into a JSON object, giving you access to all standard SSE fields via jsonPath or jmesPath. For example, the event:
id: 77535
event: snapshot
data: [{"symbol":"BTC","price":4628.27},{"symbol":"ETH","price":3249.19}]
becomes:
{
  "id": "77535",
  "event": "snapshot",
  "data": [
    {"symbol": "BTC", "price": 4628.27},
    {"symbol": "ETH", "price": 3249.19}
  ]
}
This allows you to apply standard check criteria on any field.

Set a Check After Connecting

Attach a check directly to the get or post action to validate the first message received:
Java
exec(
  sse("connect and await snapshot")
    .get("/market/stream")
    .await(10).on(
      sse.checkMessage("snapshot").check(
        jsonPath("$.event").is("snapshot"),
        jsonPath("$.data[0].symbol").is("BTC")
      )
    )
)

Set a Check from the Main Flow

After the connection is established, set additional checks from the main scenario flow using setCheck:
Java
exec(
  sse("wait for update")
    .setCheck()
    .await(15).on(
      sse.checkMessage("price update").check(
        jsonPath("$.event").is("update"),
        jsonPath("$.data.price").saveAs("latestPrice")
      )
    )
)

Multiple Check Sequences

You can configure multiple checks in a single sequence (each expecting one event) or multiple sequences with different timeouts:
exec(
  sse("await two events")
    .setCheck()
    .await(10).on(
      sse.checkMessage("first event").check(jsonPath("$.event").is("connected")),
      sse.checkMessage("second event").check(jsonPath("$.event").is("snapshot"))
    )
)

Creating Checks

Use sse.checkMessage("checkName") to create a check definition. The full set of Gatling HTTP check criteria is available, including jsonPath, jmesPath, bodyString, substring, and saveAs.
Java
sse.checkMessage("order confirmation")
  .check(
    jsonPath("$.event").is("order_filled"),
    jsonPath("$.orderId").saveAs("filledOrderId"),
    jsonPath("$.quantity").ofInt().greaterThan(0)
  )

Matching Messages

Use matching to filter which events a check targets. Non-matching events are silently ignored. The matching criterion does not accept saveAs.
Java
sse.checkMessage("my order only")
  .matching(jsonPath("$.orderId").is("#{orderId}"))
  .check(jsonPath("$.status").saveAs("orderStatus"))

Processing Unmatched Messages

Events that arrive but are not matched by any active check can be buffered for later processing. Enable buffering by setting sseUnmatchedInboundMessageBufferSize on the HTTP protocol:
Java
HttpProtocolBuilder httpProtocol = http
  .baseUrl("https://api.example.com")
  .sseUnmatchedInboundMessageBufferSize(100);
The buffer resets when:
  • an outbound message is sent
  • processUnmatchedMessages is called
Call sse.processUnmatchedMessages on the sse DSL object (not on a named action):
Java
sse.processUnmatchedMessages((messages, session) -> {
  // messages are sorted oldest-first (SseInboundMessage instances)
  // each message is the JSON string representation of the event
  return session.set("bufferedEventCount", messages.size());
})
Scala
sse.processUnmatchedMessages { (messages, session) =>
  session.set("bufferedEventCount", messages.size)
}

HTTP Protocol Parameters for SSE

The following options are available on the HTTP protocol builder when working with SSE:
Java
HttpProtocolBuilder httpProtocol = http
  .baseUrl("https://api.example.com")
  .sseUnmatchedInboundMessageBufferSize(50);

Debugging

To inspect SSE traffic at the FSM level, add the following logger to your Logback configuration:
logback-test.xml
<logger name="io.gatling.http.action.sse.fsm" level="DEBUG" />

Full Example

The following example simulates users connecting to a stock market SSE feed, waiting for a snapshot event, then periodically checking for price updates.
Java
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

public class SseSimulation extends Simulation {

  HttpProtocolBuilder httpProtocol = http
    .baseUrl("http://localhost:8080")
    .sseUnmatchedInboundMessageBufferSize(50);

  ScenarioBuilder scn = scenario("SSE stock market simulation")
    .exec(
      sse("connect market stream")
        .get("/market/stream")
        .await(10).on(
          sse.checkMessage("initial snapshot")
            .check(
              jsonPath("$.event").is("snapshot"),
              jsonPath("$.data").exists()
            )
        )
    )
    .pause(2)
    .repeat(5).on(
      exec(
        sse("wait for price update")
          .setCheck()
          .await(15).on(
            sse.checkMessage("price update")
              .matching(jsonPath("$.event").is("update"))
              .check(jsonPath("$.data.price").saveAs("price"))
          )
      )
      .pause(3)
    )
    .exec(sse("close stream").close());

  { setUp(scn.injectOpen(rampUsers(50).during(60))).protocols(httpProtocol); }
}

Build docs developers (and LLMs) love