Record and Replay Testing for HTTP APIs with GoReplay
HTTP record and replay testing means recording requests, sending them to a target backend, and checking its behavior. GoReplay supplies the capture and replay stages. Your application’s assertions and observations determine whether the test passed.
“Record and replay” also describes other tasks. Identify the artifact and destination before choosing a tool:
| Task | What is recorded | Where replay happens | What you learn |
|---|---|---|---|
| HTTP request replay | Requests received by a service | A running target backend | How that backend responds to the selected workload, with your verification |
| HTTP response fixtures | Request/response pairs | A mock server serving saved responses | How a client behaves against those fixtures |
| UI test recording | Browser actions such as clicks and inputs | A browser executing the recorded steps | Whether the UI meets the test’s assertions |
| Session analytics | User interaction events used to reconstruct a session | A visual playback interface | What a user experienced; playback alone is not an automated test |
For concrete examples of the other testing categories, MockServer documents recorded response expectations and Tricentis describes UI record-and-playback testing. GoReplay does not turn a server capture into a video of a user’s screen or a browser action script.
How HTTP record/replay works
The useful sequence is capture → save → replay → verify. It can expose requests and payload combinations that your written tests do not include. A capture only represents the traffic observed during its collection window; keep explicit tests for new features, rare cases and important behavior that did not occur then.
1. Choose the capture boundary
Select the service, port, time window and allowed request scope. Raw capture needs access to the relevant interface and capture permissions. For TLS traffic, capture an available plaintext HTTP leg after termination: --input-raw cannot decrypt an encrypted connection. See capturing and HTTPS.
Use a fresh directory for a bounded sample:
capture_dir=$(mktemp -d)
sudo gor --input-raw :8080 --http-allow-method GET \
--output-file "$capture_dir/requests.gor" --output-file-append \
--exit-after 30s
Append mode makes the saved filename match the subsequent replay. Without it, the default writer uses numbered chunks. A GET filter does not sanitize data or prove the target has no side effects. Configure and verify filtering, rewriting and any middleware needed for the selected data before capture.
2. Prepare the target and replay
Start an isolated target with known data and controlled downstream services. Replace the example hostname below with that target; run from the shell that still has capture_dir set:
gor --input-file "$capture_dir/requests.gor" \
--output-http="http://staging.example.com" --exit-after 60s
The 60-second limit bounds this example; it is not a success assertion. A longer capture can be cut short, and in-flight responses may remain unfinished when the process stops. Choose a duration that covers the sample and response time, then check expected request counts, output errors and the target’s observations. See file replay and HTTP output.
File replay uses recorded timestamp gaps, which a percentage input limiter can scale. This does not guarantee the original request completion order, achieved requests per second, or application session behavior. Token refresh, state transitions and dependencies may require explicit handling. OSS replay does not provide PRO’s documented TCP-session recognition.
3. Verify the application result
Choose the expected status, relevant body fields and resulting state for each case. Count missing, extra and rejected requests as well as successful ones. A captured bug must not become the desired behavior merely because it is the recorded response.
For paired origin/candidate comparison, arrange to collect origin responses with --input-raw-track-response and replay responses with --output-http-track-response. The middleware protocol explains their asynchronous arrival and request IDs. Add application-specific comparison rules and account for fields that legitimately change. GoReplay alone does not provide a general pass/fail oracle for your service.
Practice the file workflow locally
The Python replay exercise uses an installed GoReplay binary and Python 3.9+. Save the script, inspect it, and run:
python3 replay-demo.py --gor /path/to/gor
It generates three synthetic requests, saves only the two GETs to a fresh append-mode file, and replays them to a temporary loopback server. The script asserts that /price?currency=USD produces 200, /price?currency=INVALID produces 422, and the excluded POST never arrives. A successful run prints result: "passed"; unexpected observations fail the exercise. Temporary files and the server are cleaned up afterward.
This practices file filtering, filename handling and local replay. It does not demonstrate production packet capture, TLS, high load, session preservation or a response-diff engine. The application-specific assertions in the script illustrate the verification work your own test must supply.
Implementation Strategies That Actually Work
Integrating With CI/CD Pipelines
A CI job needs more than a gor command. Make each phase observable:
| Phase | Required evidence or decision |
|---|---|
| Prepare | Target build/version, ready endpoint, seeded data and isolated dependencies |
| Select input | A reviewed capture or synthetic fixture, its collection scope and expected cases |
| Transform | Valid target credentials and any ID/token mapping; verified removal of sensitive values |
| Replay | A finite run, output errors, request counts and enough time for responses to finish |
| Assert | Status/body/state rules; fail the job on missing results or unexpected behavior |
| Clean up | Stop the target, remove temporary data and retain only the approved diagnostic artifact |
Do not infer a CI pass from GoReplay’s process exit code alone. Keep the test’s assertions in version control and run them against the target results. Record which capture and target version produced a failure so someone else can reproduce it.
Managing Test Data Effectively
A production request can contain an expired credential, a resource ID that does not exist in the target, or a write that triggers a downstream action. Decide which values to replace, seed the necessary entities, and reset state between runs. Block or replace external effects such as email, payments and webhooks. Filtering one method is not a substitute for this work.
If a workflow requires one response to generate the next request’s token or ID, a static capture may need custom middleware or a purpose-built stateful test. Increasing the replay speed does not resolve those dependencies.
Choose OSS or PRO for the requirement
Start with OSS for HTTP capture, local-file replay, filtering and configurable request transformations. The PRO documentation describes S3-backed storage, binary-protocol replay and TCP-session recognition as PRO capabilities. Validate the required protocol and connection behavior for your application; do not assume a TCP session is the same as an authenticated business workflow. Use the PRO page for current edition and support details.
Measuring Success and Demonstrating ROI
Track whether the replay reproduced a known defect, found a confirmed new regression, or validated a specified migration behavior. Also record preparation, data-maintenance, investigation and infrastructure costs. Compare equivalent cases and environments when measuring time saved.
Request volume is not test coverage, and accepted requests are not proof of correctness. There is no universal improvement percentage. Once this workflow is reliable, use shadow testing for sampled live comparison or choose a performance objective from the types of load testing.