loading...

Adaptive Serving using JavaScript and the Network Information API

addyosmani profile image Addy Osmani Updated on ・3 min read

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

Posted on by:

addyosmani profile

Addy Osmani

@addyosmani

My name is Addy and I’m an engineering manager on the Chrome team. Let's make the web fast <3

Discussion

pic
Editor guide
 

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.

 

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.

 

Nice!!. Working fine for connection lost/gain & network emulation too. But for offline it shows below

  • Effective network connection type: 4g
  • Downlink Speed/bandwidth estimate: 0Mb/s
  • Round-trip time estimate: 0ms
  • Data-saver mode on/requested: false

Is this expected behaviour or a bug ???

 

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

 

Nice, thank you!

 

Awesome article addy!!!

 

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? 🤔

 

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.

 

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 :)

 
 

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