I'm using the JavaScript Performance API and I'm trying to figure out the right combination of metrics to log my page load time on the console, whenever any individual page is requested and loads.
TLDR: I want to use JavaScript's Performance API to get a number close to the number reported by load on the Network tab of Firefox Developer Tools (or any browser developer tools).
See the number on the right hand side in the image immediately below:
I wouldn't have an issue but for the fact that no combination that I've yet tried comes consistently close to the number reported by load on the Network tab of Firefox Developer Tools - sometimes the final number I get is up to several hundredths of a second under, sometimes the same amount over.
It may be that I'm already achieving numbers as close as I can get, but I want to be sure that I am and not accidentally referring to inappropriate metrics.
Here are the metrics I'm using (from the PerformanceNavigationTiming interface of the Performance API):
domainLookupEndconnectEnd- I was using this before, but not currentlyresponseEndloadEventStart
And here's what I have at present:
window.addEventListener('load', () => {
let domainLookupEnd = performance.getEntriesByType('navigation')[0].domainLookupEnd;
let connectEnd = performance.getEntriesByType('navigation')[0].connectEnd;
let responseEnd = performance.getEntriesByType('navigation')[0].responseEnd;
let loadEventStart = performance.getEntriesByType('navigation')[0].loadEventStart;
console.log(`
domainLookupEnd: ${domainLookupEnd}
connectEnd: ${connectEnd}
responseEnd: ${responseEnd}
loadEventStart: ${loadEventStart}
Page loaded in: (${responseEnd} - ${domainLookupEnd})
Page built in: (${loadEventStart} - ${responseEnd})
Page loaded and built in: (${loadEventStart} - ${domainLookupEnd})
// ^^^ All this is just temporary helper info to ensure that the three lines below are correct
Page loaded in: ${((responseEnd - domainLookupEnd) / 1000)} seconds.
Page built in: ${((loadEventStart - responseEnd) / 1000)} seconds.
Page loaded and built in: ${((loadEventStart - domainLookupEnd) / 1000)} seconds.
`);
});
Fairly consistently I find that the metrics reported in the javascript console are between one thousandth (0.001) and (as much as) four hundredths (0.04) of a second less than the load time reported by the Network tab.
Is this the best I can hope for, or am I doing something wrong / choosing the wrong metrics?

Your times are likely faster because you are measuring less
Let's start with MDN's very excellent illustration from Measuring performance:
The earliest segment moment you include is
domainLookupEnd, which means only the stuff after the green DNS lookup in the graph.MDN and Mozilla include more
All of the MDN and Mozilla docs below consider
navigationStartthe beginning of the page load time measurement, and go at least toloadEventStart, if not toloadEventEnd.MDN's Page load time doc says:
The MDN's Navigation Timing API doc has a slightly different calculation of page load time:
Mozilla's Improving Firefox Page Load (2020) blog post:
Mozilla's Comparing Browser Page Load Time: An Introduction to Methodology (2017) seems to go with
loadEventEnd:Your may also be measuring cache hits instead of fresh web requests
Firefox Developer Tools shows both separately, so you should make sure you are using the set of numbers that matches how your code's requests are handled.
How to include the
onLoadsegment in your measurementIf Firefox is including the entire
onLoadsegment in its measurement, it's including the execution time of allonLoadorloadevent scripts. This currently includes the execution time of your own measurement script!That might explain why sometimes it differs by so little ("one thousandth") and sometimes by more ("four hundredths"): on pages where your measurement script is the only
onLoadscript, it differs by just the time it takes to execute that script, and on pages that have more scripts it takes more time and the difference in measurement is larger.There is no standard event to trigger execution after all
onLoadscripts are done. So instead you'll have to schedule it later from withinonLoad:other useful resources
Measuring Web Performance in 2022: The Definitive Guide