Docs / Capturing traffic
Update from a recording
Find out whether a diagram still matches what the API really does, and fix it when it does not.
On this page
Diagrams go stale. A field gets renamed, a number becomes a string, a 200 becomes a 201, and the diagram goes on saying what used to be true. Update from recording, also called Drift Check, compares a diagram with a recording of the real traffic, marks every step that no longer matches, and updates those steps for you.
It is free in the editor, needs no account, and runs entirely in your browser.
Try the demo
Open the Drift Check demo. It loads the OAuth client credentials example together with a recording in which the auth server has started returning expires_in as a string and the client no longer sends scope. Two steps drift, and the bar under the diagram offers to fix them.
Run a check
- Open the diagram in the editor.
- Record the flow in your browser and save a HAR file.
- Click Update from recording in the bar under the diagram and pick the file.
You can also drop the HAR file on the editor and choose Compare with this diagram in the import dialog.
The check runs again on every edit, so you can fix things by hand and watch the marks clear. Click Check another recording to switch files, and Close the recording when you are done.
Reading the results
A bar in the diagram pane shows the recording's name, a count for each status, and a verdict such as "2 steps differ from the recording." Each checked arrow gets a mark, and selecting an arrow shows the details in the inspector: what was recorded, and each field that differs.
| Status | Meaning |
|---|---|
| Match | The request was recorded and nothing important differs. |
| Drifted | The request was recorded, but a documented field was not sent or received, a JSON type changed, the reply's status code differs, or it happened earlier than the diagram says. |
| Missing | No matching request was recorded at all. Its replies are skipped. |
| Skipped | The step is in an if branch the real server did not take, such as the error branch when the call succeeded. |
| Undocumented | A recorded request the diagram never mentions. Listed separately; it does not count as drift. |
Fields the recording has but the diagram does not show are reported as "seen, not documented". They do not make a step drift, because diagrams often leave out fields on purpose, but Update will add them.
Use First issue and Next issue to walk through the steps that need attention.
Updating steps
Click Update this step from the recording in the inspector, or Update N steps in the bar to update everything at once. For each step, Volley:
- keeps your example values for fields that still exist;
- adds fields the recording has and the diagram lacks, with secrets redacted;
- removes documented fields the recording no longer has;
- takes the recorded value when a field's type changed;
- updates the status code in a reply when it changed within the same class, such as
200 OKto201 Created. A change from success to failure is left for you to decide.
JSON, form and parameter payloads are updated. Header lists, raw http blocks and text payloads are left as they are. Every update can be undone from the notice that appears.
Adding undocumented requests
Click the undocumented count to see the requests the diagram does not mention, then Add all N to the diagram (or Add it to the diagram for one). They are written at the end of the source, using the diagram's own lane names, ready for you to move into place. On Free, up to 8 are added at a time; on Pro, up to 500.
How steps are matched
Only messages that read like HTTP calls are checked: a solid or bold arrow whose text starts with an uppercase method and a path, such as POST /oauth2/token or GET https://api.example.com/invoices. Text after the path is fine. Messages that do not look like this are left alone, and if none do, the bar says so.
- Method and path. The method must match. The path must have the same number of segments, and each segment must be equal or a placeholder:
{id},:id,<id>,[id]or*. Two example ids of the same kind also match, such asinv_123andinv_9001, or two UUIDs. - Host. Checked only when the message has a full URL.
- Query strings are ignored for matching.
- Order. Each recorded request is used once, and Volley looks forward through the recording as it walks the diagram. A request found only earlier is still matched but marked as out of order.
- Replies. A dashed reply's expected status is the three-digit number at the start of its text. When an
ifhas a reply per branch, the one whose status the server returned is the branch that was taken.
How payloads are compared
- Names and types, never values. Diagrams hold examples, so
"id": "inv_123"and"id": "inv_9001"match. A number that became a string does not. - JSON is compared four levels deep. Arrays are compared by their first item.
- Header lists are checked for presence only, and
Authorization,CookieandProxy-Authorizationare never reported missing. - Placeholders such as
<redacted>,***or a value ending in...are not type-checked. - Text payloads are not compared.
- On the request side, the body is compared, or the query parameters when there is no body.
In CI
Check diagrams on every pull request so they cannot drift unnoticed. Record the traffic with your end-to-end tests, then verify each diagram against the recording.
With the command line tool
Run the command line tool from a checkout of the Volley repository:
node bin/volley.ts verify docs/checkout.volley test-results/checkout.harIt prints a report like this one, from the demo:
DRIFT #1 POST /oauth2/token (line 4)
1 documented field not sent.
input scope: documented, not seen
DRIFT #2 200 OK (line 11)
1 field changed type, 1 undocumented field.
output expires_in: was number, now string
output scope: seen, not documented
ok #3 GET /invoices?status=open (line 21)
ok #4 200 OK (line 25)
output [].due_at: seen, not documented
Recorded requests the diagram does not mention (1):
POST api.example.com/invoices/inv_9001/reminders (202)
4 checked: 2 match, 2 drifted, 0 missing, 0 skipped. The diagram has drifted from the recording.It exits with 0 when the diagram matches, 1 when it has drifted and 2 when it could not run. Add --strict to fail on undocumented requests too, --host to check one service, and --json for a machine-readable report.
With the HTTP API
Call POST /api/v1/verify with an API key. This GitHub Actions job records a Playwright run and fails when the diagram has drifted:
name: Diagram drift
on: [pull_request]
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Record traffic
run: npx playwright test checkout.spec.ts
- name: Check the diagram against the recording
env:
VOLLEY_KEY: ${{ secrets.VOLLEY_KEY }}
run: |
jq -n --rawfile source docs/checkout.volley \
--slurpfile har test-results/checkout.har \
'{source: $source, har: $har[0]}' > verify.json
curl -s --fail-with-body https://volley.sh/api/v1/verify \
-H "Authorization: Bearer $VOLLEY_KEY" \
-H "Content-Type: application/json" \
--data-binary @verify.json > report.json
jq -r '.messages[] | "\(.status)\t#\(.index)\t\(.summary)"' report.json
jq -e '.passed' report.json > /dev/nullTo record a HAR file with Playwright, create the browser context like this:
const context = await browser.newContext({
recordHar: { path: "test-results/checkout.har", content: "embed" },
});Each verify call counts as one API call against your monthly allowance.