https://w3c.github.io/web-performance/specs/HAR/Overview.html on 14 August 2026 by scripts/external_checks_traffic_files.sh.This is an old revision of the document!
A crawl is an event. A traffic file is the artefact it leaves behind: a re-readable record of what went over the network, written once and analysed many times. Writing one is what lets you answer a question you had not thought of on the day of the crawl, hand the evidence to a reviewer, and let somebody else recompute your number instead of trusting it.
This page is about choosing where to tap, and what the resulting file can and cannot answer. It is not about how HTTP works — for the wire format go to the RFCs, and for the browser API go to MDN. It pairs with the crawler comparison (what drives the browser), Archives (reading somebody else's recording), Requests (what you do with the requests once you have them) and IP classification (one field in the file that most people miss).
The one thing to take away. The three places you can tap — the packet stream, an intercepting proxy, the browser's own internals — are not nested, and neither is a superset of the others. Measured on a single page load of a local fixture (What We Ran):
serverIPAddress in the browser's file is the proxy's;pageref fields and an empty log.pages — so you cannot tell from it which page load a request belongs to.
Pick the layer from the question, not from what is easiest to install, and say in the paper which one you used. “We collected HAR files” does not identify an instrument: Chrome, Firefox, Playwright and mitmproxy all write files labelled “version”: “1.2” and they disagree about the contents.
| Packet capture | Intercepting proxy | Browser-internal | |
|---|---|---|---|
| Typical tool | tcpdump, Wireshark/tshark | mitmproxy, Burp, Fiddler, Charles | DevTools HAR export, CDP, recordHar |
| File | .pcap / .pcapng | mitmproxy .flows, or a HAR export | HAR, NetLog, or your own JSON |
| Sees requests the browser decided not to send | ✗ | ✗ | ✓ |
| Sees requests from other processes on the host | ✓ | only if they are proxied | ✗ |
| Response bodies | only if you can decrypt TLS | ✓ by default | ✓ but usually off by default |
| Which page load a request belongs to | ✗ | ✗ (no pageref) | ✓ (pageref / log.pages) |
| Who initiated the request (script, parser, redirect) | ✗ | ✗ | ✓ via CDP; ✗ in a plain HAR |
| Origin server IP address | ✓ | ✓ (as the proxy saw it) | ✓ unless you are behind a proxy |
| Cache hits, and requests served from memory | ✗ (no packets) | ✗ | ✓ |
| TLS/QUIC handshake detail, timing at packet granularity | ✓ | partial | ✗ |
| Changes what the site sees | no | yes — new TLS stack, new certificate | mostly no |
| Volume per 1,000 sites | tens of GB | GB | hundreds of MB without bodies |
Three consequences that decide most projects:
SSLKEYLOGFILE environment variable, and Wireshark reads that file — but a keylog file is a decryption key for every session in the capture, so it inherits every rule in Before You Publish The File.HAR — HTTP Archive format — is a JSON log of HTTP transactions. It is the lingua franca of the browser layer: every major browser exports it from DevTools, and every automation library can write one.
Its specification is abandoned, and this matters more than it sounds. HAR 1.2 was written in 2011–2012 by Jan Odvarko and taken up by the W3C Web Performance Working Group, which never published it. The W3C copy now opens with a banner reading “\*DO NOT USE\* This document was never published by the W3C Web Performance Working Group and has been abandoned.”1) Six papers in our corpus cite one of the two W3C URLs as the HAR specification — and the older dvcs.w3.org copy several of them point at does not carry the banner, so following the citation does not tell you the document was withdrawn. There has been no successor: a community repository carries a “proposed” 1.3 that has been dormant for years. In practice the specification is whatever the writers agree on, which is why the differences below exist at all. Cite Odvarko's original at softwareishard.com/blog/har-12-spec/ if you must cite something, and name your writer.
Two different things are called “HTTP Archive”, and conflating them is the most common error in this literature. HAR is a file format. The HTTP Archive (httparchive.org) is a monthly crawl of millions of sites, queryable in BigQuery, and it is a dataset, not a file you made. In our corpus, 14 papers analyse the dataset and 32 use the format, and only one paper does both ([1Trevisan, Martino; Traverso, Stefano; Bassi, Eleonora; Mellia, Marco (2019): "4 Years of EU Cookie Law: Results and Lessons Learned", Proceedings on Privacy Enhancing Technologies 2019(2):126-145. (DOI)]). See Use in Publications.
Only a handful of the schema's fields carry a measurement. In rough order of how often you will touch them:
| Field | What it is | Watch out for |
|---|---|---|
log.entries[] | one HTTP transaction | a redirect chain is n entries, not one; sort by startedDateTime before assuming order |
log.pages[] + entry.pageref | page boundaries | a proxy-written HAR has neither — see below |
request.url, .method, .headers | the request | headers are an array of objects, not a map; duplicates are legal and meaningful |
request.queryString | parsed query parameters | pre-parsed for you, but the raw string is still in url — and they can disagree on encoding |
request.postData.text | the request body | where exfiltrated identifiers live; also where credentials live |
response.status | status code | a negative or zero status is a request that never completed; check it before averaging anything |
response.redirectURL | Location of a redirect | the cheapest way to reconstruct a chain |
response.content.size / .text | the body | .text is normally absent; .size is present anyway |
response.cookies / request.cookies | per-transaction cookies | not a cookie jar — see below |
serverIPAddress | the address the recorder connected to | see IP classification |
timings | phase breakdown, milliseconds | -1 means “not applicable or not available”, and it is common; do not sum blindly |
We recorded one load of a local fixture three ways at once — Playwright's HAR with bodies omitted, the same with bodies embedded, and a raw CDP session on the same page — and diffed them field by field. The fixture deliberately contains a redirect chain, a script-initiated fetch, a POST with a body, a 200 KiB response, a request that is never answered, a WebSocket, and an image the page's own CSP forbids. This is the comparison table from the run's output; the full output, including the per-URL outcome table and the extension-field list, is on traffic_files.
HAR (omit) HAR (embed) CDP entries / requests 12 12 11 …of which redirect hops 2 2 2 …of which never completed (status -1 / loadingFailed) 2 2 2 entries carrying response body text 0 6 on demand (Network.getResponseBody) entries with an initiator / call stack 0 0 11 …with a JS stack frame 0 0 5 entries with a resource type 12 12 11 entries with a frame id 12 12 11 entries with serverIPAddress 8 8 7 WebSocket connections 1 1 1 WebSocket frames 0 4 4
Reading that table, in order of how much it costs you:
Network.requestWillBeSent carries initiator, including a JavaScript stack. If your question is “which script caused this third-party request” — the question behind most of Requests and all of JavaScript — a HAR cannot answer it and you need the browser's event stream, or a crawler that records it for you (OpenWPM, PageGraph).content: 'omit' the file was 20,566 B; with content: 'embed' it was 226,719 B — 11× larger, for one 200 KiB response. Bodies are base64-encoded when they are not text, so budget roughly the raw byte count plus a third on top of it. At crawl scale this is the difference between a dataset you can release and one you cannot.status: -1. Why they failed is not in the standard: Playwright adds a non-standard response._failureText (it read “csp” for the blocked image, and nothing at all for the request left in flight). CDP told us blockedReason: “csp” for one and, for the other, nothing — it had emitted no terminal event by the time the context closed./slow request failed and recorded the 204 beacon as complete; CDP emitted loadingFailed net::ERR_ABORTED for the beacon and no terminal event at all for /slow. Neither is a superset. In-flight requests at the moment you stop recording are recorded inconsistently, so drain the page before you close the context and report how long you waited.response.cookies correctly contained the HttpOnly cookie — that part of the folklore is wrong, the flag hides a cookie from document.cookie, not from the recorder. But at the end of the load the browser jar held 4 cookies and one of them, set by document.cookie in a script, appears in no HAR entry, because it never crossed the network. Counting cookies from a HAR counts cookies observed in HTTP headers, which is a different quantity from cookies in the jar. Say which one you mean. Cookies is the page for the rest of that problem._webSocketMessages, and it only started doing so in version 1.61 (June 2026) — so a HAR written by an older Playwright, or by a different tool, may show nothing. Check rather than assume._-prefixed names for custom fields, and the useful ones all live there. Playwright 1.62.1 emitted exactly _resourceType, _securityDetails, _serverPort, _webSocketMessages, response._failureText and response._transferSize. Chrome DevTools emits a different set. So an analysis script written against one writer's HAR quietly produces empty columns against another's.| Writer | How | Status, checked 2026-08-14 |
|---|---|---|
| Chrome / Edge DevTools | Network panel → Save all as HAR (sanitized) or (with sensitive data) | current; the sanitized variant is the default since Chrome 130 — see Before You Publish The File |
| Firefox DevTools | Network panel → Save All As HAR; devtools.netmonitor.har.enableAutoExportToFile auto-saves every load | current; the pref is how [2Wang, Kailong; Zhang, Junzhe; Bai, Guangdong; Ko, Ryan K. L.; Dong, Jin Song (2021): "It's Not Just the Site, It's the Contents: Intra-domain Fingerprinting Social Media Websites Through CDN Bursts", in: Proceedings of the ACM Web Conference. (DOI)] automated it. Read the neighbouring prefs too |
| Playwright | browser.newContext({recordHar: {path, content, mode, urlFilter}}), or context.tracing.startHar(path) / stopHar() since 1.60 | current; content (omit/embed/attach) is the 11× size difference, mode is full or minimal. Moving: the tracing API is new in 1.60 (May 2026) and WebSocket requests only started appearing in Playwright's HAR in 1.61 |
| Puppeteer | no built-in writer — use a library over CDP | chrome-har-capturer (npm 0.14.4, 2026-01-27) is maintained and is what the corpus uses [3Muthuraj, Naveenraj; Eghbal, Nooshin; Lu, Paul (2024): "Replication: "Taking a long look at QUIC"", in: Proceedings of the ACM Internet Measurement Conference. (DOI), 4Zhang, Xumiao; Jin, Shuowei; He, Yi; Hassan, Ahmad; Mao, Z. Morley; Qian, Feng; Zhang, Zhi-Li (2024): "QUIC is not Quick Enough over Fast Internet", in: Proceedings of the ACM Web Conference. (DOI)] |
| Selenium | none built in; classic WebDriver has no network commands at all | this is why Selenium crawls historically end up with a proxy bolted on, and selenium-wire, the usual bridge, was archived in January 2024. WebDriver BiDi has since given Selenium native network interception — with its own caveats — but still no HAR writer |
| mitmproxy | mitmdump –set hardump=out.har | current (12.2.3, 2026-05-12); proxy-layer HAR — bodies by default, no page boundaries |
| WebPageTest | records a HAR alongside its own waterfall [5Chaqfeh, Moumena; Zaki, Yasir; Hu, Jacinta; Subramanian, Lakshmi (2020): "JSCleaner: De-Cluttering Mobile Webpages Through JavaScript Cleanup", in: Proceedings of the ACM Web Conference. (DOI)] | current; run by Catchpoint since 2020 |
| HARExportTrigger | a Firefox extension that triggers export from inside the page | deprecated and archived, description “DEPRECATED”; last release 0.6.1, May 2018. It is what [6Borgolte, Kevin; Feamster, Nick (2020): "Understanding the Performance Costs and Benefits of Privacy-focused Browser Extensions", in: Proceedings of the ACM Web Conference. (DOI)] automated Firefox with; for new work use the pref above instead |
| BrowserMob Proxy | a Java proxy that writes HAR | effectively dead: the last GitHub Release is 2.1.4 (December 2016); a later 2.1.5 tag carries no release notes, and there have been no substantive commits since |
Firefox's defaults are not Chrome's, and the prefs say so. Read straight out of browser/app/profile/firefox.js in current Firefox: includeResponseBodies defaults to true, so a Firefox HAR carries bodies unless you turn them off; multiple-pages defaults to false, so an auto-exported HAR covers one page; and pageLoadedTimeout is 1500 ms, which is how long the exporter waits after load before writing — anything still in flight after that is what §What a HAR Loses is about. Chrome's sanitized-by-default export strips headers, not bodies. Two files both labelled HAR 1.2, three different defaults.
An intercepting proxy terminates TLS in the middle: it presents your own CA's certificate to the client, opens its own connection to the origin, and sees plaintext in both directions. mitmproxy is the field's default — 98 papers in our corpus, against 18 for Burp Suite and 15 for Fiddler (Use in Publications) — and mitmdump is its non-interactive form, which is what a crawl wants. It is actively maintained (12.2.3, May 2026); of the alternatives named in the corpus, Fiddler Classic is no longer in active development and Charles is commercial.
Its two research-relevant outputs are its own .flows stream (-w file) and a HAR (–set hardump=file). We ran the same fixture load through mitmdump and recorded the browser's HAR at the same time (excerpt of the run's output — the rest is on traffic_files):
browser HAR mitmproxy HAR entries 12 11 entries with response body text 0 10 entries with _resourceType 12 1 entries with a pageref 12 0 log.pages 1 0 WebSocket entries 1 0 in the browser HAR only: http://127.0.0.99:1/blocked-by-csp.gif, ws://127.0.0.1:8098/ws in the mitmproxy HAR only: /ws file sizes browser HAR (content omitted) 20453 B mitmproxy HAR (bodies included) 261692 B mitmproxy .flows (its own format) 232420 B ratio, mitmproxy HAR / browser HAR 12.8x
pageref values and an empty log.pages. In a crawl of n sites through one proxy you must reconstruct “which site was this” yourself, normally by having the crawler stamp a header or by writing one flow file per site. Doing it by timestamp is a bug waiting to happen: page loads overlap.ws://…/ws in the browser's, http://…/ws (the upgrade) in the proxy's. Joining the two files on URL silently loses it.serverIPAddress the browser records becomes the proxy's. Re-running the same script against https://example.com/ on 14 August 2026, the browser HAR recorded 127.0.0.1 — the proxy — and the mitmproxy HAR recorded 104.20.23.154, the origin. (That second address is not a constant: example.com sits on Cloudflare's anycast network and the edge address rotates. The point is which side each recorder sees, not the octets.) If you need origin addresses and you are proxying, take them from the proxy side. IP classification is where that matters.What the proxy buys you that the browser layer does not: traffic from a mobile app or an IoT device that has no DevTools at all — which is why much of the mobile-privacy literature is built on it [7Kollnig, Konrad; Shuba, Anastasia; Binns, Reuben; Van Kleek, Max; Shadbolt, Nigel (2022): "Are iPhones Really Better for Privacy? A Comparative Study of iOS and Android Apps", Proceedings on Privacy Enhancing Technologies 2022(2):6-24. (DOI)] — and full request and response bodies without the browser's cooperation. It is not the only way onto a phone: [8Figueira, Olivia; Trimananda, Rahmadi; Markopoulou, Athina; Jordan, Scott (2024): "DiffAudit: Auditing Privacy Practices of Online Services for Children and Adolescents", in: Proceedings of the ACM Internet Measurement Conference. (DOI)] goes to the packet layer there instead, with an on-device capture app, and keeps the browser layer for the web half of the same study.
What it costs. Certificate pinning breaks. TLS fingerprinting sees mitmproxy, not Chrome. QUIC and HTTP/3 interception is newer and less complete than HTTP/1.1 and HTTP/2 — mitmproxy enables it by default but documents the support as limited, and browsers do not accept a custom CA over QUIC the way they do over TLS — so a proxied crawl can silently downgrade the protocol under measurement. That is fatal when the protocol is the measurement, which is why the QUIC website-fingerprinting work captures at the browser and packet layers instead [9Siby, Sandra; Barman, Ludovic; Wood, Christopher; Fayed, Marwan; Sullivan, Nick; Troncoso, Carmela (2023): "Evaluating Practical QUIC Website Fingerprinting Defenses for the Masses", Proceedings on Privacy Enhancing Technologies 2023(4):79-95. (DOI)]. And you have added a component that can fail: a flow the proxy drops looks exactly like a request the site did not make.
tcpdump (4.99.6) and Wireshark (4.6.8) are, by a wide margin, the most-named capture instruments in the corpus — 119 and 128 papers — and for web measurement they are usually the wrong layer. They are there because the corpus is seven security and networking venues, and most of those papers are not measuring the web at all (Use in Publications separates the two).
Reach for a packet capture when the question is genuinely below HTTP:
Practicalities that bite:
tcpdump -s) truncates each packet; a BPF filter drops the traffic you do not want. Decide both before the crawl, because you cannot recover what you did not write.–ssl-key-log-file flag and the SSLKEYLOGFILE environment variable both write the NSS key-log format Wireshark reads; one https://example.com/ load through Playwright's Chromium build produced a five-line key log for us — or restrict yourself to what survives encryption: SNI, certificate details on older TLS versions, packet sizes, timing, and the addresses. That is exactly the input set of the website-fingerprinting literature..pcap vs .pcapng. .pcapng is the modern container (multiple interfaces, comments, name-resolution blocks, decryption secrets embedded in the file). Modern tcpdump and Wireshark write and read both; some older analysis code reads only classic .pcap. Convert with editcap rather than re-capturing.draft-ietf-opsawg-pcap (rev 08) and draft-ietf-opsawg-pcapng (rev 05) are still Internet-Drafts at the IETF; the first is even headed for Historic status rather than Standards Track. In practice the reference implementation is libpcap, and “what Wireshark reads” is the specification. Cite the drafts and the version of libpcap you used.
A traffic file is a recording, and a recording can be played back: serve the stored responses to a real browser so the page executes without touching the network again. That is the reproducibility argument for storing traffic in the first place, and it is where HAR and WARC meet — WARC being the archival format that Archives covers, and the one the Wayback Machine and pywb speak.
Replay is not free of the recording's blind spots, and Hantke et al. measured the cost [10Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)]. Replaying archived responses to a browser and comparing the JavaScript API calls against a live baseline, they found an average per-origin difference of 0.7% for their own execution-recording format, against 13.9% for HAR and 13.3% for WARC — “the drawback of replaying content rather than recording and inspecting the executions directly”. Replaying itself fails sometimes: over 8,523 origins they hit 311 HAR and 44 WARC issues replaying responses.
The same paper is also the best available check on whether a HAR captures the requests: across 8,544 origins they counted 778,500 requests in the HAR after filtering out non-page requests, against 776,229 recorded inside the browser — less than 0.3% difference. So a HAR is a faithful record of what left the browser; it is the why and the what happened next that it drops. Their framing is worth copying: “HAR is developed to record all requests that leave the browser, while WebREC captures every activity happening on the page.”
A raw traffic file is a credential store. By design it holds Authorization headers, Cookie and Set-Cookie headers, session tokens in query strings, CSRF tokens and login POST bodies, and — if you enabled bodies — whatever the responses contained.
This is not theoretical, and the one well-documented case is worth knowing in detail. Between 28 September and 17 October 2023 an attacker had access to Okta's customer support case-management system. Okta's own root-cause post says: “Some of these files were HAR files that contained session tokens which could in turn be used for session hijacking attacks”, and that “the threat actor was able to use these session tokens to hijack the legitimate Okta sessions of 5 customers”. The initial disclosure said 134 customers' files were accessed; a follow-up on 29 November 2023 revised the scope to essentially all Workforce and Customer Identity customers.2) An independent forensic investigation was reported closed on 8 February 2024 with no further malicious activity found, so the figures above stand.3) The files were uploaded by customers, at Okta's request, to help debug a login problem. Nobody involved thought they were sending a credential.
Treat every traffic file you did not personally sanitise as a live secret.
There is currently no maintained general-purpose HAR sanitiser, and this is a claim we tried to disprove rather than assert. Every candidate we could find is archived or dormant as of 14 August 2026: Google's har-sanitizer and Cloudflare's har-sanitizer are both archived read-only, as is the sanitizhar Chrome extension; Beyond Identity's har-sanitize has not been touched since November 2023; harmor was last committed in April 2025; and Edgio's har-tools is orphaned, its publisher having shut down in January 2025. If one of these has revived since, it is a better answer than the paragraph below — check before you write your own. What survives is vendor-specific: Okta's own sanitiser strips all cookies and the signature of ID/access/SAML tokens but explicitly “There is no attempt to remove user information as part of the sanitization process” and leaves JWT claims and SAML attributes intact, and recommends capturing with a test account instead. If you need sanitisation in a crawl pipeline, you are writing it.
Before a traffic file goes into an artefact, a support ticket, or a shared drive:
request.headers Authorization/Cookie/Proxy-Authorization, response.headers Set-Cookie, request.cookies/response.cookies, and any bearer/session token in request.queryString or request.postData. Chrome DevTools has sanitised its HAR export by default since Chrome 130 (October 2024) — but read what that means: “the network log exported in HAR format will no longer contain Cookie, Set-Cookie, and Authorization headers by default”, and nothing else. Query-string tokens, POST bodies, JWT claims and non-standard auth headers all survive it.A reviewer cannot check a traffic-file measurement without these, and in our corpus most papers give none of them:
tcpdump it is 3.4%.status: -1 entries — and how long you waited before closing the context.robots.txt handling.Wanted: a measurement of how much a browser HAR and a proxy HAR of the same crawl disagree at scale, on real sites rather than a fixture. Our fixture shows the mechanisms; nobody in this corpus has quantified the gap over a top-list crawl. If you run it, please add it here.
Every figure below comes from the publication corpus of 5,859 papers across CCS, IMC, NDSS, PoPETs, USENIX Security, TheWebConf and IEEE S&P, 2010–2026. Each names its own denominator; the full query log is on traffic_files.
The corpus records capture tooling in two categories. Taking only tuples marked used or produced: 509 papers name a traffic-capture tool and 206 name a proxy-interception tool, overlapping on 36, for a union of 679. Of those 679, 217 measured the web platform and 178 ran an automated web crawl.
That raw union is not the page's population. On a broad security corpus the traffic-capture category is dominated by instruments that produce no web traffic file at all — software-defined radios, Bluetooth and 802.15.4 sniffers, oscilloscopes and logic analysers, screen recorders, micro-architectural side-channel probes, load generators, and commercial VPN services that are vantage points rather than instruments. Folding the 457 distinct tool names into families and excluding those explicitly leaves 514 papers naming an on-topic instrument; 162 papers name only off-topic ones. The fold and its residue are on traffic_files.
| Family | Layer | Papers | Share of 679 | Distinct spellings |
|---|---|---|---|---|
| packet capture (libpcap family) | packet | 287 | 42.3% | 72 |
| TLS-intercepting proxy | proxy | 189 | 27.8% | 79 |
| IDS / stream analyser (Bro, Zeek) | packet | 28 | 4.1% | 10 |
| on-device mobile / IoT capture | mobile | 21 | 3.1% | 15 |
| high-rate capture (PF_RING, DPDK, netmap) | packet | 15 | 2.2% | 9 |
| flow-level export (NetFlow / IPFIX) | flow | 13 | 1.9% | 11 |
| record-and-replay / web archive | browser | 9 | 1.3% | 9 |
| browser-native HTTP log (HAR / NetLog) | browser | 8 | 1.2% | 8 |
| forward / caching proxy, self-hosted (Squid, Privoxy) | proxy | 7 | 1.0% | 6 |
The named instruments, folded across spellings and counted by paper:
| Instrument | Papers | Share of 679 |
|---|---|---|
Wireshark / tshark / dumpcap | 128 | 18.9% |
tcpdump | 119 | 17.5% |
mitmproxy / mitmdump | 98 | 14.4% |
| Bro / Zeek | 24 | 3.5% |
| Scapy | 18 | 2.7% |
| Burp Suite | 18 | 2.7% |
| Fiddler | 15 | 2.2% |
| PF_RING | 12 | 1.8% |
| HAR, as a named tool | 10 | 1.5% |
record-and-replay (WPR / pywb / Mahimahi) | 8 | 1.2% |
| Charles Proxy | 5 | 0.7% |
proxy libraries in the crawler (selenium-wire, BrowserMob) | 4 | 0.6% |
| NetLog (Chrome) | 3 | 0.4% |
| OWASP ZAP | 2 | 0.3% |
The layer flips when you restrict to the web. Of the 514 on-topic papers, 61.9% name a packet-capture tool and 37.7% a proxy. Of the 188 whose platform includes web, it is 50.5% proxy against 45.7% packet — the packet layer's dominance is an artefact of the venues, not advice about web measurement.
If you ask the extraction which papers used HAR, you get almost nothing: HAR appears as a named tool in 10 papers. So we swept the full text of all 5,855 papers with stored text for /HAR|HTTP Archive|httparchive/ and hand-classified all 95 hits. The sweep cannot be automated, because both names are homographs.
| Verdict | Papers | Share of the 95 |
|---|---|---|
citation — httparchive.org or the Web Almanac cited for a background statistic | 36 | 37.9% |
instrument — the paper writes and/or reads HAR files as its own data | 32 | 33.7% |
dataset — the paper analyses the httparchive.org crawl corpus | 14 | 14.7% |
homograph — “HAR” means something else entirely | 11 | 11.6% |
mention — HAR discussed but not used | 2 | 2.1% |
The 11 homographs are worth naming, because a regex over full text will otherwise inflate any HAR count by a tenth: Human Activity Recognition is the standard expansion in the sensing and ML literature (UCI-HAR, KU-HAR and UTAH-STM-HAR are benchmark datasets, and five papers use them), one XR-biometrics paper defines HAR as Harmonic Amplitude Ratio, and four hits are surnames and identifiers that the corpus's two-column repair split across a line break — S HAR, B HAR-GAVA, D HAR-MDASANI, IS_WORD_C HAR.
Of the 32 papers that use HAR as an instrument, only 9 (28.1%) name it in any tool field, and only 16 (50.0%) have any traffic-capture or proxy tuple at all. A structured tool query would have found at most half of them. That is a fact about how the field reports its instruments, not about the extraction: writing HAR files is treated as too ordinary to name.
Where they are, by year bucket: 2010–2013 1, 2014–2017 3, 2018–2021 12, 2022–2024 9, 2025–2026 7 (2025–2026 is provisional — CCS 2026 and IMC 2026 have not been held). By venue: IMC 9, PoPETs 8, TheWebConf 7, IEEE S&P 4, USENIX Security 3, NDSS 1. No CCS paper in the corpus uses HAR as an instrument, and that is not a small-n artefact: CCS contributes 163 crawling papers, more than IMC's 132, and IMC contributes 9 of the 32.
And it stays a minority practice inside crawling. Of the 1,120 papers that ran an automated web crawl, 156 (13.9%) name an on-topic capture instrument and 26 (2.3%) use HAR; the union is 172 (15.4%). Six papers in seven that crawl the web either never wrote a traffic file or never said so.
Of the 669 tool tuples in on-topic capture families, 85 (12.7%) state a version.
| Tool | Papers | Tuples | Tuples with a version | Share |
|---|---|---|---|---|
Wireshark / tshark | 121 | 130 | 16 | 12.3% |
tcpdump | 119 | 119 | 4 | 3.4% |
| mitmproxy | 98 | 101 | 25 | 24.8% |
mitmproxy is reported twice as often as Wireshark and seven times as often as tcpdump, which is the right way round — mitmproxy's behaviour changes between major versions in ways that matter, and researchers seem to know it.
For HAR the equivalent question is which writer produced the file, and it can only be answered as an upper bound: a keyword probe over the full text of the 32 instrument papers finds a recognisable writer in 25 (78.1%), but it counts any mention of Selenium or DevTools anywhere in the paper, so the true figure is lower. Seven of the 32 name no recognisable writer anywhere at all.
The two comparisons on this page are reproducible. fixture_traffic.mjs serves a local page containing a redirect chain, script-initiated requests, a POST body, a 200 KiB response, a request that is never answered, a WebSocket, and an image blocked by the page's own CSP. har_vs_cdp.mjs records one load of it as a HAR and as a CDP event stream simultaneously; mitm_vs_browser.mjs records one load through mitmdump while the browser writes its own HAR.
// The core of sandbox/har_vs_cdp.mjs: one page load, two recordings, one diff. // Full script and fixture: see provenance:programming:traffic_files. import fs from 'node:fs'; import { chromium } from 'playwright'; const harPath = '/tmp/one-load.har'; const browser = await chromium.launch({ executablePath: process.env.PW_EXEC, headless: true }); // content: 'omit' | 'embed' | 'attach' -- this one flag is the 11x size difference. const context = await browser.newContext({ recordHar: { path: harPath, content: 'omit' } }); const page = await context.newPage(); // A CDP session on the SAME page, so both recordings see exactly one load. const cdp = await context.newCDPSession(page); const sent = []; cdp.on('Network.requestWillBeSent', (e) => sent.push(e)); await cdp.send('Network.enable'); await page.goto('http://127.0.0.1:8098/', { waitUntil: 'load' }).catch(() => {}); await page.waitForTimeout(2500); // drain in-flight requests before closing await context.close(); // the HAR is only written on context.close() await browser.close(); const log = JSON.parse(fs.readFileSync(harPath, 'utf8')).log; console.log('HAR entries with an initiator:', log.entries.filter((e) => e._initiator).length); console.log('CDP requests with an initiator:', sent.filter((e) => e.initiator).length); console.log('CDP requests with a JS stack: ', sent.filter((e) => e.initiator?.stack).length);
Run against the fixture, that prints:
HAR entries with an initiator: 0 CDP requests with an initiator: 11 CDP requests with a JS stack: 5
Environment: Playwright 1.62.1 driving its own chromium_headless_shell build, mitmproxy 11.0.2, on Linux aarch64, 14 August 2026. Both comparisons were run three times; the per-URL outcome table was identical each time apart from entry ordering.
Every corpus figure on this page comes from scripts/report_traffic_files.mjs; every query, its denominator, the tool-name fold with its unmapped residue, the 95 hand-classified HAR verdicts with the deciding sentence for each, and the spot-checked quotes are on traffic_files. The corpus-wide caveats — what the seven venues do and do not cover, why 2025–2026 is provisional, and how stable each field is — are on Corpus.
Three limits specific to this page:
selenium-wire is on-topic is a decision, not a measurement; the family list and the 162 excluded papers are published so you can disagree with it.serverIPAddress, and why it is the proxy's when you proxy.https://w3c.github.io/web-performance/specs/HAR/Overview.html on 14 August 2026 by scripts/external_checks_traffic_files.sh.https://sec.okta.com/articles/harfiles/, “Okta October 2023 Security Incident Investigation Closure”. Despite the URL, that page carries no HAR-specific text.