HAR File Analyzer: Read, Summarize and Safely Share a HAR
On this page
A support engineer asks you to “send a HAR file”. You export one from DevTools, and you now have a JSON file that holds every request the page made, every response, and often your session cookie and bearer token too. This guide covers that file: how to export it from each browser, how to read it, how to turn hundreds of entries into a short list of endpoints, and what to check before you send it to anyone.
You will use two tools. The site’s HAR analyzer runs in your browser and turns a capture into a redacted API summary. REA, the open-source project by morluto, has inspect-web-network-capture, which lets an AI agent read the same HAR record by record without fetching any of the recorded URLs.
Who this is for: developers, QA engineers and support staff who need to debug a web app from a capture, or hand a capture to someone else.
What you will learn:
- Export a HAR from Chrome, Edge, Firefox and Safari
- Find the sensitive parts of a HAR: headers, cookies, query strings and bodies
- Summarize a HAR by endpoint and spot slow requests and error codes
- Decide what to share, and what each tool’s redaction does and does not cover
- Let an agent read the HAR with REA 6.4.0
Only capture traffic you are allowed to record: your own app, a test account, or a system you are authorized to test. A HAR can contain other people’s personal data. See REA’s DISCLAIMER.md.
What a HAR file is
HAR (HTTP Archive) is a JSON format. Its top level is log, with version (normally "1.2"), creator (the browser that wrote it) and entries. Each entry is one request and response pair:
request: method, URL with query string, headers, cookies, andpostDatafor a bodyresponse: status, headers, cookies, andcontentwith the response body astext(sometimes base64)timeandtimings: how long the request took, split into phases such aswait(time to first byte)
Because the body text is usually included, a HAR is much more than a list of URLs. That is why it is useful for debugging, and why you need to be careful with it.
Step 1: Export a HAR from your browser
In every browser, open the developer tools before you reproduce the problem. The Network panel only records while it is open.
Chrome and Edge (Chromium):
- Open DevTools (F12) and go to Network. Tick Preserve log so a navigation does not clear the list.
- Reproduce the problem.
- Click the download icon in the Network toolbar and choose Export HAR (sanitized)….
Since Chrome 130 the default export leaves out Cookie, Set-Cookie and Authorization headers. To include them you must enable Settings > Preferences > Network > Allow to generate HAR with sensitive data. For a support ticket, the sanitized export is almost always the right choice.
Firefox: open the developer tools, go to Network, enable Persist Logs if the page navigates, reproduce the problem, then right-click the request list and choose Save All As HAR. Firefox does not apply Chrome’s sanitizing step, so treat its HAR as containing everything.
Safari: enable the Develop menu in Safari’s settings (Advanced > Show features for web developers), open the Web Inspector, go to Network, reproduce the problem and use Export to save a .har file. Treat it as unsanitized.
Keep the capture small. Start recording right before the action you care about and stop right after. A short capture is easier to read and holds less personal data.
Step 2: Know where the secrets are
Before you summarize or share a HAR, it helps to know where sensitive values hide:
| Location | Typical content | Removed by Chrome’s sanitized export? |
|---|---|---|
Authorization header |
Bearer tokens, Basic credentials | Yes |
Cookie / Set-Cookie headers and cookies arrays |
Session IDs | Yes |
Other headers such as X-Api-Key |
API keys | No |
| URL query string | ?token=, ?api_key=, signed URL parameters |
No |
postData.text |
Passwords from a login form, personal data | No |
response.content.text |
Anything the server returned, including user records | No |
The last three rows are the ones people miss. A sanitized Chrome export can still contain an API key in a query string and a full user profile in a response body.
Step 3: Summarize the HAR by endpoint
A HAR with 400 entries is hard to read in a text editor. What you usually want is a list of endpoints with their counts, status codes and timings. Open the HAR analyzer and drop the file on it. The file is parsed in a Web Worker in your tab and is not uploaded.
To show real output, we built a small HAR for a demo notes app at notes.example.com. It has seven entries: two note reads, one note create, a search that fails with a 500, a GraphQL query, and two scripts, one of them from a third-party host. Some requests carry a JWT bearer token and a session cookie, and the search URL carries api_key=test-key-123. This is an excerpt of the JSON export the tool produced from it:
{
"summary": {
"exchanges": 7,
"endpoints": 6,
"firstParty": "example.com",
"thirdPartyRatio": 0.143
},
"endpoints": [
{
"host": "notes.example.com",
"method": "GET",
"path": "/api/notes/{id}",
"count": 2,
"status": { "200": 2 },
"credentials": [
{ "where": "header", "name": "authorization", "value": "[REDACTED]",
"length": 60, "scheme": "Bearer", "jwt": true },
{ "where": "cookie", "name": "sid", "value": "[REDACTED]", "length": 20 }
],
"maxMs": 2400,
"avgMs": 1242.5,
"resShape": { "object": { "id": "number", "title": "string",
"tags": { "array": "string" }, "archived": "boolean|null" } }
},
{
"host": "notes.example.com",
"method": "GET",
"path": "/api/search",
"status": { "500": 1 },
"query": ["api_key", "q"],
"credentials": [
{ "where": "query", "name": "api_key", "value": "[REDACTED]", "length": 12 }
],
"maxMs": 310
}
]
}
How to read it:
- Path templates group repeated calls.
/api/notes/41and/api/notes/42became one row,/api/notes/{id}, withcount: 2. Numeric segments, UUIDs, JWTs, dates, long hex strings, e-mail addresses and token-like strings become placeholders. A slug such asorder-12345stays literal. maxMsnext toavgMspoints at slow requests. The average of 1242.5 ms hides the real story: one of the two reads took 2400 ms. When an endpoint’s maximum is far above its average, look at that endpoint first.- The
statusmap shows errors per endpoint. The search endpoint returned500. A status of0means the request got no response, for example because it was blocked or cancelled. resShapedescribes the body without the data. You see thatarchivedis sometimes a boolean and sometimesnull. That kind of difference is often the cause of a front-end bug.- GraphQL requests are split by operation. The demo’s
/graphqlrequest appeared as its own endpoint with"kind": "graphql"and"operation": "query Me". The query text and variables were not kept.
We also searched the full export for every secret in the demo file: the JWT, the cookie value, test-key-123, the search term and the note body text. None of them were in it. The tool never copies header, cookie, query or body values into the report. It keeps only names, types, counts and the length of the longest value.
Step 4: Decide what to share
The analyzer does not write a cleaned-up HAR. It writes a summary. That gives you three options, from safest to most complete:
- Share the analyzer’s JSON export. It contains no values, only hosts, path templates, names, types, counts and timings. It does contain the file name you opened. This is enough to answer “which endpoint fails and how slow is it”.
- Share a sanitized browser export. Use Chrome’s or Edge’s Export HAR (sanitized), then search the file yourself for API keys in query strings and for personal data in bodies (see the checklist below).
- Share the full HAR only when the recipient really needs bodies and headers, through a channel your organization approves. Afterwards, sign out of the test session so its tokens stop working.
Pre-share checklist:
- Search the file for
token,key,secret,password,sessionandeyJ(the start of most JWTs). - Search for your own e-mail address, name and phone number.
- Check
postData.texton login and sign-up requests. - Check whether the capture includes requests to unrelated tabs or sites.
- Prefer a test account. A real account’s tokens stay valid until they expire or you log out.
What the analyzer’s credential rules cover: headers named authorization, proxy-authorization, cookie, set-cookie or x-api-key; any header or query parameter whose name contains token, secret, password, session, key, auth, signature or credential; and any header or query value that is a JWT. Those are listed by name as credentials. All other values are dropped too, because the report never stores values at all. What the analyzer cannot do is tell you whether a body field held personal data. It only shows that a field called title was a string.
Step 5: Let an AI agent read the HAR with REA
The summary tells you which request to look at. To read that request’s actual headers and body, or to let an agent compare a request with the front-end code, use REA’s inspect-web-network-capture. It needs no browser and no extra engine. Install REA as described in Install REA and connect it to Claude Code, Cursor or Codex.
rea inspect-web-network-capture /absolute/path/notes-demo.har har --record 1 --json
--record takes zero-based entry numbers and can be repeated. Leave it out to read every entry. This is part of what REA 6.4.0 returned for entry 1 of the demo file:
"records": [
{
"ordinal": 1,
"location": { "kind": "json-pointer", "pointer": "/log/entries/1" },
"reported": {
"request": {
"method": "GET",
"url": "https://notes.example.com/api/notes/41",
"headers": [
{ "name": "authorization", "value": null },
{ "name": "cookie", "value": null }
]
},
"response": {
"status": 200,
"content": {
"mimeType": "application/json",
"text": "{\"id\":41,\"title\":\"a\",\"tags\":[\"x\"],\"archived\":false}"
}
}
},
"redactions": [
{ "pointer": "/request/headers/0/value", "reason": "transport-credential" },
{ "pointer": "/request/headers/1/value", "reason": "transport-credential" }
]
}
]
This is a different kind of tool from the analyzer. REA keeps the record as the browser wrote it, including the response body, and records an Evidence ID and the file’s SHA-256 so an agent can cite exactly which file and entry a fact came from. It removes only known transport credentials: the values of Authorization, Proxy-Authorization, Cookie and Set-Cookie headers, cookie values, and user names and passwords embedded in URLs.
Everything else stays. When we read entry 4, the failing search, the URL came back unchanged as https://notes.example.com/api/search?q=invoice&api_key=test-key-123, with an empty redactions list. To exclude a value like that, declare it:
rea inspect-web-network-capture /absolute/path/notes-demo.har har \
--record 4 --sensitive-value 'test-key-123' --json
With that flag, REA 6.4.0 replaced the whole url field with null and recorded {"pointer": "/request/url", "reason": "explicit-sensitive-value"}. The key did not appear anywhere in the output, and the Evidence parameters store only "sensitive_value_count": 1, not the value. Note that the entire field is dropped, not just the matching part, so you lose the rest of the URL for that record.
Over MCP, an agent calls inspect_web_network_capture with capture_path, format: "har", and optionally record_ordinals and sensitive_values. A good prompt:
Use REA to read /absolute/path/notes-demo.har. Find the requests that failed or
took more than one second, show me their request and response, and cite the
record ordinal for each. Treat test-key-123 as a sensitive value.
What REA 6.4.0 does not do here: it accepts HAR 1.2 and native mitmproxy captures only. Mitmproxy captures need mitmdump 12.2.3 on Linux. It does not read Fiddler .saz files (the site’s analyzer does). It has no endpoint-grouping view for HAR, so use the analyzer’s summary for that. Inputs are limited to 32 MiB. It never sends a request: “Recorded URLs are never fetched”, as the tool’s own limitation list puts it.
Troubleshooting
The analyzer says the JSON is not a HAR 1.2 log. The file lacks log.entries, or an entry has no request method, URL or response status. Export it again from the browser rather than editing it by hand.
No credentials show up for an endpoint you know is authenticated. Your HAR probably came from Chrome’s sanitized export, which removed Authorization and cookies before the analyzer ever saw them. That is fine for sharing. For an audit of which endpoints send credentials, use the export with sensitive data, analyze it locally and delete it afterwards.
REA rejects the file. REA accepts HAR 1.2 only, rejects duplicate JSON keys and stops at 32 MiB. Export a shorter capture that covers just the action you are debugging.
The same endpoint appears twice. The path has a segment the placeholder rules treat as a word, for example order-12345. The rows are still correct. They are just not merged.
FAQ
Is a HAR file safe to send to support?
Not by default. A sanitized Chrome or Edge export removes cookies and the Authorization header, but query strings and bodies remain. Run the checklist above, or send the analyzer’s summary instead if it answers the question.
Does the HAR analyzer upload my file?
No. It runs in a Web Worker and the worker’s Content Security Policy blocks network requests. The tool page explains how to check this with your browser’s Network panel or by going offline.
Can I open a HAR without any tool?
Yes, it is JSON. jq '.log.entries[] | [.request.method, .request.url, .response.status, .time]' file.har gives a quick table. You will still want path templates and redaction before sharing the result.
What is the difference between this and tracing API calls to code?
This guide is about the HAR file itself. To go from a request to the JavaScript that sent it, read Trace Website API Calls with REA.
Next steps
- Follow a request back to the front-end code: Trace Website API Calls with REA: Browser, HAR and Bundles.
- Map a minified stack frame from the same session to source: Recover JavaScript Source from a Bundle.
- Keep captures as comparable Evidence across releases: Evidence, snapshots and version comparison.
- Read REA’s network capture reference.