Using Service Worker for server-side adaption based on network type

Following on from my anecdote about India and developers needing to specialize their sites for 2g networks, I wanted to send network type information through on each request so that sites could be responsive to the users network situation, but noted that it wasn't possible. Well, Ilya Grigorik pinged me and there were three points he made (see 2-4, I made up point 1.)

  1. Ilya is ahead of his time, he talked about using Service Worker to add Client Hints almost a year ago!
  2. The Network Information API is in the SW context
  3. MaxDownlink Speed looks like it might now be getting some love
  4. You can send some network information through to the server by using Service Worker

The ability for you — the web developer — to control every network request that goes through your page with Service Workers is incredibly powerful especially if you have extra client-side information available to you inside the service worker context.

Prior to Service Worker the only way that you could annotate each web request made by your page was to dynamically create the request with a unique URL describing the network type. For example, for any XMLHttpRequest you could add a custom header, or if you wanted to return a custom stylesheet you would have to dynamically insert a <link rel=stylesheet> into your page with a custom query string parameter. All of these solutions required custom JavaScript to run in the context of your page and would either block the page from rendering or it would cause a FOUC (Flash of Unstyled Content).

Now with Service Worker you can remove the in-page hacks and simply detect the type of network that the user is on for every request that is sent through from the page as follows.

self.addEventListener("fetch", function(event) {
  var requestURL = new URL(event.request.url);
  
  var dm = 0;
  var navType = "unknown";
  
  if(navigator.connection && navigator.connection.downlinkMax !== false) {
    dm = navigator.connection.downlinkMax;
  }
  
  if(navigator.connection && navigator.connection.type !== false) {
    navType = navigator.connection.type;
  }
  
  if (requestURL.origin == location.origin) {
    // append the MD header, set value to NetInfo's downlinkMax:
    // http://w3c.github.io/netinfo/#downlinkmax-attribute
    event.respondWith(
      fetch(event.request.url, {
        headers: { 
          'MD': dm,
          'Network-Type': navType
        }
      })
    );
  }
});

The above code determines if the user is on any of the following types of networks: cellular, wifi, other, none, unknown, bluetooth, ethernet, wimax; and then adds this information to a custom HTTP header called Network-Type.

This is extremely useful because today I can differentiate easily between low-latency networks (Wifi and ethernet) and high latency networks such as a mobile (cellular) network. It's a great first step but it's not everything that we would need to be truly responsive to bandwidth and latency. That requires downlinkMax.

When downlinkMax becomes available to browsers in the NetInfo API it will finally let all developers control what they send back to the client based on an estimation of the current (theoretical) maximum network speed of the user.

I have this code running live on my site right now and whilst my site doesn't need a whole lot of adaption, but I do plan on serving up highly compressed images over mobile, so that will be the first thing that I do.

I would suggest if you are building sites that are for markets (maybe India as an example) you to serve up content differently based on the network type then this method of annotating your requests can be very useful.

I lead the Chrome Developer Relations team at Google.

We want people to have the best experience possible on the web without having to install a native app or produce content in a walled garden.

Our team tries to make it easier for developers to build on the web by supporting every Chrome release, creating great content to support developers on web.dev, contributing to MDN, helping to improve browser compatibility, and some of the best developer tools like Lighthouse, Workbox, Squoosh to name just a few.

I love to learn about what you are building, and how I can help with Chrome or Web development in general, so if you want to chat with me directly, please feel free to book a consultation.

I'm trialing a newsletter, you can subscribe below (thank you!)