Use .HAR files to work with Chrome DevTools network tab programmatically

The network tab in the DevTools is really useful, but the way I've done things, I've compared the outputs of two runs by taking on notes the questions I've had & then refreshing. Or keeping two windows open, which could get confusing. And when I had new questions, I'd reload & take new notes.

This has been good enough to get me to today, but it turns out there's always been a way to extract that as JSON. You can right click any of the entries & save the JSON. And this is great. It has everything from the Network tab:

console.log("entry:", Object.keys(requests[0]))
console.log("request:", Object.keys(requests[0].request))
console.log("response: ", Object.keys(requests[0].response))

entry: [
  '_initiator',
  '_priority',
  '_resourceType',
  'cache',
  'connection',
  'pageref',
  'request',
  'response',
  'serverIPAddress',
  'startedDateTime',
  'time',
  'timings'
]
request: [
  'method',
  'url',
  'httpVersion',
  'headers',
  'queryString',
  'cookies',
  'headersSize',
  'bodySize'
]
response:  [
  'status',      'statusText',
  'httpVersion', 'headers',
  'cookies',     'content',
  'redirectURL', 'headersSize',
  'bodySize',    '_transferSize',
  '_error'
]

I used it to write a little script that I'm going to use when I play performance golf on the worththetime.info

const fs = require('fs')

const file = JSON.parse(fs.readFileSync('result.har'))

const extractTiming = (timingData) => {
  return Object.values(timingData).map(e => Number(e)).filter(e => e > 0).reduce((e, f) => e+f)
}

const requests = file.log.entries
const timings = requests.map(r => r.timings)
let total = 0;

const totalTime = timings
  .map(t => extractTiming(t))
  .reduce((t, acc) => t+acc)

---

num requests is:  7
total time 631.9129998691976

But you could also use it to do things like assert there are no 302s:

const statuses = requests.map(r => r.response.status)
const no302s = statuses.every(s => s !== 302)

console.log('statuses: ', statuses)
console.log('no redirects?', no302s)

---

statuses:  [
  200, 302, 200,
  200, 302, 200,
  200
]
no redirects? false

You can do whatever you want!

Many tabs let you save their data as JSON...

... but none are quite as comprensible

If you save the profiler the output is a few thousand lines of this:

{"args":{"name":"Browser"},"cat":"__metadata","name":"process_name","ph":"M","pid":10802,"tid":0,"ts":0},
{"args":{"name":"Renderer"},"cat":"__metadata","name":"process_name","ph":"M","pid":96133,"tid":0,"ts":0},
{"args":{},"cat":"disabled-by-default-devtools.timeline","dur":13,"name":"RunTask","ph":"X","pid":96133,"tdur":11,"tid":13571,"ts":383268870474,"tts":756385},

The Memory profiler also has this, though it looks even more tied to the layout of that tab. I guess it's possible that it can be consumed by a conventional memory profiler. ... but over all none of the

Programmatically getting the HAR file

You could go a step further and use that to fetch the .HAR files. Puppeteer is a tool for letting you work with chrome headlessly. I would have thought that the ability to get .HAR files would be built in, but according to this ticket it's not.

There's still a few options:

  1. https://github.com/Everettss/puppeteer-har
  2. https://www.npmjs.com/package/chrome-har
  3. that github thread does have some code snippets

I haven't needed to do this yet, so I haven't looked into them. For me, right now it's not "worth the time"

A note about Lighthouse

Lighthouse must be using some of these same data sources in it's reports. I'd bet it uses Puppeteer directly to fetch the, but even if not, I'm certain that it has another way to access the same data (via the protocol) & it reshapes things into more human developer.

In conclusion

I'm glad I found this, and hope you found it useful. Good day!