New in Redocly CLI
Your API says one thing.
Your docs say another.
Nobody notices, because nothing fails – until an SDK breaks in a customer's build.
The gap has a name: drift. proxy records what your API actually does. drift compares it against what your OpenAPI description claims.
npm i -g @redocly/cli@latestredocly drift – report
Exchanges: total=2 documented=2 undocumented=0
Findings: total=3 error=2 warning=1 info=0
→ Response field "page.total" must be string.
↳ sample exchange=0 GET /menu (200) listMenuItems
expected: type "string" · actual: 5
⚠ Undocumented query parameter in traffic: "category"
↳ sample exchange=1 GET /menu (200) listMenuItems
→ exit code 1 — drift detected
5
traffic formats supported
4
built-in rule packs
0
lines of extra test code
1
exit code that fails the build
/ The problem
Nothing warns you about drift. Your customers find it first.
Drift builds up one hotfix and one forgotten field at a time. Your linter cannot see it, because the linter only reads the description. Only the traffic shows what the API really does.
Generated SDKs break
An SDK generated from a stale description compiles fine – then throws in production when the API returns a field the types do not declare.
Partner integrations choke
A partner builds against a field that was "documented" but never actually returned. Their integration fails, and your support queue hears about it first.
Shadow endpoints ship
Endpoints and parameters nobody documented run in production anyway – invisible to your security review, your gateway policies, and your API governance.
/ How it works
Record first. Compare later.
Two commands, one plain HAR file between them. Use them together, or feed drift traffic you already have – browser DevTools exports, Kong, Nginx, or Apache logs.
Capture what your API actually does. A local reverse proxy in front of your API. Point any client at it – a browser, a test suite, a curl script – and every exchange is captured into a standard HAR file.
- ✓Streams to disk as it captures – nothing held in memory
- ✓Validates live against your description with
--api - ✓Requests pass through unchanged
Compare it against what you claim. Replays recorded traffic against your OpenAPI description, matches each exchange to a documented operation, and reports every discrepancy it finds.
- ✓Undocumented endpoints, parameters, and headers
- ✓Request and response schema mismatches
- ✓Reports as pretty text, JSON, CSV, or SARIF
Your clients
tests · curl · browser
redocly proxy
records → capture.har
redocly drift
+ openapi.yaml
Drift report
exit code 1 on error
/ Two-minute demo
Find real drift
in two requests
No setup required – try it against Redocly Cafe, our public demo API. Change one field in the description, and drift finds it, together with a problem you did not add.
- 1
Start a proxy in front of the live API
One command, and every request that flows through
localhost:4040is on the record. - 2
Send some traffic through it
Two curl requests are enough. Press
Ctrl+Cand the proxy writes the HAR file. - 3
Break the description on purpose
Change
page.totalfromintegertostringin the Cafe OpenAPI description. This is a typical silent drift. - 4
Replay and read the report
The error is the change you made in step 3. The warning – an undocumented
categoryquery parameter – is drift that was already there. Two requests were enough to find a real problem.
cafe-demo – bash
$ redocly proxy --target https://api.cafe.redocly.com --har ./cafe.har
Proxy listening on http://localhost:4040 → forwarding to https://api.cafe.redocly.com/
Recording traffic to ./cafe.har — press Ctrl+C to stop.
$ curl http://localhost:4040/menu
$ curl "http://localhost:4040/menu?category=dessert"
^C
Captured 2 exchange(s) to ./cafe.har
$ redocly drift ./cafe.har --api ./cafe-openapi.json
| Exchanges: total=2 documented=2 undocumented=0
| Findings: total=3 error=2 warning=1 info=0 ✖
| Problems: total=2
✖ ERROR #1 ×2 → Response field "page.total" must be string.
↳ sample exchange=0 GET /menu (200) listMenuItems
▲ WARN #2 → Undocumented query parameter in traffic: "category"
↳ sample exchange=1 GET /menu (200) listMenuItems
Your e2e tests are already writing contract tests. Stop throwing them away.
Every test run sends realistic traffic to your API – and then discards it.
Start proxy before the run, route the tests through it, and replay the capture with drift when they finish.
ci-contract-check.sh
redocly proxy --target http://localhost:9000 \
--har ./test-traffic.har &
PROXY_PID=$!
# run your e2e tests against http://localhost:4040
npm run test:e2e
kill "$PROXY_PID" && wait "$PROXY_PID"
redocly drift ./test-traffic.har --api ./openapi.yaml
# exits 1 on drift and fails the pipeline
The proxy sits between your tests and the API: requests pass through unchanged, and every exchange is captured on the way.
- ✓Every test run doubles as a contract check
- ✓Zero extra test code to write or maintain
- ✓Exit code 1 on error-level findings fails the pipeline
- ✓SARIF output plugs straight into code scanning
/ Built-in rules
More than schemas
Findings come from four built-in rule packs. Run them all, or pick a subset with --rules
Find the endpoints nobody wrote down. Flags traffic that doesn't match any documented operation – the shadow API your governance never sees.
Validate every payload against its schema. Validates parameters, headers, and request/response bodies against your schemas, powered by the same engine that lints your descriptions.
Check that security requirements are enforced. Checks that requests actually satisfy the security requirements your description declares, and flags credentials sent over plain HTTP. Loopback hosts are exempt, so local sandboxes stay warning-free.
Scan traffic with OWASP heuristics. Looks for credential-like query parameters, insecure CORS, weak cookie attributes, sensitive-looking response fields, and large unpaginated responses – based on the OWASP API Security Top 10.
/ Interoperability
Works with the logs you already have
No agents to install, no vendor lock-in. If you have traffic, you can check it – and the report goes wherever your tooling lives.
Traffic in
Reports out
Experimental: both commands support OpenAPI 3.x descriptions only, and flags, output formats, and behavior may change – including breaking changes – while we shape them with your feedback.
“Your API and its description should tell the same story. Now you can check.”
Frequently asked questions
npm i -g @redocly/cli@latestredocly proxy --target http://localhost:9000 --har capture.harredocly drift capture.har --api openapi.yaml