http-snapshot
http-snapshot is a pytest plugin that captures and snapshots HTTP requests/responses made with popular Python HTTP clients like httpx and requests. It uses inline-snapshot to store HTTP interactions as JSON files, enabling fast and reliable HTTP testing without making actual network calls.
Features
- 🚀 Support for multiple HTTP clients:
httpx(async, sync) andrequests(sync) - 📸 Automatic HTTP interaction capture: Records both requests and responses
- 🔒 Security-aware: Automatically excludes sensitive headers like authorization and cookies
- ⚙️ Configurable: Control what gets captured and what gets excluded
- 🧪 pytest integration: Works seamlessly with your existing pytest test suite
- 📁 External snapshots: Stores snapshots in organized JSON files
Installation
pip install http-snapshot
For specific HTTP client support:
# For httpx support
pip install http-snapshot[httpx]
# For requests support
pip install http-snapshot[requests]
# For both
pip install http-snapshot[httpx,requests]
Quick Start
Using Context Managers (Recommended)
The context manager API provides proper resource cleanup and doesn't require any additional dependencies.
Using with httpx (async)
import pytest
import inline_snapshot
from http_snapshot.httpx import HttpxAsyncSnapshotClient
@pytest.mark.anyio
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
async def test_api_call(http_snapshot, is_recording: bool) -> None:
async with HttpxAsyncSnapshotClient(
snapshot=http_snapshot,
is_recording=is_recording,
) as client:
response = await client.get("https://api.example.com/users")
assert response.status_code == 200
assert "users" in response.json()
Using with httpx (sync)
import pytest
import inline_snapshot
from http_snapshot.httpx import HttpxSyncSnapshotClient
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_api_call(http_snapshot, is_recording: bool) -> None:
with HttpxSyncSnapshotClient(
snapshot=http_snapshot,
is_recording=is_recording,
) as client:
response = client.get("https://api.example.com/users")
assert response.status_code == 200
assert "users" in response.json()
Using with requests (sync)
import pytest
import inline_snapshot
from http_snapshot.requests import RequestsSnapshotSession
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_api_call(http_snapshot, is_recording: bool) -> None:
with RequestsSnapshotSession(
snapshot=http_snapshot,
is_recording=is_recording,
) as session:
response = session.get("https://api.example.com/users")
assert response.status_code == 200
assert "users" in response.json()
How It Works
# Record new HTTP interactions (makes actual network calls and creates snapshots)
pytest tests/ --http-record --inline-snapshot=create
# Re-record and update existing snapshots (makes actual network calls and updates snapshots)
pytest tests/ --http-record --inline-snapshot=fix
# Replay existing snapshots (default - no network calls made)
pytest tests/
Configuration Options
You can customize what gets captured using SnapshotSerializerOptions:
Using with context managers:
import pytest
import inline_snapshot
from http_snapshot.requests import RequestsSnapshotSession, SnapshotSerializerOptions
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:my-test-snapshot.json")],
)
def test_with_custom_options(http_snapshot, is_recording: bool) -> None:
serializer_options = SnapshotSerializerOptions(
exclude_request_headers=["X-API-Key"],
include_request=True,
)
with RequestsSnapshotSession(
snapshot=http_snapshot,
is_recording=is_recording,
serializer_options=serializer_options,
) as session:
response = session.get(
"https://api.example.com/protected",
headers={"X-API-Key": "secret-key"}
)
assert response.status_code == 200
Available Options
include_request: Whether to include request details in snapshots (default:True)exclude_request_headers: List of request headers to exclude from snapshotsexclude_response_headers: List of response headers to exclude from snapshots
By default, the following sensitive headers are always excluded:
- Request:
authorization,cookie - Response:
set-cookie,www-authenticate,proxy-authenticate,authentication-info,proxy-authentication-info,transfer-encoding,content-encoding
Snapshot Format
Snapshots are stored as JSON files with the following structure:
[
{
"request": {
"method": "GET",
"url": "https://api.example.com/users",
"headers": {
"host": "api.example.com",
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"connection": "keep-alive",
"user-agent": "python-httpx/0.28.1"
},
"body": ""
},
"response": {
"status_code": 200,
"headers": {
"date": "Thu, 21 Aug 2025 15:49:45 GMT",
"content-type": "application/json; charset=utf-8",
"connection": "keep-alive",
"server": "nginx/1.18.0"
},
"body": {
"users": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane@example.com"
}
]
}
}
}
]
Content Encoding
The plugin intelligently handles different content types:
- JSON: Formatted with proper indentation for readability
- Text: Stored as UTF-8 strings
- Binary: Base64 encoded
Advanced Examples
Testing API with Multiple Requests
from http_snapshot.httpx import HttpxAsyncSnapshotClient
@pytest.mark.anyio
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:multi-request-test.json")],
)
async def test_multiple_requests(http_snapshot, is_recording: bool) -> None:
async with HttpxAsyncSnapshotClient(
snapshot=http_snapshot,
is_recording=is_recording,
) as client:
create_response = await client.post(
"https://api.example.com/users",
json={"name": "Alice", "email": "alice@example.com"}
)
assert create_response.status_code == 201
user_id = create_response.json()["id"]
get_response = await client.get(
f"https://api.example.com/users/{user_id}"
)
assert get_response.status_code == 200
assert get_response.json()["name"] == "Alice"
Testing with Authentication
from http_snapshot.requests import RequestsSnapshotSession, SnapshotSerializerOptions
@pytest.mark.parametrize(
"http_snapshot",
[inline_snapshot.external("uuid:auth-test.json")],
)
def test_authenticated_request(http_snapshot, is_recording: bool) -> None:
serializer_options = SnapshotSerializerOptions(
exclude_request_headers=["Authorization"]
)
with RequestsSnapshotSession(
snapshot=http_snapshot,
is_recording=is_recording,
serializer_options=serializer_options,
) as session:
response = session.get(
"https://api.example.com/profile",
headers={"Authorization": "Bearer secret-token"}
)
assert response.status_code == 200
Best Practices
- Exclude sensitive data: Always exclude headers containing secrets, tokens, or personal data
- Review snapshots: Check generated snapshot files into version control and review changes
Metadata
Release files for http-snapshot 0.1.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| http_snapshot-0.1.9.tar.gz | 11.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| http_snapshot-0.1.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.9 kB
Release files / http_snapshot-0.1.9.tar.gz
| Download URL | http_snapshot-0.1.9.tar.gz |
|---|---|
| Size | 11.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
22e6a1f0ff2836e14c33724213422d6351fe9513aafbbc5e0608cad9a2c5363c
|
|
BLAKE2b-256 checksum How to use checksums |
306d10494f06ba67f9d74f98b25f9db3ae339969b6049e30144d7f161a1b33ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.
Transparency logRelease files / http_snapshot-0.1.9-py3-none-any.whl
| Download URL | http_snapshot-0.1.9-py3-none-any.whl |
|---|---|
| Size | 12.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
62df93b7c429bd8d836e4dad48b36c473ca88d13652985267a01de9ec4c865c3
|
|
BLAKE2b-256 checksum How to use checksums |
8abe2a84ec7f2ac134e7628235768f488f157918f484a9254fa7fa3348d4afbf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.
Transparency log