What it is
A check of type multistep owns an ordered list of steps, each its own HTTP request: method, URL, an optional body and content type, and its own assertions. Steps run in order against a single cookie jar, so a session cookie set by step one's response is sent automatically on every request after it. The check is up only if every step passes, in order; the first step that fails ends the run there, and which step it was is recorded in the down reason, for example Step 2 ("Load account"): expected status 200, got 401.
It runs from RealUptime's own cloud probes, in the regions you pick for it, the same as an HTTP check. It is not agent-bound: the Monitor agent does not run multi-step journeys today, the same boundary browser checks draw for their own reason. A multi-step check counts as one monitor against your plan's allowance, on every plan, exactly like any other check type -- there is no separate tier gate on the check type itself.
When to use it
Reach for a multi-step check when a single request cannot tell whether the thing that matters is actually working: a login that has to succeed before the page behind it means anything, an API that needs a resource created before it can be read back, a multi-request handshake where an intermediate step is the one that actually breaks. A plain HTTP check on any one of those URLs in isolation can stay green while the flow that connects them is down.
Steps
Each step has:
- Name -- a label shown in the down reason if this step fails.
- Method --
GET,POST,PUT,PATCH,DELETE, orHEAD. - URL -- validated the same way as any other check's target, on every step, every run.
- Body and content type -- optional, and independent of each other: a step can set a body with the default content type, or a content type on an empty request. Only sent on the step's own request, never replayed onto a redirect.
A journey holds at most 10 steps. A request over that limit is refused before anything is saved.
Assertions
Each step can set its own assertions, evaluated in this order -- status, then body, then header, then JSON path -- and a failing check in one group stops evaluation there rather than reporting every mismatch at once:
- Status -- an inclusive range (min and max; an exact status is min = max) replacing the default 2xx-is-up rule for this step.
- Body -- contains or does not contain a literal string, with a case-sensitivity toggle. Never a regex: a customer-authored pattern evaluated on every probe tick is a ReDoS surface, the same reasoning that keeps regex out of a plain HTTP check's own assertions.
- Header -- a named response header equals or contains a value you set.
- JSON path -- a field in a JSON response, addressed the way you'd read it in code (
data.status,data.items[0].name), required to equal a value, to contain one, or simply to exist. Paths are plain keys and indexes only -- no wildcards, no filters, no recursive descent -- and a path using one is refused when you save it.
A step needs no assertions at all: with none set, it passes on the default 2xx-is-up rule alone, the same as a plain HTTP check.
The cookie jar
Every Set-Cookie header seen on every step's response, redirects included, is merged into one jar and sent back on every request after it. This is what makes "log in, then act as that session" representable at all -- a login step's session cookie reaches every later step with nothing to configure. There is no other value-passing between steps in v1: a response body field from step one cannot be extracted and inserted into step two's URL or body. If a flow needs that, only the parts reachable through cookie-based session state are expressible today.
Redirects
A step's own request carries its configured method and body. Up to three redirect hops after that are followed as bare GET requests with no body -- a login POST's credentials are never forwarded to a redirect target on its say-so. Assertions run against the final, non-redirect response.
Limits
- Up to 10 steps per check.
- A 10-second timeout per step's own request (and per redirect hop within it).
- A 45-second ceiling on the entire journey, regardless of step count.
- Up to 256 KB of a step's response body is read for a body or JSON-path assertion.
- Editing an existing check's steps replaces the whole ordered list at once -- there is no add/remove/reorder-one-step call, so the edit form always submits every step's current state.
Examples
Login, then load the account page
Step one logs in and only checks that the response looks like a successful sign-in; step two relies on the cookie step one set and confirms the account payload actually has a plan on it, not just that the endpoint answered.
Step 1 POST https://app.example.com/api/login
body: {"email":"probe@example.com","password":"..."}
assert: status 200-204
Step 2 GET https://app.example.com/api/account
assert: status 200
assert: json data.plan existsCreate a resource, then read it back
Step one creates something through your API; step two reads the list back and asserts the created item is actually in it, catching an API that returns 201 for a write that silently failed to persist.
Step 1 POST https://api.example.com/v1/widgets
body: {"name":"probe-widget"}
assert: status 201
Step 2 GET https://api.example.com/v1/widgets?name=probe-widget
assert: status 200
assert: json data.items[0].name equals "probe-widget"