Skip to content
← All articles

HAR file: what it is, how to record one, and how not to hand over your session

In short. A HAR (HTTP Archive) file is a JSON log that your browser writes for every network request a tab made: URLs, headers, status codes, sizes and timings. Support teams ask for it to see the problem through your eyes. Recording one takes a minute in DevTools. The catch: a raw HAR contains your session cookies and auth tokens, so scrub it before you send it.

What a HAR file is and why support asks for one

HAR stands for HTTP Archive. It is a plain text file in JSON format that your browser's developer tools produce from the network log of a single tab: every request the page sent and every response it received. The extension is .har, and the contents are human-readable JSON you can open in any text editor.

The format started in the Firebug project, reached version 1.2 and never left draft status — yet every major browser can export it and dozens of tools can read it. That is exactly why support asks for a HAR: it is a portable way to hand over the network picture without giving anyone access to your machine.

Inside the file there is a single log object with four meaningful parts:

  • log.version and log.creator — the format version and which browser wrote it;
  • log.pages — loaded pages with onContentLoad and onLoad markers;
  • log.entries — the important one: an array with one record per network request;
  • inside each entry — request (method, URL, headers, cookies, POST body), response (status, headers, cookies, size, sometimes the body), timings (per-phase breakdown), serverIPAddress and time, the total duration in milliseconds.

Who actually reads HAR files: hosting and CDN support, payment gateway engineers, front-end and back-end developers, SREs during an incident. They all look for the same things — which request failed, which returned the wrong status, and where the time went.

A HAR is not a screenshot and not a server log. It is what your browser saw: your cookies, your headers, your route to the site. That is both why it is useful for diagnosis and why it is dangerous to email around.
Diagram of HAR file structure: the log object, the entries array, and request, response and timings inside one entry
A HAR is JSON: log to entries, one record per network request.

How to record a HAR file, step by step

The procedure is the same everywhere; only the menu labels differ. Six steps:

  1. Open the tab where the problem happens.
  2. Open developer tools — usually F12 or Ctrl+Shift+I (Cmd+Option+I on macOS).
  3. Switch to the Network tab.
  4. Tick "Preserve log" (called "Persist Logs" in Firefox). Without it a redirect or a reload wipes the list.
  5. Reproduce the problem: reload the page, click the button, submit the form — exactly the action that breaks.
  6. Export the result as HAR and save the file.

Chrome

Open with F12, or the three-dot menu, then More tools, then Developer tools. Go to the Network tab. "Preserve log" sits in the toolbar next to "Disable cache" — tick both, so you capture a real load rather than a cache hit.

To export: the download-arrow icon in the Network toolbar, or right-click the request list and choose the "save all as HAR" item. Recent Chrome builds split this into two options: a sanitized export, which strips cookies and Authorization headers, and a separate one that keeps sensitive data and response bodies. Exact wording changes between versions — look for "sanitized", "sensitive data" or "with content".

Firefox

Open with F12, or the menu, then More tools, then Web Developer Tools. Go to the Network tab. The checkbox is called "Persist Logs" and lives in the filter bar above the request list.

To export: right-click any request in the list and choose "Save All As HAR". There is usually a "Copy All As HAR" next to it, handy when you want to paste into a ticket rather than attach a file.

Edge

Edge is Chromium-based, so the panel matches Chrome closely. Open with F12, or the three-dot menu, then More tools, then Developer tools. Go to the Network tab, tick "Preserve log" and "Disable cache", reproduce the issue, then export with the download-arrow icon in the Network toolbar or via right-click on the request list.

Two Edge-specific notes. First, in enterprise builds developer tools can be disabled by policy — if F12 does nothing, that is the likely reason and only an administrator can lift it. Second, Edge shows a separate list of requests per tab, so make sure you are exporting from the tab that actually reproduced the problem, not from a background one.

Safari

Developer tools are hidden by default. Open Safari settings, go to the Advanced tab and enable the option that shows web developer features; a "Develop" menu then appears in the menu bar.

Open the inspector with Cmd+Option+I or Develop, then Show Web Inspector, and switch to the Network tab. To export, use the export button (a down arrow) on the right side of the Network toolbar — it writes the whole log to a .har file.

Safari's equivalent of "Preserve log" is not present in every version and lives in the Network tab's own settings rather than the main toolbar. If you cannot find it, simply do not reload more than necessary: start the recording, reproduce the problem, export immediately. Safari on iOS cannot export a HAR by itself — connect the device to a Mac and use Safari's Develop menu to inspect it remotely.

Chromium-based browsers in general

Brave, Opera, Vivaldi, Yandex Browser and the rest of the Chromium family all ship the same DevTools. The keyboard shortcut, the Network tab, the "Preserve log" checkbox and the HAR export behave identically; only the path through the application menu is worded differently.

BrowserOpen DevToolsKeep-the-log checkboxExport
ChromeF12 → Network tabPreserve logDownload-arrow icon in the Network toolbar, or right-click → save all as HAR
FirefoxF12 → Network tabPersist LogsRight-click the request list → Save All As HAR
EdgeF12 → Network tabPreserve logDownload-arrow icon in the Network toolbar
SafariCmd+Option+I after enabling the Develop menuNot in every version; in the Network tab settingsExport button on the right of the Network toolbar
Other Chromium browsersF12 → Network tabPreserve logSame as Chrome
The most common reason for "they sent me an empty HAR" is a missing "Preserve log" tick. Without it a redirect, a link click or a plain reload clears the request list and you export nothing. Enable it before you reproduce the problem.
Diagram of a browser Network panel: record button, preserve log checkbox, request list and HAR export control
The order that matters: open Network, enable Preserve log, reproduce, then export.

What ends up inside a HAR: cookies, tokens, passwords

This is the part most instructions skip. A HAR is not anonymised telemetry. It records the content of the exchange, not just the fact of it. A raw file contains:

  • Session cookies — in the request.cookies array and in the Cookie header. Enough to enter your account without a password for as long as the session lives.
  • The Authorization header — bearer tokens, JWTs, API keys, and Basic auth, which is a base64 string one decode away from your login and password.
  • Set-Cookie headers from responses — freshly issued session identifiers.
  • POST bodies in request.postData — everything you typed into a form: address, phone number, order id, and on a sign-in page, the credentials themselves in clear text.
  • URL parameters — password reset tokens, one-time links and API keys whenever they travel in the query string.
  • Response bodies, if the export was made "with content" — HTML and JSON with personal data: names, e-mails, amounts, documents.
  • Your network pathserverIPAddress per host, plus the full list of third-party domains the page contacted.
Sending an unprocessed HAR to support means handing over access to your session. The file lands in a ticket system, sits in mailboxes, gets forwarded between staff and stays there for years. Treat a raw HAR as the equivalent of a password.

How to record a HAR without sensitive data

  • Do not sign in inside the same recording. Log in first, then open DevTools, start capturing and reproduce only the failure. That keeps the sign-in POST with your credentials out of the file.
  • Capture the minimum. One action, one HAR. A short recording contains less and is far easier for support to read.
  • If the problem reproduces logged out, capture it in a private window on an anonymous session. That is the cleanest option: almost no cookies, no tokens.
  • Do not save response bodies unless asked. Response bodies (response.content.text) are a separate thing from headers. An export "with content" embeds whole HTML and JSON payloads as base64: the file balloons and starts carrying whatever was on screen. Performance diagnosis does not need bodies at all — timings and sizes live in other fields.
  • Do not rely on the browser sanitising for you. Recent Chrome versions do strip cookies and Authorization from the default export, but that behaviour is not in every version and not in every browser. Always verify the file yourself — the command is below.
Diagram showing cookies, Authorization header, Set-Cookie and request bodies being removed from a HAR while timings remain
A scrubbed HAR loses its secrets but keeps its timings, which is all performance diagnosis needs.

How to scrub a HAR before sending it

A HAR is JSON, so it can be edited programmatically. The handiest tool is jq. The command below empties cookies in requests and responses, drops auth headers and Set-Cookie, and wipes POST bodies and response bodies:

# Scrub a HAR: cookies, auth headers, request and response bodies
jq --arg drop "cookie,authorization,proxy-authorization,x-api-key,x-auth-token,x-csrf-token" '
  ($drop | split(",")) as $d
  | .log.entries |= map(
        .request.cookies  = []
      | .response.cookies = []
      | .request.headers  |= map(select((.name | ascii_downcase) as $n | $d | index($n) | not))
      | .response.headers |= map(select((.name | ascii_downcase) != "set-cookie"))
      | (if .request.postData    then .request.postData.text = "[removed]"
                                      | .request.postData.params = [] else . end)
      | (if .response.content    then .response.content |= del(.text) else . end)
    )' raw.har > clean.har

Then verify. The first command must print nothing, the second must print zero:

# 1. Any cookie/authorization headers left?
jq -r '.log.entries[].request.headers[]?.name' clean.har   | tr 'A-Z' 'a-z' | grep -E '^(cookie|authorization)$' | sort -u

# 2. Any response bodies left?
jq '[.log.entries[].response.content.text // empty] | length' clean.har

# 3. Eyeball it: grep the whole file for suspicious strings
grep -o -i -E '(bearer [a-z0-9._-]{10,}|sessionid|phpsessid|password)' clean.har | sort -u

Check query strings separately. If the site passes a token through the URL (?token=…, ?key=…), it stays in request.url and no amount of header scrubbing removes it. Those URLs are easiest to edit by hand in a text editor.

If you have already sent a HAR captured on a live session, treat that session as compromised. Sign out on all devices — any decent service has a "terminate all sessions" button — revoke API keys that appeared in headers, and change the password if the recording contained a sign-in.

An important consequence: a scrubbed HAR is just as informative to analyse as a raw one. Timings, status codes, sizes (bodySize, headersSize), caching and compression headers, request order — all of that survives. The secrets live in different fields. So "we need a HAR with content" is a request worth questioning: for a performance investigation it is almost never required.

How to open and read a HAR file

Three practical options:

  • Back into DevTools. Open the Network tab and drag the .har straight onto the request list — the browser redraws the familiar waterfall with all timings. Fastest way to look at it with your eyes, and it works offline.
  • An online analyser. Our HAR analyser parses the file and surfaces bottlenecks immediately: slowest requests, redirect chains, heavy uncompressed resources.
  • A text editor or jq. When you have one specific question ("which request returned 502?"), a one-liner beats scrolling a UI.

What to look at first:

  • The waterfall — the visual timeline. Look for long bars and staircases, where the next request only starts after the previous one finished.
  • Status codes — anything that is not 2xx: 3xx (redundant redirects), 4xx (broken links, expired auth), 5xx (server-side failure).
  • Timings — the per-phase breakdown in the table below.
  • Sizes and compression — a bodySize in the hundreds of kilobytes with no Content-Encoding header means the resource ships without gzip or brotli.
Field in timingsWhat it measuresWhat a large value suggests
blockedTime queued in the browser before the request startsHit the per-host connection limit, or a slow proxy or browser extension is in the way
dnsDomain name resolutionSlow or distant resolver, cold cache, too many third-party domains
connectTCP connection setupServer is far away, packet loss, no keep-alive
sslTLS handshake (included in connect)Long certificate chain, no session resumption, weak server hardware
sendPushing the request to the serverLarge POST body or a narrow uplink on the client
waitWaiting for the first byte — this is TTFB at request levelSlow backend: heavy database queries, no caching, external API calls inside the handler
receiveDownloading the response bodyResource is large or uncompressed, narrow link, no CDN

A value of -1 in any field means "not applicable" — for example dns and connect are -1 when the connection was reused. The phases add up to entry.time.

What a HAR is not

A HAR describes the network, and only the network. It will not show you:

  • JavaScript execution. Long tasks, a blocked main thread, wasteful re-renders — that is the Performance profiler, not a HAR.
  • Rendering and layout. Layout shifts, time to paint the largest element, responsiveness to a click — those are Core Web Vitals, and a HAR does not measure them.
  • A score. A HAR is raw data, not a report. For a synthetic audit with recommendations use a website speed testing tool.
  • What happened on the server. A long wait tells you the backend was slow, not why — that answer lives in application logs.
Waterfall diagram: a long wait phase on the document, a queue of blocked requests and one heavy uncompressed resource
Three classic waterfall patterns: slow backend, connection queue, and a heavy uncompressed resource.

How to find the cause of a slow page in a HAR

Start with two commands: one shows who thought the longest, the other who weighs the most.

# Top 20 requests by server think time (wait ~ TTFB)
jq -r '.log.entries[] | [(.timings.wait | floor), .response.status, .request.url] | @tsv' page.har   | sort -rn | head -20

# Heaviest responses and how they are compressed
jq -r '.log.entries | sort_by(-(.response.bodySize)) | .[:15][]
       | [ .response.bodySize,
           (.response.content.mimeType // "-"),
           (first(.response.headers[] | select(.name | ascii_downcase == "content-encoding") | .value) // "none"),
           .request.url ] | @tsv' page.har
# Redirect chains
jq -r '.log.entries[] | select(.response.status >= 300 and .response.status < 400)
       | [.response.status, .request.url, (.response.redirectURL // "-")] | @tsv' page.har

# URLs requested more than once
jq -r '.log.entries[].request.url' page.har | sort | uniq -c | sort -rn | awk '$1 > 1'
What you see in the HARLikely causeWhat to do and how to verify
Long wait (hundreds of ms to seconds) on the HTML document itselfSlow backend: heavy queries, no page cache, an external call inside the handlerAdd server-side caching, profile the backend. Measure from outside with a speed check
Dozens of requests with a long blockedPer-host connection limit reached, typical of HTTP/1.1Move to HTTP/2 or HTTP/3, bundle small files. Check the protocol and headers with the HTTP header analyser
A 301 → 302 → 200 chain at the start of the recordingRedundant redirects: http to https to www to trailing slashCollapse to a single hop. Verify the chain with the URL and redirect check
Hundreds of kilobytes with no Content-Encodinggzip or brotli not enabled on the serverTurn on compression for text types. Verify with the HTTP header analyser
Lots of third-party domains near the start of the waterfallBlocking third-party scripts: analytics, chat widgets, fontsLoad them with async or defer, after the main content
The same URL repeated dozens of timesNo caching, a broken retry loop, or a loop in client codeSet Cache-Control and ETag, cap retries
Long dns across many domainsSlow resolver or cold cacheReduce the number of third-party domains. Verify with a DNS lookup and a ping check
Long connect and sslDistant server, packet loss, expensive handshakeUse a CDN and keep-alive, inspect the route with traceroute

HAR recording problems and how to fix them

The file is empty or has two entries

Almost always a missing "Preserve log" tick, with a reload wiping the list. The other cause is opening DevTools after the page had already loaded: the browser only records while the panel is open. The correct order is open DevTools, enable Preserve log, and only then reload.

The recording stops at a redirect

Same reason. Every navigation is a fresh page load, and without Preserve log the list is cleared. It shows up most often on sign-in and checkout flows, where several hops happen in a row.

The file is enormous

A 50–200 MB HAR usually means an export "with content" on a heavy page: response bodies sit inside as base64, which inflates them by roughly a third over the original bytes. What to do:

# How many entries, and how big
jq '.log.entries | length' page.har
du -h page.har

# Keep only your own domain — usually shrinks the file several times over
jq '.log.entries |= map(select(.request.url | test("^https://example\.com/")))' page.har > small.har

# Or drop response bodies while keeping every diagnostic field
jq '.log.entries |= map(if .response.content then .response.content |= del(.text) else . end)'    page.har > light.har

The file will not open and the analyser complains about JSON

Usually the file is truncated: the browser or tab died mid-export, or the recording was simply too long. The tell is that the file does not end with }. Check integrity with jq empty page.har — if the JSON is broken, jq reports the offset. The only fix is a fresh, shorter recording. Another common cause: the file was sent through a messenger that renamed or repackaged it — try the original.

The request you need is missing

Check three things. First, filters in the Network panel: with a type filter on (XHR only, for instance) the export usually still contains everything, but you will not see it on screen — search the file, not the UI. Second, the request may have come from another tab, an iframe or an extension; a HAR only covers the current tab. Third, the response may have come from cache: tick "Disable cache" and try again.

How to analyse a HAR with our tools

Upload the file to the HAR analyser: it parses log.entries, breaks the time down by phase, surfaces the slowest requests, redirect chains, error responses and heavy uncompressed resources. A file scrubbed of cookies and tokens analyses just as fully — scrubbing does not touch timings or sizes.

What to pair it with:

Frequently asked questions

Is a HAR file dangerous?

A raw one is. It carries your session cookies, the Authorization header and form bodies — enough to enter your account without a password until the session expires. A scrubbed HAR is safe and still perfectly usable for performance diagnosis.

How do I open a HAR file offline?

Drag it onto the Network tab of any browser's developer tools and it renders as a normal waterfall. Nothing is uploaded anywhere.

How is a HAR different from a screenshot of the Network panel?

A screenshot is a picture; a HAR is data. With a HAR you can sort requests, sum sizes, find a specific header and feed the file to an analyser. Support almost always needs the file itself.

Why is there no response body in my HAR?

Because the export was the plain one rather than "with content". For performance work that is fine and in fact preferable: timings, statuses and sizes are all there, and no personal data is.

Can I record a HAR on a phone?

Not directly in a mobile browser. The standard route is remote debugging: connect the device to a computer and capture from desktop Chrome for Chromium-based Android browsers, or from Safari on macOS for Safari on iOS. The Network panel then works as usual.

How many entries is normal for one page?

A typical page makes anywhere from a few dozen to a couple hundred requests. A thousand or more is a signal to look for a loop in client code or an avalanche of third-party scripts.

Support asks for a HAR "with content" — should I agree?

Ask which request they actually need. Often one specific response body is enough rather than the whole page. If bodies really are required, capture the recording on a test account or on data you do not mind sharing.

Checklist before you send a HAR

  • DevTools opened before the reload, "Preserve log" enabled.
  • The recording contains only the reproduction — no sign-in, no unrelated clicking.
  • Exported without response bodies unless they were explicitly requested.
  • File run through jq: cookies emptied, Authorization and Set-Cookie removed, POST bodies wiped.
  • Verification done: grepping for cookie, authorization, bearer, password returns nothing.
  • Tokens in query strings replaced by hand.
  • File size reasonable — unrelated domains filtered out.
  • jq empty file.har runs clean, so the JSON is intact.
  • The file reopens in the Network panel and contains the request in question.
  • If the recording used a live session, that session has been terminated and API keys revoked.

Check your website right now

Check your site's speed →
More articles: Performance
Performance
Gzip vs Brotli: Web Compression Compared
16.03.2026 · 459 views
Performance
CDN Cache Invalidation: Strategies for Delivering Fresh Content
16.03.2026 · 453 views
Performance
Resource Hints Explained: Prefetch, Preload, Preconnect, DNS-Prefetch
16.03.2026 · 375 views
Performance
Latency vs Throughput: Understanding Network Performance Metrics
16.03.2026 · 307 views