"Is my 144 Hz monitor actually running at 144?" is a question people search for every day, and the browser can answer it reasonably well. requestAnimationFrame fires once per frame the browser presents, with a high-resolution timestamp. The gap between two callbacks is the frame time, and 1000 / frameTime is the refresh rate.
That's the whole idea. Making it give a trustworthy number took a few more decisions, which I made while building the refresh rate test on A2Z Tools.
The basic loop
const WINDOW = 120 ; // frames the rate is measured over const AWAY_MS = 500 ; // a gap this long is the tab being away, not a frame let intervals = [], last = 0 ;
function frame ( now ) { requestAnimationFrame ( frame ); if ( last ) { const dt = now - last ; if ( dt > 0 && dt < AWAY_MS ) { intervals . push ( dt ); if ( intervals . length > WINDOW ) intervals .…