There are a number of tools that are used in this approach and, although not fully supported across all browsers, we can combine what's available to get the best result.
Navigation Timing API
The Navigation Timing API gives us access to metrics of page load provided by the browser, including information about what happens before the page starts loading. This is by far the best source of data available to us and, in this instance, we will be using the difference between the request start and DOM ready which will give a good indication of a combination of network latency and time taken to download the page itself.
In page timers
Android exposes information on the connection type to the browser via
navigator.connection.type. This provides us with a value that is one of 2G, 3G, WiFi, wired or unknown. Whilst this does not tell us directly about the connection speed we can use it to tell if we are on a mobile connection which is likely to be slow or bandwidth capped.
First of all we need to set a threshold for the request time above which we class it as a slow load. I collect RUM data on a number of my sites and have used this to set a value of 2.5 seconds which I feel is reasonable. You should look at similar data from your own sites to determine the value you use for the cut off time.
Once we have the threshold time we gather the information from the page using the Navigation Timing API if present. If not, we use in page timers as discussed above to estimate the equivalent data.
We start with a default of a slow load time and then compare the time we measured for the request with our threshold time. If it is less than the threshold then we class it as a fast page load.
If session storage is available then we use it to store the last known page load speed. We set a threshold for a number of page loads over which we compare the load speeds. I have set mine to four so if the first four page loads are slow then the connection is classed as slow for the remainder of the session.
Finally, if the connection type is known, an override is set forcing 2G and 3G connections to be registered as a slow speed. Whilst this may not be completely accurate, we do know that the browser is using a network that typically has limited bandwidth and increased latency. When on a wired or WiFi connection we still rely on the timing information and do not assume a fast connection as they may be using a 3G to WiFi router or using a contested or limited broadband connection such as WiFi in a café or conference venue.
We now have a value for the connection speed as either
slow so we add this as a class hook to the
<html> element and store it as an item in the profile which allows us to use this information to make decisions about which resources to load, either as part of our client side scripts or to send optimised content from the server.
By using timing information provided by the browser or calculated from in page timers we can estimate the speed of a user's connection and use that to modify the assets we request and serve. This means we do not try to send large assets (typically images) to users on slow connections thus providing them with a faster page load. When we know the connection is faster we can make use of this to send larger assets providing a richer experience where we know it will not significantly hamper the fundamental aspect of load speed.