# vcrpy: record HTTP once, replay it in every test run

> vcrpy is a Python library that records HTTP interactions into YAML cassette files and replays them on later runs. It fits test suites that hit third-party APIs and need deterministic, offline execution.

**kevin1024/vcrpy** — Automatically mock your HTTP interactions to simplify and speed up testing

- Repository: https://github.com/kevin1024/vcrpy
- Stars: 3,015 · Forks: 442
- Language: Python
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/kevin1024-vcrpy

## What vcrpy records and who ends up maintaining the cassettes

vcrpy is a Python reimplementation of Ruby's VCR library. Its stated purpose is to simplify and speed up tests that make HTTP requests. The first time code runs inside a VCR.py context manager or a decorated function, vcrpy records every HTTP interaction that passes through the libraries it supports, serializes them, and writes them to a flat file. That file is called a cassette, and YAML is the default format. On later runs, vcrpy reads the cassette, intercepts requests it recognises, and returns the recorded responses instead of sending traffic. The README lists three consequences: tests work offline, they become completely deterministic, and they run faster.

The audience is anyone whose test suite depends on a remote HTTP service. That includes teams testing a client library against a third-party API, and teams whose integration tests are slow or flaky because a staging server is unavailable. The trade-off is ownership. A cassette is a checked-in artifact that describes someone else's API at a moment in time. When that API changes, the README's instruction is blunt: delete the cassette files, run the tests again, and vcrpy will detect the missing cassette and re-record. That is a simple recovery path, but it is manual, and it means the cassette set is a maintenance surface you now own.

## How cassettes intercept requests: matching, serialization and replay

The mechanism is interception at the HTTP client layer rather than at the socket. vcrpy supports a set of Python HTTP libraries, and the project's own test dependencies in pyproject.toml name many of them: requests, urllib3, httpx, httpx-curl-cffi, aiohttp, boto3, httplib2, pycurl, pyreqwest, tornado, and niquests through a separate extra. That list is the project's test matrix, so it is the best available signal of what is exercised, but the README itself does not enumerate supported clients.

A recorded interaction is a request and its response. vcrpy serializes both into the cassette and, on replay, has to decide whether an incoming request corresponds to a stored one. That decision is matching, and the searches people run around this project include vcr match_on and Vcrpy before_record_request, which points at the two knobs that matter most in practice: what counts as the same request, and what gets written down before it is stored. Matching matters because a cassette keyed too loosely will return the wrong response, and one keyed too strictly will miss and fail. before_record_request matters because it is the hook where you can strip or rewrite parts of a request before it lands in a file you are about to commit.

The README does not document the defaults for either hook. If you are evaluating vcrpy, read the documentation site at vcrpy.readthedocs.io for the current matching rules rather than assuming them.

## Installing vcrpy and recording a first cassette

The package is published on PyPI as vcrpy, and the current release line in the repository is v8.3.0 from 2026-07-04. The README and pyproject.toml do not give a pip command, so take the install instructions from the project's documentation site at vcrpy.readthedocs.io. What the repository does state is the runtime surface: Python 3.10 or newer, with PyYAML and wrapt as the only declared dependencies.

The README describes the recording model rather than a worked example. Code placed inside a VCR.py context manager or decorated function is what gets recorded, and the cassette is the flat file that receives the serialized interactions. The README does not show the context manager call itself, so read the documentation for the exact API before writing your first test.

What the README does specify is the lifecycle. Run the code once with network access and the interactions are written to the cassette. Run it again and vcrpy reads the serialized requests and responses, intercepts the requests it recognises, and returns the stored responses, so no HTTP traffic leaves the process. The record mode controls this behaviour, and vcrpy record mode is one of the phrases people search for around the library; the README does not spell out the available modes.

If you use pytest, the README points to a separate library, pytest-recording, for fixtures. Do not expect fixtures from vcrpy itself.

## Where vcrpy stops being the right tool

The clearest limitation is that a cassette is a snapshot, not a contract test. Once a response is recorded, vcrpy will keep returning it even if the real server has changed, added fields, or started returning errors. A green suite therefore says your code handles the recorded response, not that the upstream service still behaves that way. The README's answer is to delete cassettes and re-record, which means someone has to notice the drift first. There is no built-in mechanism described for detecting it.

Second, cassettes are files in your repository, and they contain whatever the server sent. If your tests authenticate against a real service, the recorded request may carry tokens, cookies, or personal data. The existence of a before_record_request hook suggests the maintainers expect you to filter, but the README does not document the hook or provide a default redaction policy. Treat cassette contents as data you are publishing to everyone with repository access.

Third, vcrpy only sees traffic that goes through the libraries it supports. A client it does not intercept will make real network calls inside a recording block, which is the worst outcome: a test that looks mocked and is not. Confirm your client is covered before trusting the setup.

Finally, if the thing you actually need to test is live server behaviour, retries against a real endpoint, or rate limiting, vcrpy is the wrong layer entirely. It removes the network; it cannot test it.

## vcrpy against responses and hand-written mocks

The obvious alternative is the responses library, which patches the requests library directly. The difference in approach is where the fake data comes from. With responses you write the stubbed response yourself in the test: status code, headers, body. With vcrpy you record a real interaction and store it. Hand-written stubs are explicit and reviewable, and they cannot leak a real credential because you typed them. They also drift silently in the same way cassettes do, and writing them for a response with many fields is tedious.

A second alternative is a plain mock of your HTTP client, which avoids any HTTP-level detail at all. That is fine for unit-testing your parsing logic, but it stops testing whether your code sets headers, builds URLs, or handles status codes correctly, because the mock never sees a real request shape. vcrpy sits between these: it exercises your real client code against a recorded server response, at the cost of storing that response.

The choice usually comes down to volume. A handful of endpoints favours hand-written stubs. A client that talks to dozens of endpoints, or tests that walk through multi-step API flows, favours recording.

## Maintenance, upgrade cost and the MIT licence

The repository is not archived, and the last push was on 2026-09-15, with v8.3.0 released on 2026-07-04. Releases in this line have been frequent, and the project classifies itself as Production/Stable. None of that tells you whether your cassettes will survive an upgrade. Version bumps in a recording library can change serialization or matching behaviour, and the README gives no migration notes for cassettes across versions.

The upgrade cost you should budget for is re-recording, not code changes. Because the documented recovery path is to delete cassettes and run the tests again, a vcrpy upgrade that changes cassette format is recoverable, provided you can reach the real services from a developer machine. If your test data comes from a service you cannot call on demand, that recovery path is not available to you, and an upgrade becomes a project.

The licence is MIT, declared in pyproject.toml and in LICENSE.txt. That is permissive and imposes no conditions on how you distribute your own code. It says nothing about the contents of your cassettes, which are your data and your responsibility. This is not legal advice; if your recordings contain regulated data, talk to someone qualified.

## Conclusion

Adopt vcrpy when your tests call third-party HTTP services and you want them to run offline and deterministically, and when you are willing to commit cassette files and regenerate them when an upstream API changes. Do not adopt it if you need to verify live server behaviour in CI or you cannot store recorded responses, since cassettes can hold credentials and personal data. Before wiring it in, confirm that your HTTP client is among the libraries the project's test dependencies list, and check whether you want the pytest-recording fixtures instead of the context manager. The README's own upgrade path is the one to trust: delete the cassettes and run the tests again.

## FAQ

### Does vcrpy work with httpx and other HTTP clients?

The project's test dependencies list httpx, httpx-curl-cffi, requests, urllib3, aiohttp, boto3, httplib2, pycurl, pyreqwest, tornado and niquests, which indicates those clients are exercised in the test suite. The README itself does not enumerate supported libraries, so check the documentation for the current list before assuming your client is intercepted.

### How do I use vcrpy with pytest?

The README states that a separate library, pytest-recording, provides pytest fixtures for vcrpy. Install and use that rather than expecting fixtures from vcrpy itself.

### What happens when the API I am testing changes?

The README says to delete your existing cassette files and run your tests again. vcrpy detects the absence of a cassette and records all HTTP interactions anew, updating them to match the new API.

### Can I stop secrets from being written into a cassette?

The before_record_request hook is the point where a request can be altered before it is stored, and people search for it by name, but the README does not document it or describe any default redaction. Read the documentation site for the current behaviour before committing cassettes that contain credentials.

## Sources

- [Issues](https://github.com/kevin1024/vcrpy/issues)
- [kevin1024/vcrpy on GitHub](https://github.com/kevin1024/vcrpy)
- [License: MIT](https://github.com/kevin1024/vcrpy/blob/master/LICENSE)
- [README](https://github.com/kevin1024/vcrpy/blob/master/README.md)
- [Releases](https://github.com/kevin1024/vcrpy/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kevin1024-vcrpy
