DEV Community

Addy Osmani
Addy Osmani

Posted on • Updated on • Originally published at addyosmani.com

Adaptive Serving using JavaScript and the Network Information API

navigator.connection.effectiveType is useful for delivering different assets based on the quality of the user's network connection.

effectiveType is a property of the Network Information API, exposed to JavaScript via the navigator.connection object. In Chrome, you can drop the following into DevTools to see your effective connection type (ECT):

console.log(navigator.connection.effectiveType); // 4G

Possible values for effectiveType are 'slow-2g', '2g', '3g', or '4g'. On slow connections this capability allows you to improve how quickly pages load by serving lower-quality versions of resources.

Before Chrome 62, we only exposed the theoretical network connection type to developers (via navigator.connection.type) rather than the network quality actually experienced by the client.

Chrome's implementation of effective connection type is now determined using a combination of recently observed round-trip times (rtt) and downlink values.

It summarizes measured network performance as the cellular connection type (e.g. 2G) most similar, even if the actual connection is WiFi. i.e. picture you're on Starbucks WiFi, but your actual effective network type is 2G or 3G.

What about responding to changes in network quality? We can use the connection.onchange event listener to monitor for connection changes:


function onConnectionChange() {
    const { rtt, downlink, effectiveType,  saveData } = navigator.connection;

    console.log(`Effective network connection type: ${effectiveType}`);
    console.log(`Downlink Speed/bandwidth estimate: ${downlink}Mb/s`);
    console.log(`Round-trip time estimate: ${rtt}ms`);
    console.log(`Data-saver mode on/requested: ${saveData}`);
}

navigator.connection.addEventListener('change', onConnectionChange)

Below is a quick test where I emulated a "Low-end mobile" profile in DevTools and was able to switch from "4g" to "2g" conditions:

effectiveType is supported in Chrome, Opera and Firefox on Android. A number of other network quality hints are available on navigator.connection, including rtt, downlink and downlinkMax.

An open-source project I've used effectiveType in was a Vue.js Google Doodles app. Using data-binding, we were able to set a connection property to either fast or slow based on ECT values. Roughly:

if (/\slow-2g|2g|3g/.test(navigator.connection.effectiveType)) {
  this.connection = "slow";
} else {
  this.connection = "fast";
}

This allowed us to conditionally render different output (a video vs. a low-res image) depending on the user's effective connection type.

   <template>
      <div id="home">
        <div v-if="connection === 'fast'">
          <!-- 1.3MB video -->
          <video class="theatre" autoplay muted playsinline control>
            <source src="/static/img/doodle-theatre.webm" type="video/webm">
            <source src="/static/img/doodle-theatre.mp4" type="video/mp4">
          </video>
        </div>
        <!-- 28KB image -->
        <div v-if="connection === 'slow'">
          <img class="theatre" src="/static/img/doodle-theatre-poster.jpg">
        </div>
      </div>
   </template>

Max Böck wrote an interesting article about network-aware components using React. He similarly highlighted how to render different components based on the network speed:

        switch(connectionType) {
            case '4g':
                return <Video src={videoSrc} />

            case '3g':
                return <Image src={imageSrc.hires} alt={alt} />

            default:
                return <Image src={imageSrc.lowres} alt={alt} />
        }

Note: You can pair effectiveType with Service Workers to adapt to when users are offline in addition to slower effective connection types.

For debugging, you can override the network quality estimate using the Chrome flag "force-effective-connection-type" which can be set from chrome://flags. DevTools Network emulation can provide a limited debugging experience for ECT too.

effectiveType values are also exposed via Client Hints allowing developers to convey Chrome's network connection speed to servers.

Further reading on this feature, see:

You can also find this post on addyosmani.com

Top comments (10)

Collapse
 
ben profile image
Ben Halpern

This is a great addition to the app shell architecture. Pre-installed shell loads different versions of the network-served app depending on connection. Really nice.

Collapse
 
ginsterbusch profile image
Fabian Wolf

Well .. that took them quite some time. I've implemented this feature in an .NET application in 2006. So, just 12 (!) years after I've done this, that feature is finally live .. :)

I wouldnt waste this on some app though - use it for proper Adaptive Images instead - or go as far as in your example, and implement Adaptive Media (Embeds) :)

cu, w0lf.

Collapse
 
sagar profile image
Sagar

Awesome article addy!!!

Collapse
 
simevidas profile image
Šime Vidas

I’m not so sure that silently replacing the video with a poster image is a good idea. What if a user shares the page on social media after watching the video, and some users who open the shared page are served the image instead? Would these users not think that the website is broken somehow as they expected to see a video?

I think a better approach would be to just prevent the video from auto-playing instead. But then, that sounds like a job for the browser, not the website (a “Don’t auto-play videos on slow connections” browser setting).

Collapse
 
rhymes profile image
rhymes

Nice, thank you!

Collapse
 
ahmadawais profile image
Ahmad Awais ⚡️

Pretty easy to use that in the latest version of Chrome. How well is it supported in other browsers and backward compact? I suppose there would be a pollyfil? 🤔

Collapse
 
addyosmani profile image
Addy Osmani

In Chrome, we leverage our Network Quality Estimator to plumb through the information that gives you a more accurate effective connection type. Although it isn't possible to entirely replicate this client-side, you could write a polyfill for estimating something like bandwidth speed. JS could download files from a server (with correct caching headers, so not in cache) and approximate download speeds that way. This can be notoriously inaccurate so it's important to consider the tradeoffs.

Collapse
 
ahmadawais profile image
Ahmad Awais ⚡️

That's what I have been thinking. Maybe that could be put in a worker but inaccuracy would be a big tradeoff — I think it's better to keep things civil and let it work for the latest versions. Otherwise, I am thinking we'll have to sideload things for mobiles — also I found out that you can't really estimate the network with smaller files coz many ISPs have dynamic fluctuations in a dynamic IP settings — the initial network push is quite strong to download up to a 1Mb file but real speeds start to reflect as we move closer to 10Mb and that's a terrible idea to be implemented. Maybe, that's me but that's where I am :)

Collapse
 
kaganasg profile image
Gary Kaganas

Thanks, Addy. What's the compat of the spec, currently? Any talk at the other shops when this will land?

Collapse
 
gradecalculator profile image
Grade Calculator

It took a long time to find a instruction on javascript with network information API. Thanks!