Turn a recorded browser HAR into a deterministic mock API in seconds.
A HAR file is the source of truth: upload it once, point your app to the generated base URL, and every matching request is replayed immediately from memory with the same method, path, query, and body semantics you captured in the browser.
HAR Mock is designed for one simple workflow:
- record a real browser or API interaction with a HAR file
- load that HAR into a local or shared mock endpoint
- run your app against the mock instead of the live backend
- keep the replay stable, fast, and deterministic for testing and integration work
This is especially useful for:
- frontend UI testing without hitting live infrastructure
- QA environments that need stable, repeatable responses
- debugging against captured production or staging traffic
- local development when a backend is slow, unavailable, or expensive to reach
- Upload a HAR and create an app/environment namespace instantly
- Replay matching requests by method, normalized path, query, and request body
- Ignore original host/port differences while matching against your mock URL
- Use a lightweight management API for listing, deleting, and reloading mocks
- Run as a local mock server or as a shared server behind your own ingress
- Keep the replay fast by serving responses directly from memory
docker build -t har-mock .
docker run --rm -p 8080:8080 -v har-mock-data:/app/data har-mockUpload a HAR:
curl -X POST 'http://localhost:8080/_har/checkout/qa' \
-F 'file=@checkout.har'If your HAR contains requests such as:
https://api.example.com/api/cart
https://api.example.com/api/products/123
then your mock base URL is:
http://localhost:8080/checkout/qa
And the app can call:
GET http://localhost:8080/checkout/qa/api/cart
GET http://localhost:8080/checkout/qa/api/products/123
Open the management page at:
http://localhost:8080/_har/
dotnet run -- project/checkout.harOr explicitly:
dotnet run -- run checkout.har --port 5050The local runner exposes the HAR directly at the root, so if the HAR contains https://api.company.com/api/cart, the local mock URL becomes:
http://127.0.0.1:5050/api/cart
| Method | Path | Purpose |
|---|---|---|
GET |
/health |
Liveness check |
GET |
/_har/ |
HTML status page |
GET |
/_har/environments |
List configured mocks |
GET |
/_har/{app}/{env} |
Show mock metadata |
POST |
/_har/{app}/{env} |
Upload or replace a HAR |
DELETE |
/_har/{app}/{env} |
Remove a mock |
* |
/{app}/{env}/{**path} |
Replay recorded responses |
You can also upload raw HAR JSON instead of a multipart upload:
curl -X POST 'http://localhost:8080/_har/checkout/qa' \
-H 'Content-Type: application/json' \
--data-binary @checkout.harHAR Mock matches requests using a deterministic strategy:
- application + environment select the route table in memory
- original HAR scheme, host, and port are ignored during replay matching
- method + normalized path + normalized query are used for matching
- query parameter ordering is ignored, while duplicate values are preserved
- if an exact query match misses, a single recorded variant can be used to tolerate cache-busting or tracking params
- for routes with multiple recorded variants, the request body helps disambiguate the response
- duplicate entries for the same method/path/query/body use the last HAR response
- recorded latency is ignored; the mock responds immediately
If no route matches, the server returns structured JSON with a short list of closest matches.
Browser HARs often mix page, CDN, auth, and API hosts. HAR Mock chooses one primary host to avoid collisions and warns when other hosts are present.
If you need to force the host selection:
curl -X POST 'http://localhost:8080/_har/checkout/qa?host=api.example.com' \
-F 'file=@checkout.har'For a shared server, the CLI supports the same behavior:
har-mock push checkout.har \
--server https://mock.company.internal \
--app checkout \
--env qa \
--host api.example.comYou can commit HAR files under the Har/ folder:
Har/
checkout/
dev.har
qa.har
accounts/
dev.har
On startup these become checkout/dev, checkout/qa, etc. If an environment is already persisted, the existing version wins and the bundled file is left alone.
HARs can contain sensitive response bodies. Treat the service and its persistent volume as test-data infrastructure.
Protect management endpoints with a key:
docker run --rm -p 8080:8080 \
-e HarMock__ManagementApiKey='replace-me' \
-v har-mock-data:/app/data har-mockThen send X-Api-Key with your requests. Replay URLs remain unauthenticated by design so the app under test does not need a mock-specific auth flow.
Maximum upload size defaults to 100 MiB and is configurable using HarMock__MaxUploadBytes.
Requires the .NET 10 SDK:
dotnet runThe project can also be packed as a .NET local/global tool:
dotnet pack -c Release
dotnet tool install --global --add-source ./nupkg HarMock.Toolhar-mock run checkout.har
har-mock run checkout.har --port 6060
har-mock run checkout.har --host api.company.com
har-mock push checkout.har --server https://mock.company.internal --app checkout --env qa
har-mock list --server https://mock.company.internal
har-mock delete --server https://mock.company.internal --app checkout --env qaIf management security is enabled:
export HAR_MOCK_API_KEY='...'
har-mock push checkout.har --server https://mock.company.internal --app checkout --env qaRun har-mock help for the full command reference.
This repository includes a generated animated demo that can be regenerated at any time:
py scripts/generate_demo_gif.pyThe output is written to:
docs/assets/har-mock-demo.gif
Use HTTPS at your ingress or reverse proxy, persist /app/data, restrict management access, and avoid uploading production HARs containing secrets or personal data unless they have been sanitized.
- no upstream proxying or YARP
- no artificial replay latency
- no route templating such as
/users/{id} - no multi-node coordination in v1
This keeps the service intentionally simple: a deterministic, in-memory HAR replay layer that feels like a local API mirror of the captured environment.
