How to determine the screen refresh rate in Hz of the monitor with JavaScript in the browser

How to determine the screen refresh rate in Hz of the monitor with JavaScript in the browser

In the last days, for one of those stupid purchases I usually make, I bought a Benq Zowie 27" XL2740 with a refresh rate of 240Hz. This kind of monitor is specially made for gaming as the refresh rate is pretty high compared to a regular monitor whose refresh rate is usually 60Hz. Personally, the color depth is awful, but the smoothness is incredible so it wasn't a very stupid purchase after all.

Then the idea of how to determine this value from the monitors with some programming language came to my mind. I started with JavaScript and in this article, I'm going to share with you what I discovered about this topic and how to get the refresh rate of the monitor with JavaScript in the browser.

Important note

All the methods based on the requestAnimationFrame that you will find on the internet will help you to determine the Hz of the primary monitor in your system (if you have more than a single monitor, you will be able to obtain only the one that is defined as primary in your system), for example, consider my setup that has 3 monitors in the following order:

  1. Samsung U28E590 4K (1920x1080@60Hz)
  2. Benq Zowie 27" XL2740 (1920x1080@240Hz) - Defined as primary display
  3. Samsung C24F390 (1920x1080@60Hz)

Arrange displays Windows 10

This means that if I try to obtain the Hz value with JavaScript I will be able to do it only in the primary display, it doesn't matter if you move the chrome window to another monitor, it will always obtain the speed of the primary display (in my case the 240hz monitor).

Obtaining the screen refresh rate

The first proposal to obtain the screen refresh rate is to calculate it through the times obtained in the requestAnimationFrame method of the browser. This method tells the browser that you would like to perform an animation and therefore request the browser to call a specified function to update an animation before the next repaint, expecting a single callback to be executed before the repaint.

The callback provided as the first argument of the requestAnimationFrame method will receive as the first argument a DOMHighResTimeStamp (a double value used to store a time value in milliseconds) similar to the one returned by performance.now(), indicating the point in time when requestAnimationFrame starts to execute callback functions. The following method getScreenRefreshRate will help you to obtain the estimated Hz of your primary display:

/**
 * Allows to obtain the estimated Hz of the primary monitor in the system.
 * 
 * @param {Function} callback The function triggered after obtaining the estimated Hz of the monitor.
 * @param {Boolean} runIndefinitely If set to true, the callback will be triggered indefinitely (for live counter).
 */
function getScreenRefreshRate(callback, runIndefinitely){
    let requestId = null;
    let callbackTriggered = false;
    runIndefinitely = runIndefinitely || false;

    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
    }
    
    let DOMHighResTimeStampCollection = [];

    let triggerAnimation = function(DOMHighResTimeStamp){
        DOMHighResTimeStampCollection.unshift(DOMHighResTimeStamp);
        
        if (DOMHighResTimeStampCollection.length > 10) {
            let t0 = DOMHighResTimeStampCollection.pop();
            let fps = Math.floor(1000 * 10 / (DOMHighResTimeStamp - t0));

            if(!callbackTriggered){
                callback.call(undefined, fps, DOMHighResTimeStampCollection);
            }

            if(runIndefinitely){
                callbackTriggered = false;
            }else{
                callbackTriggered = true;
            }
        }
    
        requestId = window.requestAnimationFrame(triggerAnimation);
    };
    
    window.requestAnimationFrame(triggerAnimation);

    // Stop after half second if it shouldn't run indefinitely
    if(!runIndefinitely){
        window.setTimeout(function(){
            window.cancelAnimationFrame(requestId);
            requestId = null;
        }, 500);
    }
}

It has 2 possible ways to use, the first one is to obtain the value just once with the method that is by itself asynchronous:

// After 500ms, will output the estimated Hz of the monitor (frames per second - FPS)
// 239 FPS (in my case)
getScreenRefreshRate(function(FPS){
    console.log(`${FPS} FPS`);
});

Alternatively, if you are going to create a live counter, running the callback indefinitely can be possible by providing the second argument of the function as true:

// Warning: the method will be executed forever, ideal for live counters
getScreenRefreshRate(function(FPS){
    console.log(`${FPS} FPS`);
}, true);
// Will output forever something like: 
// 240 FPS
// 239 FPS
// 240 FPS
// 239 FPS
// 240 FPS
// 239 FPS
// 240 FPS

Happy coding ❤️!

This could interest you

Become a more social person