HAR File Viewer
Open a .har capture and read the waterfall, per-phase timings, sizes and failures — the file never leaves this device.
0 bytes uploaded — the capture is read in this browser tab. Nothing from this file is stored between visits: no local copy, no link payload, no cache.
Drop a .har file here, or choose one — it is read on this device and never uploaded.
- —Requests
- —Failed
- —Transferred
- —Wall clock
- —Slowest
- —Unknown sizes
What a HAR file holds
- log — version, the capturing tool, and everything below it
- log.pages — one record per navigation, with its onLoad time
- log.entries — one record per request, in capture order
- entry.request — method, URL, headers, cookies, query string, post data
- entry.response — status, headers, cookies, content size and body
- entry.timings — blocked, dns, connect, ssl, send, wait, receive
A phase of -1 means the capture marks it as not applicable, not zero.
What this page does not do
- It never uploads, shares or stores the capture.
- It does not record a capture — export one from your browser first.
- It does not sanitize or re-export a redacted capture.
- It does not score, grade or rank performance.
- It never invents a field the capture does not contain.
Choose a request to see its headers, cookies, payload and timings.
A shared link carries the view options only — the filter, sort and phases. It never carries the capture.
Press ? for shortcuts
Do it offline:$
How to use it
- Record the page in your browser's Network panel, then export the request list as .har.
- Drop it here or choose it with the file button — dropping a capture starts no request of its own.
- Read the summary strip, then switch between table and waterfall; sort by slowest or largest, filter by status class, kind or failures only.
- Open a request to inspect it, and reveal only the values you need to see.
A .har file is what a browser Network panel exports: one JSON document holding every request of a session with its timings, sizes and status. Drop one here to read it as a sortable table and a waterfall, then open a request for its headers, cookies and body. Values arrive masked until you reveal them, and the capture is read in this tab.
How it works
A capture is one object with a single member, log: version names the format, creator the tool that wrote it, pages each recorded navigation, entries the requests. Every entry holds its own startedDateTime, request, response, cache record and timings.
Seven phases make up an entry's time: blocked, dns, connect, ssl, send, wait and receive. HAR 1.2 puts the ssl slice inside connect, so it is drawn at the tail of that bar and left out of the sum — counting both would invent time that never passed. A phase written as -1 means the recorder had nothing to report, so it reads n/a rather than 0.
A capture replays a real session, so it holds cookies, Authorization headers and whatever was posted. That sets every rule here: parsing runs in a worker in this tab, each inspector value starts masked behind its own control, copying waits until you reveal one, and a share link carries view options, never the file.
Examples
clean-3.har — a three-request page load exported as HAR 1.23 requests · 0 failed · 23,326 B transferred · 265 ms wall clock
+0 ms · GET · https://example.test/index.html?ref=fixture · 200 OK · document · 632 B · 150.5 ms
+160 ms · GET · https://example.test/assets/site.css · 200 OK · stylesheet · 2,138 B · 40 ms
+205 ms · GET · https://cdn.example.test/app.js · 200 · script · 20,556 B · 60 msOffsets run from the first request, so the rows share one timeline. The third shows a bare 200: that response was HTTP/2, which has no reason phrase, and an empty statusText prints empty.
aborted-zero.har — one request that never received a response+0 ms · GET · https://example.test/never-finished.json · 0 · other · unknown · n/a
Request 1 (GET https://example.test/never-finished.json) records status 0, which is how a capture stores a request that never got a response — it is counted as a failure, not as a 2xx.
Request 1 (GET https://example.test/never-finished.json) reports `headersSize`/`bodySize` as -1, the HAR value for "not available" — its size column reads "unknown" and it is left out of the transferred total rather than counted as 0.
Request 1 (GET https://example.test/never-finished.json) carries no readable `timings` phases, so it has no bar on the waterfall — only its start and its total time are known.One aborted request raises three notices, each naming the request it came from. The row keeps its place on the timeline with no bar to draw, and its unknown size stays out of the transferred total.
truncated.har — an export cancelled while it was being writtenThis file is not valid JSON — line 148, column 38. The parser reported: Unterminated string in JSON at position 3928 (line 148 column 38)
The text ends with brackets still open, which is what a capture looks like when the export was interrupted — re-export the recording and try the new file.A file that cannot be read whole shows nothing: half a capture means half a waterfall and wrong totals. The position is quoted so you can see where writing stopped.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
The ssl phase is already inside connect
HAR 1.2 includes the ssl time in connect, so a bar showing both would outrun the request. The handshake is drawn at the end of that segment and still gets its own number.
-1 means unavailable, and never zero
Recorders write -1 for a size or phase they cannot report. A 0 would claim an empty response, so those cells read unknown and those phases n/a, joining no total.
Most captures carry no response bodies
content.text is optional and exporters routinely omit it or store it base64-encoded. Absent, the inspector says so; encoded, the text appears as the file holds it, undecoded.
Fields that start with an underscore came from the tool
_initiator, _resourceType and _transferSize are extensions the capturing tool added, which HAR 1.2 permits. They sit under their own heading, outside the file's own numbers.
Sharing a view shares no capture
0 bytes uploaded · nothing stored between visits. A share link carries view, filters, sort and phases, so reopening it asks for the .har file again.
Common errors
There is nothing to read yet — the file is empty.- The chosen file holds no bytes, usually because it was saved before anything had been recorded.
This file is not valid JSON — line 5, column 3. The parser reported: Expected double-quoted property name in JSON at position 56 (line 5 column 3)- A hand-edited capture easily loses its JSON syntax, most often to a comma left after the last item of a list. The parser's verdict is kept, with the line and column it stopped at.
This file is valid JSON but not a HAR capture — there is no `log` object at the top level. A HAR 1.2 file is a single object whose only member is `log`, and `log` carries a `version` string.- The file is JSON but has none of the shape this page reads: a request collection exported from an API client is not a HAR.
This HAR carries no requests — `log.entries` is empty or absent, so there is nothing to lay out. The Network panel was probably cleared before the export.- A valid capture with an empty request list: recording has to be armed before the navigation you want, and the list must survive until the export.
This capture is 24.001 MiB (25,166,848 bytes), past the 24 MiB limit this page can hold in one tab — nothing was read. Export a shorter recording, or clear the Network panel before the step you want to capture.- Long sessions carrying response bodies outgrow what one tab can lay out, so the file is declined whole rather than read in part. The limit and the arriving size are both printed.
FAQ
Is my HAR file uploaded anywhere?
No. It is read here and parsed in a worker in the same tab; the route issues no request of its own, which the build checks on every run. Nothing reaches storage either.
Why are header and cookie values hidden until I reveal them?
Because a capture normally contains live session cookies and bearer tokens, and screens get shared. Each value opens on its own, and the choice is never remembered: a new file starts masked again.
Why does a request show no timings or an unknown size?
Because the file says so. An aborted request, or one answered from cache, often carries no timings object and writes -1 for its sizes; the gap is reported rather than filled with a zero that would move the totals.
Keyboard shortcuts
- o
- Open a capture — the same picker as the button.
- f
- Jump to the filter row.
- j / k
- Move to the next or previous request.
- Enter
- Inspect the selected request.
- Esc
- Close the inspector; focus returns to its row.
- 1 / 2
- Switch between the table and the waterfall.
- ⌘/Ctrl + C
- With nothing selected, copy the derived summary; a selection copies itself.
- ⌘/Ctrl + Shift + C
- Force-copy the derived summary.