Skip to content

run

Replayable flows

Since 0.2.1 Requires Cloak Proxy 0.2.1 or later.

Turn captured requests, such as log in, create an order and pay, into an API client flow that reads fresh IDs, tokens and cookies from each response.

Make Replayable Flow turns a sequence of captured requests into a flow in the API client that sends them again in order. Replaying captured requests as they are usually fails: the order ID in step 3 belongs to an order the server created during the capture, and the access token from the login has expired. A replayable flow fixes that by reading every value a later request reuses from the fresh response of an earlier one, so each run works with new IDs and tokens. Load-testing tools call this correlation.

Use it to reproduce a bug that needs several calls, to keep a smoke test of a real user journey, or to start a test from what your app actually does.

  1. In the traffic list, select the requests of the journey, for example the login, the order and the payment. Order doesn’t matter: Cloak Proxy sorts them by when they started.

    To pick every request that carried one value, trace it and click Make Replayable Flow in the Trace Value window instead.

  2. Right-click one of the selected requests and choose Make Replayable Flow from N Requests… (or Make Replayable Flow… for one request).

    The sheet lists the steps and the values it will chain between them.

  3. Check Values chained. Each entry says which response provides the value and which later requests use it.

  4. Change the Flow name if you like, and choose whether to check each step’s status.

  5. Click Create Flow (or press Return).

    The API client opens on Flows with the new flow selected.

  6. Click Run (⌘ ↩) to replay it.

Make Replayable Flow… is unavailable when you right-click an encrypted tunnel, and tunnels in a selection are left out.

Three values chained across four steps: a token, a user ID and an order ID.

  1. Flow name. Also the name of the new collection.
  2. The steps, in the order they were captured.
  3. The variable the flow uses, and the captured value.
  4. Which response provides it, and which requests use it and where.
  5. Add a Check after each step that succeeded when captured.
  6. Create the collection and the flow, and open it.
The Make Replayable Flow sheet for four ShopApp requests: log in, create an order, get the order and pay, with three chained values, accessToken from step 1's body $.access_token used in the Authorization header of steps 2 and 3, userId from step 1 used in the X-User-Id header of step 4, and orderId from step 2's body $.data.order.id used in the path of step 3 and the order_id query parameter of step 4
Part What it shows or does
Flow name The name of the flow and of its collection. It starts as Replay: followed by the first request’s method and path and how many more there are, such as Replay: POST /v1/login and 3 more.
Steps (N) One line per request: method, host and path, in time order.
Values chained (N) Every value carried from a response to later requests: the variable, such as {{orderId}}, the captured value (long ones are shortened, such as eyJhbGciOiJI…iJ9.c2ln), From step N’s response, and where in it, and Used in with each step and where. When there are none, it says No later request reuses a value from an earlier response, so the steps replay as captured.
Check that each step succeeds, like it did when captured On by default. Adds a Check block after each step whose captured status was below 400.
Cancel Closes the sheet (Esc).
Create Flow Creates the collection and the flow, and opens the flow in the API client.

On Linux, Make Replayable Flow… opens in a small window of its own rather than a sheet, with the same parts.

Two things go into your workspace:

  • A collection named like the flow, with one request per step, named by number and request, such as 1. POST /v1/login and 2. POST /v1/orders. Each one is a copy of the captured request, made the same way as Save to API Client: the method, URL, headers and decompressed body, with the captured response saved as an example. Chained values are replaced with {{variables}}.
  • A flow in Flows with the same name. It runs the steps in order.

For each step, the flow has these blocks:

Block Example What it does
Send Request step2 Sends the step’s request and saves the result as step1, step2 and so on.
Check step2.status < 400, message Step 2 (POST api.shopapp.example/v1/orders) should succeed, like it did when captured (201) Fails the run if the step didn’t succeed. Only when the status check is on and the step succeeded when captured.
Set Variable orderId = step2.body.data.order.id Reads a value from this step’s fresh response for later steps. One per value the step provides.

For the screenshot above, the flow looks like this:

Replay: POST /v1/login and 3 more
Send Request 1. POST /v1/login → step1
Check step1.status < 400
Set Variable accessToken = step1.body.access_token
Set Variable userId = step1.body.user.id
Send Request 2. POST /v1/orders → step2 (Authorization: Bearer {{accessToken}})
Check step2.status < 400
Set Variable orderId = step2.body.data.order.id
Send Request 3. GET /v1/orders/{{orderId}} → step3 (Authorization: Bearer {{accessToken}})
Check step3.status < 400
Send Request 4. POST /v1/payments?order_id={{orderId}} → step4 (X-User-Id: {{userId}})
Check step4.status < 400

It’s an ordinary flow: you can edit, reorder or delete blocks, add Output blocks, set inputs, or automate it. See Flows for every block.

Cloak Proxy goes through the steps in order. For each response, it collects the values that look like identifiers, then checks whether a later request uses them.

  1. Find candidate values in a response. It looks at every string and number in a JSON response body (up to the first 200 items of each array) and at the response headers, except standard ones such as Date, Content-Type, Set-Cookie, ETag, Cache-Control, Server and the security headers.

  2. Keep only values that look like IDs or tokens. A value qualifies when it:

    • is at least 4 characters long, with no spaces, and
    • contains a digit, or is at least 20 characters long, and
    • isn’t a Unix timestamp in seconds or milliseconds, a date such as 2026-10-14, a version number such as 1.2.3, or a number with fewer than 5 digits.

    So fc68188e, usr_42ab and a JWT qualify; true, admin, 2026-10-14T10:00:00Z and 1760436000 don’t.

  3. Skip values the app made itself. If an earlier request (or the same one) already sent the value, the server didn’t create it, so it isn’t chained.

  4. Find where later requests use it. It searches each later request’s path, query parameters, headers and body (form fields or raw text). A value must match as a whole token: 48213 isn’t replaced inside 948213, but is in /orders/48213 or "id": "48213".

  5. Replace it with a variable. Every use in a later request becomes {{variable}}, and a Set Variable block after the providing step reads the fresh value. A value is chained from the first response that has it, once.

Values that no later request uses aren’t chained. Values the app got before the first selected request, such as a token from a login you didn’t select, stay exactly as captured.

The variable is named after where the value was in the response:

Found at Variable Read with
body $.access_token accessToken step1.body.access_token
body $.user.id userId step1.body.user.id
body $.data.order.id orderId step2.body.data.order.id
body $.items[0].sku_code skuCode step3.body.items[0].sku_code
header X-Request-Id requestId step1.headers["x-request-id"]

The name comes from the last key, in camelCase. When that key is a generic word such as id, uuid, token, key, code, value or number, the key before it is added in the singular: orders.id gives orderId. Header names lose an X- prefix. If two values would get the same name, the second gets a number, such as orderId2. Names that clash with flow variables, such as response, item, index, trigger, vars and step1, are avoided the same way.

Cookies come from the run, not the capture. When an earlier step’s response set a cookie with Set-Cookie, that cookie is removed from the captured Cookie header of later requests. When the flow runs, the API client’s cookie jar sends the fresh cookie the server set during the run.

A request’s own Cookie header and the cookie jar are merged: the request sends its own cookies plus every cookie from the jar it doesn’t already have. When both have a cookie with the same name, the request’s own value wins.

In the API client, open the flow under Flows and click Run (⌘ ↩). The Run pane shows each step with its status and time, the chained values being set, and whether each check passed. See Read the run results.

From the command line, run it with cloakctl flow run, for example from CI or cron. The command exits with 1 when a check fails:

Terminal
cloakctl flow run "Replay: POST /v1/login and 3 more"

The requests use the API client’s settings, the active environment and your variables. To run the same flow against staging, replace the host in each request with a variable such as {{baseUrl}} and set it per environment.

Problem What to do
The first request fails with 401 Its credentials or token came from before the capture and have expired. Select the login request too, or update the token in the first request.
A later step fails with 404 or 400 A value wasn’t chained: it may be computed by the app, sent in a shape Cloak Proxy doesn’t recognize, or too short to qualify. Find it with Trace Value, then add a Set Variable block and put {{name}} in the request yourself.
A step fails because a value is a one-time code Codes sent by email or SMS, CAPTCHA answers and signed nonces can’t be replayed. Replace that step, or start the flow after it.
A Check fails The step returned a status of 400 or higher. Read the step’s response in the Run pane. A status that differs from the capture but is below 400, such as 200 instead of 201, passes.

The MCP server has a build_replay_flow tool. It takes ids (the request numbers, in any order), and optionally name (default Replay of N requests) and check_status (default true). It creates the collection and the flow, opens them in the API client, and returns the steps and every chained value with where it comes from and where it’s used. Run the flow with run_flow. See the MCP tools reference.