284

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”.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Sharon Haim Pour
  • 6,595
  • 12
  • 42
  • 64
  • 1
    @Jakub, @Ankit: People may use Flash for it, but you don't *need* to. No reason whatsoever you can't do it with JavaScript. – T.J. Crowder Apr 03 '11 at 13:31

12 Answers12

362

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 = "https://upload.wikimedia.org/wikipedia/commons/3/3a/Bloemen_van_adderwortel_%28Persicaria_bistorta%2C_synoniem%2C_Polygonum_bistorta%29_06-06-2021._%28d.j.b%29.jpg"; 
var downloadSize = 7300000; //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" style="font-family:sans-serif">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.

  4. Consider to first get a read on the device screen size and select accordingly an image size. Small screens normally equates to slower connection, so a smaller image should be sufficient to obtain a good read.

  5. And lastly, keep in mind that other things may be downloading in parallel. So if you need an accurate read run it after all downloads have finished.

MeSo2
  • 450
  • 1
  • 7
  • 18
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • the .12 mbps was the js execution time, if you run a execution time function then minus that from the big picture... you should get a fairly similar solution. –  Mar 05 '14 at 22:18
  • 10
    Take care that the test image is properly optimized and compressed. If it isn't, then default compression on connections by webserver might show speed bigger than it really is. – Rauli Rajande Sep 25 '14 at 09:50
  • 4
    I found a little trick to ensure your image is suitable for the test: run the code with Chrome dev tool throttling enabled, and see if the result matches the limitation. Hope this could help someone. – user284130 Dec 03 '14 at 08:40
  • 3
    joining Rauli Rajande : better use a file which is uncompressible (or nearly), or webserver compression modules may reduce it significantly, invalidating the measure. A jpeg image would be a good choice. – Fluxine Feb 06 '15 at 14:22
  • @Fluxine good call, missed that before. Will add something to the answer when having some time, please remind me again if I forget in couple of days. :) – Shadow The GPT Wizard Feb 06 '15 at 18:39
  • 1
    For those that have successfully used this Javascript code, did you initially encounter no calls going to "download.onload"? This is exactly what I am experiencing and I am still trying to find out why. –  Jul 20 '15 at 14:44
  • @John what browser? Are you sure you use the complete code? The cache buster part is crucial, if the image is retrieved from cache, some browsers (e.g. IE) won't execute the `onload()` for it. – Shadow The GPT Wizard Jul 20 '15 at 14:57
  • 3
    @Dilip smaller image means less accurate test, it's big on purpose. :) – Shadow The GPT Wizard Sep 01 '15 at 13:17
  • You can improve the test accuracy and reduce the file size of the testing image by checking latency for really small file first (like 35 bytes 1x1px gif file) and then using this data for the next speed test with a bigger file. My test shows that you can double accuracy on smaller files (less than 1MB)! – 350D Nov 20 '15 at 15:39
  • @ShadowWizard [here is](http://imgur.com/V8ICj1t) the test page chart and you can check for "waiting time" in yellow - its the same for both images. – 350D Nov 20 '15 at 20:44
  • Has anyone thought of using the timing API for this? http://www.w3.org/TR/navigation-timing It seems that one would be able to calculate the speed by looking at the request data that we get with the API? – Daniel Dimitrov Dec 14 '15 at 08:30
  • :( This solution only works when the Chrome Developer tools are open. Otherwise, nothing is written in id="progress". I placed the code in my first controller in an Angular.js project – Ian Steffy Mar 02 '16 at 08:45
  • 1
    @IanSteffy taking a look on my old code, it's not meant to work under any library (jQuery, AngularJS, etc) since it's overriding the global load event, which can cause all kinds of weird problems when library is being used, which usually also using the load event. I will improve the code soon and hopefully it will solve the problem you describe. – Shadow The GPT Wizard Mar 02 '16 at 08:50
  • @orcaman what do you mean the 'cache control headers for the image' should be set? Set to what? Setting the cache control goes something like this, right? content can equal PUBLIC | PRIVATE | NO-CACHE | NO-STORE – Ian Steffy Mar 02 '16 at 08:50
  • 1
    @IanSteffy it's relevant only if the image is in a CDN server, a good tutorial is available [here](https://www.maxcdn.com/one/tutorial/using-cache-control-headers/). – Shadow The GPT Wizard Mar 02 '16 at 08:52
  • 1
    @ShadowWizard Considering this was originally answered in 2011, I am bedazzled that you updated your code so quickly after I commented. You are a stack overflow hero. I will test it soon – Ian Steffy Mar 02 '16 at 09:37
  • @ShadowWizard This code now works every time I reload the page, however the 'Loading the image...' message no longer appears. No matter though because the connection speed is being measured! :D – Ian Steffy Mar 02 '16 at 09:46
  • The results obtained with javascript solution and results from Ookla speed test, have so much difference, what could be the reason? – pramod kumar Aug 18 '16 at 06:57
  • @pramodkumar that's a good question. I believe the main reason is that they use server side technology to locate the best server around the world, based on the user location. The image I'm using as example appears to be [hosted in New York](https://who.is/whois/kenrockwell.com), so this means those who use ISP located there will have the best results. If you can find an image with ~5mb size hosted on a server near you try changing the source and see if you get better results which match the Ookla speed test. I'm pretty sure you will. :) – Shadow The GPT Wizard Aug 18 '16 at 10:29
  • 1
    @pramodkumar I just tried changing the image url to `http://i.imgur.com/pfudboE.jpg` and size to `4281953` and it indeed gave me much better results. I will edit the answer to reflect this soon, thanks for the heads up! :) – Shadow The GPT Wizard Aug 18 '16 at 10:38
  • I'm thinking to do a continuous speed test for my application, and i have nodeJS, socketIO under my technical stack. It is a good idea to use sockets to calculate the speed test , or go with XMLhttprequests? – pramod kumar Aug 18 '16 at 10:47
  • @pramodkumar not sure, never really looked into it from a server side point of view. I think I've seen that Ookla are using sockets, so probably better explore this path first. – Shadow The GPT Wizard Aug 18 '16 at 10:49
  • yeah Ookla guys are using sockets, but since i'm doing a continuous speed check, is it going to freeze my browser, or will there be any impact on my application performance. – pramod kumar Aug 18 '16 at 10:56
  • I was not expecting this solution will be so simple, hats off to you for this. BUt i just want to know if this code can be used in realtime applications, like if i add a subdomain to any of my websites and load this code there, will this work fine for all kind of users? considering the location of server and speed of server issues... Also please guide me if this is a proper way to do this, if not what route should i take. Once again, i should say this is a greatcode with all those updates.. – Zia Ul Rehman Mughal Sep 10 '16 at 16:08
  • @Zia thanks, but as previous comments indicate, this isn't 100% reliable way, I'm afraid, and does depend on user location. I still have to edit the answer to reflect this, but bottom line don't use this for realtime use for now. Sorry! – Shadow The GPT Wizard Sep 10 '16 at 16:53
  • can you suggest anything? for the real time use... any help will be great. thankyou. – Zia Ul Rehman Mughal Sep 10 '16 at 17:09
  • Ok, i think only issue in this approach is location of server form where we are downloading file, i think if we come up with something being downloaded from some google server or microsoft server, that will be helpful, or we can add multiple files from different location servers and calculate the average maybe. – Zia Ul Rehman Mughal Sep 11 '16 at 04:47
  • 1
    @Zia good point, my main problem was to find images with file size large enough to give proper results, with small file size the results will surely be badly skewed. I'll try to see how feasible are those suggestions, thanks! – Shadow The GPT Wizard Sep 11 '16 at 09:18
  • The above code should be more accurate the slower the internet speed right ? – Иво Недев Nov 17 '16 at 16:05
  • @ИвоНедев in theory yes, though I wasn't able to really test this. – Shadow The GPT Wizard Nov 17 '16 at 16:08
  • 1
    @ShadowWizard Well there's always chrome throttling but even that is quite fast. I'm looking to log extreme cases for my users, bordering offline. I'll get back to you when I implement it and have some more detail, thanks. – Иво Недев Nov 17 '16 at 16:09
  • 1
    I tested this code, got 5.45 Mbps via the file download test and 75 Mbps via speedtest.net. Is the difference due to the testing server location? I'm guessing because I am in Thailand and the file is hosted in the US it results in a big difference... – Andrew Schultz Jul 28 '18 at 06:46
  • 2
    @AndrewSchultz yes probably the case. Speed test sites are usually big enough to have several servers around the world, and use the nearest server to the user. Also, might be an upload limit of the server hosting the file you used with my code. – Shadow The GPT Wizard Jul 28 '18 at 13:03
  • fwiw my download speed was listed at 80Mbps on the actual speed test, and 35Mbps for this JS solution – Anthony Aug 28 '20 at 20:23
  • @Anthony well, for such speeds you need bigger image to test with, I'd say even 50 mb image, but hard to find such a thing. – Shadow The GPT Wizard Aug 28 '20 at 23:37
  • The most problem of tour solution is that detected speed is strongly related of file size, so: - if i load 1 500 bytes i get ~0.01 Mbps - if i load 50 000 bytes i get ~3.0 Mbps - if i load 500 000 bytes i get ~6.0 Mbps - ...etc. So, the solution is not accurate :( – user989840 Apr 14 '21 at 10:02
  • Hi, shadow, thanks for the great idea of using image `onload`, just one question, won't by using `?` in url make the result become inaccurate? In this answer, https://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url, it states that `Bypasses caching altogether, meaning unnecessary delays and bandwidth use whenever the image doesn't change between views.` Is this true also for this situation? Please correct me if i my wrong and thank you! – James Feb 17 '22 at 18:14
  • @James that's an interesting point, admit I never thought about it. My idea was to prevent cache from being triggered, which will give false results. Back when writing this answer adding a unique querystring was the only way I knew to do that, and to be honest, I didn't really check other ways since then, in client side at least. Ideally, you would serve the image from a server you control, so you can define no cache yourself, but that doesn't fit in general answer that addresses people who don't have such a server at their disposal. :) – Shadow The GPT Wizard Feb 17 '22 at 18:26
  • @ShadowWizardHatesOmicron, just today, I am trying to develop a internet applications like what you did, Iuse the way you did, but it seems that by using `?` will lag about 10 times than usual. (test with `?`: 2.1 mb ,without `?` 22mb). Not saying your answer is not good, just curious do you know any advanced way, since ten years past... – James Feb 17 '22 at 18:36
  • @James I don't fully understand how this can be (2.1 vs. 22 mb) and sadly my skills and focus changed in the past years, to node.js and C#, less client side and "plain" web development, so I'm pretty much behind on this. :/ – Shadow The GPT Wizard Feb 18 '22 at 06:50
  • @ShadowWizardHatesOmicron, that is sad, anyways thanks. Last question, I think your code could be much shorten now since ten years past and I think almost everybody's broswer support window.onload and a better practice is to use performance.now() rather than date.now since it is always better to use it when you will deal with precise number. What do you think so? – James Feb 24 '22 at 16:49
  • @James might be, but the difference is so tiny I don't think it's worth the effort of rewriting the code, re-testing, etc. – Shadow The GPT Wizard Feb 25 '22 at 13:54
  • soo much practical and effective hats off man ! – Amir Rahman Jun 13 '22 at 13:44
128

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

Punit S
  • 3,079
  • 1
  • 21
  • 26
32

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.

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);
  }
}
dmm79
  • 462
  • 6
  • 10
26

As I outline in this other answer here on StackOverflow, you can do this by timing the download of files of various sizes (start small, ramp up if the connection seems to allow it), ensuring through cache headers and such that the file is really being read from the remote server and not being retrieved from cache. This doesn't necessarily require that you have a server of your own (the files could be coming from S3 or similar), but you will need somewhere to get the files from in order to test connection speed.

That said, point-in-time bandwidth tests are notoriously unreliable, being as they are impacted by other items being downloaded in other windows, the speed of your server, links en route, etc., etc. But you can get a rough idea using this sort of technique.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    @Jakub: You'd have to have a place to upload to, but there's no reason you can't use the same technique for that. You could use data you generate on-the-fly or, of course, you could re-use some of the data you downloaded for the download test. – T.J. Crowder Apr 03 '11 at 13:30
  • So how would you know when did the upload complete? – Jakub Hampl Apr 03 '11 at 13:32
  • 2
    @Jakub: Any of several ways. If you do a form submission to a hidden `iframe`, for instance, you poll the `iframe` or a cookie for completion. If you use an `XMLHttpRequest` object to do the post, there's a callback for completion. – T.J. Crowder Apr 03 '11 at 13:38
16

Even though this is old and answered, i´d like to share the solution i made out of it 2020 base on Shadow Wizard Says No More War´s solution

I just merged it into an object that comes with the flexibility to run at anytime and run a callbacks if the specified mbps is higher or lower the measurement result.

you can start the test anywhere after you included the testConnectionSpeed Object by running the

/**
* @param float    mbps               - Specify a limit of mbps.
* @param function more(float result) - Called if more mbps than specified limit.
* @param function less(float result) - Called if less mbps than specified limit.
*/
testConnectionSpeed.run(mbps, more, less)

for example:

var testConnectionSpeed = {
  imageAddr : "https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg", // this is just an example, you rather want an image hosted on your server
  downloadSize : 2707459, // Must match the file above (from your server ideally)
  run:function(mbps_max,cb_gt,cb_lt){
    testConnectionSpeed.mbps_max = parseFloat(mbps_max) ? parseFloat(mbps_max) : 0;
    testConnectionSpeed.cb_gt = cb_gt;
    testConnectionSpeed.cb_lt = cb_lt;
    testConnectionSpeed.InitiateSpeedDetection();
  },
  InitiateSpeedDetection: function() {
    window.setTimeout(testConnectionSpeed.MeasureConnectionSpeed, 1);
  },
  result:function(){
    var duration = (endTime - startTime) / 1000;
    var bitsLoaded = testConnectionSpeed.downloadSize * 8;
    var speedBps = (bitsLoaded / duration).toFixed(2);
    var speedKbps = (speedBps / 1024).toFixed(2);
    var speedMbps = (speedKbps / 1024).toFixed(2);
    if(speedMbps >= (testConnectionSpeed.max_mbps ? testConnectionSpeed.max_mbps : 1) ){
      testConnectionSpeed.cb_gt ? testConnectionSpeed.cb_gt(speedMbps) : false;
    }else {
      testConnectionSpeed.cb_lt ? testConnectionSpeed.cb_lt(speedMbps) : false;
    }
  },
  MeasureConnectionSpeed:function() {
    var download = new Image();
    download.onload = function () {
        endTime = (new Date()).getTime();
        testConnectionSpeed.result();
    }
    startTime = (new Date()).getTime();
    var cacheBuster = "?nnn=" + startTime;
    download.src = testConnectionSpeed.imageAddr + cacheBuster;
  }
}




// start test immediatly, you could also call this on any event or whenever you want
testConnectionSpeed.run(1.5, function(mbps){console.log(">= 1.5Mbps ("+mbps+"Mbps)")}, function(mbps){console.log("< 1.5Mbps("+mbps+"Mbps)")} )

I used this successfuly to load lowres media for slow internet connections. You have to play around a bit because on the one hand, the larger the image, the more reasonable the test, on the other hand the test will take way much longer for slow connection and in my case I especially did not want slow connection users to load lots of MBs.

john Smith
  • 17,409
  • 11
  • 76
  • 117
13

The image trick is cool but in my tests it was loading before some ajax calls I wanted to be complete.

The proper solution in 2017 is to use a worker (http://caniuse.com/#feat=webworkers).

The worker will look like:

/**
 * This function performs a synchronous request
 * and returns an object contain informations about the download
 * time and size
 */
function measure(filename) {
  var xhr = new XMLHttpRequest();
  var measure = {};
  xhr.open("GET", filename + '?' + (new Date()).getTime(), false);
  measure.start = (new Date()).getTime();
  xhr.send(null);
  measure.end = (new Date()).getTime();
  measure.len = parseInt(xhr.getResponseHeader('Content-Length') || 0);
  measure.delta = measure.end - measure.start;
  return measure;
}

/**
 * Requires that we pass a base url to the worker
 * The worker will measure the download time needed to get
 * a ~0KB and a 100KB.
 * It will return a string that serializes this informations as
 * pipe separated values
 */
onmessage = function(e) {
  measure0 = measure(e.data.base_url + '/test/0.bz2');
  measure100 = measure(e.data.base_url + '/test/100K.bz2');
  postMessage(
    measure0.delta + '|' +
    measure0.len + '|' +
    measure100.delta + '|' +
    measure100.len
  );
};

The js file that will invoke the Worker:

var base_url = PORTAL_URL + '/++plone++experimental.bwtools';
if (typeof(Worker) === 'undefined') {
  return; // unsupported
}
w = new Worker(base_url + "/scripts/worker.js");
w.postMessage({
  base_url: base_url
});
w.onmessage = function(event) {
  if (event.data) {
    set_cookie(event.data);
  }
};

Code taken from a Plone package I wrote:

alepisa
  • 1,324
  • 8
  • 14
9

It's better to use images for testing the speed. But if you have to deal with zip files, the below code works.

var fileURL = "your/url/here/testfile.zip";

var request = new XMLHttpRequest();
var avoidCache = "?avoidcache=" + (new Date()).getTime();;
request.open('GET', fileURL + avoidCache, true);
request.responseType = "application/zip";
var startTime = (new Date()).getTime();
var endTime = startTime;
request.onreadystatechange = function () {
    if (request.readyState == 2)
    {
        //ready state 2 is when the request is sent
        startTime = (new Date().getTime());
    }
    if (request.readyState == 4)
    {
        endTime = (new Date()).getTime();
        var downloadSize = request.responseText.length;
        var time = (endTime - startTime) / 1000;
        var sizeInBits = downloadSize * 8;
        var speed = ((sizeInBits / time) / (1024 * 1024)).toFixed(2);
        console.log(downloadSize, time, speed);
    }
}

request.send();

This will not work very well with files < 10MB. You will have to run aggregated results on multiple download attempts.

Akshar
  • 927
  • 9
  • 7
  • 3
    I really like the simplicity of the answer and I have adapted it for my purpose: I swapped to _window.performance.now_ for the timestamps, _request.responseType = "blob"_ (MIME types are not valid), _request.response.size_ for the download size, and _1000000_ for the speed calculation (because Mbps should be in SI units). – Rupert Rawnsley Sep 06 '17 at 09:58
6

thanks to Punit S answer, for detecting dynamic connection speed change, you can use the following code :

navigator.connection.onchange = function () {
 //do what you need to do ,on speed change event
 console.log('Connection Speed Changed');
}
Mehdi Maghrouni
  • 1,529
  • 22
  • 23
5

Improving upon John Smith's answer, a nice and clean solution which returns a Promise and thus can be used with async/await. Returns a value in Mbps.

const imageAddr = 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg';
const downloadSize = 2707459; // this must match with the image above

let startTime, endTime;
async function measureConnectionSpeed() {
  startTime = (new Date()).getTime();
  const cacheBuster = '?nnn=' + startTime;

  const download = new Image();
  download.src = imageAddr + cacheBuster;
  // this returns when the image is finished downloading
  await download.decode();
  endTime = (new Date()).getTime();
  const duration = (endTime - startTime) / 1000;
  const bitsLoaded = downloadSize * 8;
  const speedBps = (bitsLoaded / duration).toFixed(2);
  const speedKbps = (speedBps / 1024).toFixed(2);
  const speedMbps = (speedKbps / 1024).toFixed(2);
  return Math.round(Number(speedMbps));
}
Sean
  • 2,412
  • 3
  • 25
  • 31
Anthony
  • 13,434
  • 14
  • 60
  • 80
4

I needed something similar, so I wrote https://github.com/beradrian/jsbandwidth. This is a rewrite of https://code.google.com/p/jsbandwidth/.

The idea is to make two calls through Ajax, one to download and the other to upload through POST.

It should work with both jQuery.ajax or Angular $http.

Adrian Ber
  • 20,474
  • 12
  • 67
  • 117
1

//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "https://i.ibb.co/sPbbkkZ/pexels-lisa-1540258.jpg"; 
var downloadSize = 10500000; //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>
Deepak Kumar Padhy
  • 4,128
  • 6
  • 43
  • 79
-2

Mini snippet:

var speedtest = {};
function speedTest_start(name) { speedtest[name]= +new Date(); }
function speedTest_stop(name) { return +new Date() - speedtest[name] + (delete 
speedtest[name]?0:0); }

use like:

speedTest_start("test1");

// ... some code

speedTest_stop("test1");
// returns the time duration in ms

Also more tests possible:

speedTest_start("whole");

// ... some code

speedTest_start("part");

// ... some code

speedTest_stop("part");
// returns the time duration in ms of "part"

// ... some code

speedTest_stop("whole");
// returns the time duration in ms of "whole"
Batman
  • 91
  • 1
  • 6