How to detect internet speed in JavaScript?

How can I create a JavaScript page that will detect the user’s internet speed and show it on the page? Something like “your internet speed is ??/?? Kb/s”.


It's possible to some extent but won't be really accurate, the idea is load image with a known file size then in its onload event measure how much time passed until that event was triggered, and divide this time in the image file size.

Example can be found here: Calculate speed using javascript

Test case applying the fix suggested there:

//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "http://www.kenrockwell.com/contax/images/g2/examples/31120037-5mb.jpg"; 
var downloadSize = 4995374; //bytes

function ShowProgressMessage(msg) {
    if (console) {
        if (typeof msg == "string") {
            console.log(msg);
        } else {
            for (var i = 0; i < msg.length; i++) {
                console.log(msg[i]);
            }
        }
    }
    
    var oProgress = document.getElementById("progress");
    if (oProgress) {
        var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
        oProgress.innerHTML = actualHTML;
    }
}

function InitiateSpeedDetection() {
    ShowProgressMessage("Loading the image, please wait...");
    window.setTimeout(MeasureConnectionSpeed, 1);
};    

if (window.addEventListener) {
    window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
    window.attachEvent('onload', InitiateSpeedDetection);
}

function MeasureConnectionSpeed() {
    var startTime, endTime;
    var download = new Image();
    download.onload = function () {
        endTime = (new Date()).getTime();
        showResults();
    }
    
    download.onerror = function (err, msg) {
        ShowProgressMessage("Invalid image, or error downloading");
    }
    
    startTime = (new Date()).getTime();
    var cacheBuster = "?nnn=" + startTime;
    download.src = imageAddr + cacheBuster;
    
    function showResults() {
        var duration = (endTime - startTime) / 1000;
        var bitsLoaded = downloadSize * 8;
        var speedBps = (bitsLoaded / duration).toFixed(2);
        var speedKbps = (speedBps / 1024).toFixed(2);
        var speedMbps = (speedKbps / 1024).toFixed(2);
        ShowProgressMessage([
            "Your connection speed is:", 
            speedBps + " bps", 
            speedKbps + " kbps", 
            speedMbps + " Mbps"
        ]);
    }
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>

Quick comparison with "real" speed test service showed small difference of 0.12 Mbps when using big picture.

To ensure the integrity of the test, you can run the code with Chrome dev tool throttling enabled and then see if the result matches the limitation. (credit goes to user284130 :))

Important things to keep in mind:

  1. The image being used should be properly optimized and compressed. If it isn't, then default compression on connections by the web server might show speed bigger than it actually is. Another option is using uncompressible file format, e.g. jpg. (thanks Rauli Rajande for pointing this out and Fluxine for reminding me)

  2. The cache buster mechanism described above might not work with some CDN servers, which can be configured to ignore query string parameters, hence better setting cache control headers on the image itself. (thanks orcaman for pointing this out))

  3. The bigger the image size is, the better. Larger image will make the test more accurate, 5 mb is decent, but if you can use even a bigger one it would be better.


Well, this is 2017 so you now have Network Information API (albeit with a limited support across browsers as of now) to get some sort of estimate downlink speed information:

navigator.connection.downlink

This is effective bandwidth estimate in Mbits per sec. The browser makes this estimate from recently observed application layer throughput across recently active connections. Needless to say, the biggest advantage of this approach is that you need not download any content just for bandwidth/ speed calculation.

You can look at this and a couple of other related attributes here

Due to it's limited support and different implementations across browsers (as of Nov 2017), would strongly recommend read this in detail


I needed a quick way to determine if the user connection speed was fast enough to enable/disable some features in a site I’m working on, I made this little script that averages the time it takes to download a single (small) image a number of times, it's working pretty accurately in my tests, being able to clearly distinguish between 3G or Wi-Fi for example, maybe someone can make a more elegant version or even a jQuery plugin.

var arrTimes = [];
var i = 0; // start
var timesToTest = 5;
var tThreshold = 150; //ms
var testImage = "http://www.google.com/images/phd/px.gif"; // small image in your server
var dummyImage = new Image();
var isConnectedFast = false;

testLatency(function(avg){
  isConnectedFast = (avg <= tThreshold);
  /** output */
  document.body.appendChild(
    document.createTextNode("Time: " + (avg.toFixed(2)) + "ms - isConnectedFast? " + isConnectedFast)
  );
});

/** test and average time took to download image from server, called recursively timesToTest times */
function testLatency(cb) {
  var tStart = new Date().getTime();
  if (i<timesToTest-1) {
    dummyImage.src = testImage + '?t=' + tStart;
    dummyImage.onload = function() {
      var tEnd = new Date().getTime();
      var tTimeTook = tEnd-tStart;
      arrTimes[i] = tTimeTook;
      testLatency(cb);
      i++;
    };
  } else {
    /** calculate average of array items then callback */
    var sum = arrTimes.reduce(function(a, b) { return a + b; });
    var avg = sum / arrTimes.length;
    cb(avg);
  }
}