Your test suite is green on your machine and red in CI, and neither result is about your code. A payment provider's sandbox is throwing 502s. A partner API is rate-limiting the build agent. Someone's staging environment is down for the third day running.
The fix is old and well understood: record the real response once, replay it afterwards. What has changed is where you can do the recording.
The pattern already has a name
If you have written Ruby you have probably used VCR. Python
has vcrpy, Node has nock and polly.js, Go has go-vcr. They all do the same thing:
intercept HTTP at the library level, write the response to a cassette file, and serve
that file on the next run.
It works. It is also why most teams end up with three of them.
Each cassette library binds to one HTTP client in one language. A Python service and a Node service testing against the same vendor keep two independent sets of recordings that drift apart. The cassettes live in the repo of whoever recorded them, so a fixture your teammate captured is not one you can use. And nothing records the traffic your mobile app or your CI container makes, because there is no library in the loop to hook.
Recording one layer down
An HTTP proxy sits below all of that. It sees the request no matter which language emitted it, which is why proxies are how you debug mobile and third-party traffic in the first place.
Proxycept is a hosted proxy, so recording is the thing it already does. Every request through a profile is captured with its response. Save as mock turns one of those captured flows into a mock route: same method, same host, same path, the recorded status, headers and body played back.
The practical differences from a cassette file:
- Any language, any client.
curl,requests,axios, an iOS app, a Playwright run: if it goes through the proxy it can be recorded, and there is nothing to install per language. - Shared, not local. The recording lives in a workspace. A mock your colleague captured on Tuesday is one your CI job can replay on Wednesday.
- Same endpoint for record and replay. Your test config points at the proxy either way; flipping the mock server on is what changes, not your code.
Doing it
- Start a profile and point the client at it. That is the same
HTTPS_PROXYyou would set for any proxy. No SDK, no code change. - Make the real call once, while the dependency is healthy. The flow shows up in the session with its response.
- Open the flow and choose "Save as mock." Pick the profile the route should live on.
- Turn the mock server on for that profile.
- Run your tests. The recorded response is served without the request leaving the proxy.
To capture a whole session at once, use Save all as mocks. It walks the flows, skips the ones it cannot promote, and tells you which ones and why rather than silently dropping them.
What it does not do
Stated plainly, because these change whether the approach fits your suite:
- A route matches the path including its query string. A mock recorded from
/v1/accounts?page=1will not answer/v1/accounts?page=2. That is a second recording. This is deliberate: stripping the query would make the route match calls it never saw, and that failure is far harder to debug than a miss. If your dependency is called with widely varying parameters, record the calls your tests actually make. - JSON-RPC recordings are body-aware. In addition to method, host and path, Proxycept
scopes a promoted JSON-RPC route to its
method;tools/callroutes are scoped toparams.nameas well. That lets several MCP operations sharePOST /mcpwithout one recording answering every call. Other body protocols are not inferred yet. GraphQLoperationNamematching, for example, is not supported. - Responses are captured up to 64 KB. A body at that ceiling cannot be proven complete, so it is refused rather than promoted as a truncated fixture that fails confusingly later.
- Only successful responses promote. If the dependency was already returning 503 when you captured, there is nothing worth replaying.
- A profile answers for one host. The first promotion scopes the profile to the host it
came from, and the comparison is exact:
API.Example.comandapi.example.comare two different hosts.
When a cassette library is still the right answer
If you have exactly one service in exactly one language, and its tests already run without
network access, a library-level cassette is less machinery and you should keep it. vcrpy
in a Python monolith is a good tool and a proxy adds a moving part you did not need.
The proxy approach earns its keep when the recording has to be shared, when more than one language is involved, or when the traffic comes from something you cannot hook: a mobile build, a browser test, a container in CI.
The honest summary
Recording and replaying HTTP is not a new idea, and Proxycept did not invent it. What it changes is the layer: one recording, usable by every language and every teammate, instead of a cassette file per repo per runtime.
If someone else's downtime has failed your build this month, that is the problem this solves.