How to Modify Web Captures with JavaScript
Learn when to use Chrome Local Overrides, Playwright interception, HAR replay, or an archival capture—and how to modify each safely.
“Web capture” can mean several different things. Choose the workflow that matches what you need to change:
- Change a resource locally while developing: use Chrome DevTools Local Overrides. The edited response is served in your browser after reload; the origin server is unchanged.
- Change what a page receives in an automated test: use a Playwright route handler to modify a response before fulfilling the request.
- Edit a recorded exchange for deterministic replay: edit the HAR fixture and replay matching requests with Playwright.
- Create a preservation archive: use a browser based capture tool such as Scoop to create WARC or WACZ output. This is capture creation, not a general editor for an existing archive.
The sections below give runnable examples and explain the boundaries, matching behavior, privacy concerns, and common failure modes for each option.
1. Change a browser resource with Chrome Local Overrides
Local Overrides are the quickest choice when you want to prototype a page or API response without changing the server. DevTools stores a local copy of a network resource and serves that copy on reload. The change stays on your machine and does not modify the origin.
Set up an override
- Open the page in Chrome and open DevTools.
- Open the Network panel, reload the page, and find the resource you want to change.
- Right click the request and choose Override content or Override headers.
- If prompted, choose a local folder and grant DevTools permission to use it.
- Edit the saved file in the Sources panel or your editor, save it, then reload the page.
On reload, DevTools serves your saved local copy instead of the network resource. You can override response content, XHR or fetch responses, and response headers. See Chrome DevTools Local Overrides for the current UI workflow.
What Local Overrides do and do not change
- They change: the response Chrome uses on your local browser session for the overridden resource.
- They do not change: the production server, its stored data, or what another visitor receives.
- They persist: across reloads while the override remains enabled and the local file exists.
- They disable cache: Chrome automatically disables its cache while Local Overrides are active, so do not use that session to judge normal cache behavior.
Important limitations
- Edits made directly in the Elements DOM tree are not saved as overrides. Make a source or response edit instead.
- CSS edits made in the Styles pane are not saved when that CSS is embedded in an HTML file. Edit the HTML in Sources.
- Source mapped files cannot be overridden directly through the described Network workflow. Find and override the served resource instead.
2. Modify an API response in JavaScript with Playwright
For repeatable tests, Playwright route interception lets a test fetch the actual response, change its JSON, then fulfill the browser request with the modified response. The page sees the test supplied data; the live API’s stored data is not changed. This is useful for exercising a UI state before a backend change exists or for making a response fixture repeatable.
Install Playwright and its Chromium browser in a Node project:
npm install --save-dev playwright
npx playwright install chromium
Save this as modify-response.js and run it with node modify-response.js. The example assumes the page calls /api/profile and that the endpoint returns a JSON object with a name property; replace the URL pattern and fields with those used by your application.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.route('**/api/profile', async (route) => {
try {
const response = await route.fetch();
const profile = await response.json();
const modifiedProfile = {
...profile,
name: 'Test User',
plan: 'premium',
};
await route.fulfill({
response,
json: modifiedProfile,
});
} catch (error) {
console.error('Could not modify profile response:', error);
await route.abort();
}
});
await page.goto('https://example.com');
// Replace this assertion with one for the UI that consumes the API response.
// For example: await page.getByText('Test User').waitFor();
console.log('Page loaded with the intercepted response.');
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
route.fetch() obtains the original response; route.fulfill() supplies the edited JSON to the page. Passing the original response preserves its status and headers unless you override them. Playwright documents this pattern in its Mock APIs guide.
Use a fully synthetic response
If the test should not call the real backend, fulfill the route directly. This is useful for tests that need to be fast, isolated, or independent of backend availability.
await page.route('**/api/profile', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ name: 'Test User', plan: 'premium' }),
});
});
A synthetic fixture gives you control over the response but does not exercise the real API. Keep the fixture aligned with the response shape the page expects, including fields the UI reads even if the current assertion does not mention them.
Route interception tips
- Register the route before navigating or triggering the request; a request that already completed cannot be intercepted retroactively.
- Use a URL pattern that matches the actual request, including host and path as needed. If the application makes several similar calls, narrow the pattern or inspect the request URL.
- Check the real response status and JSON shape before modifying it. An error response or non JSON body will make
response.json()fail. - For a response that should remain unchanged under some conditions, call
route.continue()or fulfill with the original response as appropriate for your case.
3. Edit a HAR fixture and replay it
A HAR file records HTTP requests and responses. Editing a HAR changes the recorded fixture used for replay; it does not update the live server. Playwright can route requests from a HAR through page.routeFromHAR() or browserContext.routeFromHAR().
For example, after recording a HAR and editing its response content, replay it in a test like this:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.routeFromHAR('./fixtures/site.har', {
update: false,
});
await page.goto('https://example.com');
console.log('Loaded using matching responses from the HAR.');
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
With update: false, matching requests are fulfilled from the saved archive; an unmatched request is aborted. Edit the HAR response data (and any associated payload files if the archive uses them), then replay it. Playwright’s documentation explains HAR recording, editing, and replay.
HAR matching behavior
- URL and HTTP method are matched strictly.
- For POST requests, the POST payload is also matched strictly.
- If several entries match, Playwright selects the one with the most matching headers.
- Redirects are followed automatically.
- A request that has no matching entry is aborted when replay is used without updating the HAR.
These rules explain why an apparently similar request can miss the fixture: a changed query string, method, POST body, or relevant header can distinguish it from the recorded exchange.
Recording a HAR
To create a recording for later replay, use Playwright’s context recording option and close the context to flush the file:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext({
recordHar: { path: './fixtures/site.har' },
});
const page = await context.newPage();
await page.goto('https://example.com');
await context.close(); // writes the HAR recording
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Record only the flows needed by the test. A broad recording can capture unrelated requests, increase fixture size, and make future replay more sensitive to application changes.
4. Create a web archive with Scoop
If “modify a web capture” means creating a preservation oriented browser capture, use a capture engine designed to produce archive packages. Harvard Library Innovation Lab describes Scoop as a browser based, single page capture engine available through a CLI or JavaScript library.
Scoop can produce .warc, .warc.gz, and .wacz output. Optional capture attachments include provenance, screenshots, video, PDF, DOM snapshots, and SSL certificates. The project also describes WACZ signing and verification support and optional raw exchanges for later analysis or reprocessing.
That evidence supports using Scoop to create and configure a capture. It does not establish Scoop as a general editor for existing archives. Before changing an existing archive, identify its container format and replay software. Rewriting a package can affect provenance, signatures, or replay fidelity, so preserve the original and document any transformation.
5. Choose the right workflow
| Need | Use | What changes | Repeatability |
|---|---|---|---|
| Prototype a page or response interactively | Chrome Local Overrides | A local browser copy of a resource or headers | Persists across reloads on that setup |
| Change API data in an automated test | Playwright route interception | The response fulfilled to that test page | Repeatable when the route and fixture are controlled |
| Replay recorded exchanges | Edited HAR plus Playwright routing | The recorded response fixture | Deterministic for requests that match |
| Create a preservation capture | Scoop | A new WARC or WACZ capture package | Depends on the capture options and the page at capture time |
6. Protect secrets in captures
HAR files can contain cookies and information submitted through forms. Google Cloud advises sanitizing capture data before sharing it; see its browser trace capture guidance.
Chrome’s sanitized HAR export is the default and excludes Cookie, Set-Cookie, and Authorization headers. Sensitive export is an explicit option in the Network panel. Header filtering does not prove that every secret or personal value has been removed from request or response bodies. See the Chrome Network reference.
- Inspect the full HAR before committing it or sending it to support.
- Remove credentials, session identifiers, form values, personal data, and private response fields that the test does not need.
- Use synthetic test accounts and fixtures where possible.
- Keep the original capture in a restricted location if it must be retained for investigation.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Local edit disappears after reload | The resource was changed in Elements or Styles rather than saved as an override, or the override was not saved. | Create an override from the Network request, edit its saved file in Sources, save it, and reload. |
| CSS edit is not retained | The CSS is embedded in an HTML file, or the edited file is source mapped. | Edit the containing HTML in Sources; for source mapped assets, identify the served resource and override that resource if supported. |
| Page still shows the original response | The wrong request was overridden, the local override folder is not enabled, or a different URL is being requested. | Inspect the Network panel after reload, verify the requested URL, and confirm the override is active. |
| Playwright handler never runs | The route was registered after the request, or its pattern does not match the request URL. | Register before navigation and inspect the request URL and method; make the pattern precise enough to match. |
response.json() throws |
The endpoint returned an error, empty body, or non JSON content. | Check the status and content type; handle non JSON responses or use a synthetic JSON fixture. |
| Page receives malformed data | The modified object omits fields or types that the page expects. | Preserve the original object with a spread and change only the fields required by the test. |
| HAR replay aborts a request | No HAR entry matches; URL, method, POST payload, or headers differ. | Compare the live request with the recording. Regenerate or correct the fixture, or configure the test to handle that unmatched request explicitly. |
| HAR contains private data | The recording captured credentials, form values, or response data. | Sanitize and inspect the entire file and any payload attachments before sharing or committing. |
| Archive replay changes after repackaging | The archive container, signing, provenance, or replay metadata may have been affected. | Retain the source archive, use the format’s documented tooling, and verify the resulting package and provenance. |
8. Performance, reliability, and cost
- Local Overrides: avoids a code change or backend deployment, but applies only in the configured browser environment. Cache is disabled while overrides are active.
- Route interception: fetching the original response adds a test network dependency. A synthetic fixture removes that dependency, but tests only the behavior represented by the fixture.
- HAR replay: can make tests independent of a live service for matching requests, but unmatched requests abort and strict matching means recordings need maintenance as requests change.
- Archival capture: richer attachments can increase capture storage and processing needs. Choose attachments based on preservation or review requirements.
- Cost: the cited workflow documentation provides no comparative pricing or benchmark figures. Local Overrides use Chrome DevTools; Playwright and Scoop are software workflows whose costs depend on the environment and deployment. Avoid treating capture size, runtime, or reliability as a fixed guarantee.
9. Or skip the browser setup
If your goal is a clean screenshot of a page rather than an altered response fixture, ScreenshotNeo is a website screenshot API and MCP server for developers. Its API documentation covers the available request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use screenshot, page information, and PDF capture tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month, with no card required.
10. FAQ
Does a Local Override change the website for other people?
No. It changes the resource served by your local Chrome session. The origin server remains unchanged.
Should I use route interception or HAR replay for a UI test?
Use interception when you want to define or modify a response in test code. Use HAR replay when you need to reproduce a recorded exchange and can keep its request matching conditions stable.
Can I safely commit a HAR fixture?
Only after inspecting and sanitizing it. A default sanitized export removes certain sensitive headers, but bodies and other values still need review.
Can I change a WARC or WACZ archive with the examples above?
No. The Playwright examples modify browser responses or HAR fixtures. An existing archive requires format specific tooling, and changes may affect its provenance or replay behavior.


