Optimize Images According to Network and Device Constraints in React

❥ Sponsor

Connectivity has evolved beyond recognition since the beginning of the internet. We are lightyears past dial up, these days, and can watch a video in high resolution on our smartphone while being connected to a mobile network. But not all mobile connections are created equal – older generation networks (3G, 2G, etc.) are still quite dominant, accounting for almost half of all connections worldwide in 2020.

Unfortunately, the phasing out process is very slow, and many people around the globe are experiencing really dragged out page loads, comparable to the very early days of home internet adoption.

Modern websites became resource-hungry, featuring lots of images and animations. For a visitor on an underpowered device and a fragile network connection, an average webpage might take a good minute to load completely. This is largely due to the fact that developers often make binary decisions when it comes to user’s hardware and network conditions: devices fall either in the desktop or smartphone category, while connectivity is a question of being on- or offline. In reality, user’s circumstances tend to be much more nuanced.

We Can Do Better?

What can be done to bridge the gap for users on modest devices and spotty connections? First, we need to do a quick evaluation of what exactly their conditions are by looking at the following two properties:

Based on that, we can decide, for instance, to adjust the quality of the images we intend to serve. There is a catch, however, with Jamstack websites and apps rendered on the server – `navigator`object, as any other browser API, isn’t available during the rendering stage. A common workaround for this issue is to add a bunch of responsive image markup, but it comes with a significant pain point – inefficient scaling. An image CDN like ImageEngine helps to avoid this and other pitfalls associated with responsive images as it handles all the heavy-lifting behind the scenes by applying automated, smart tweaks to requested resources on-the-fly.

When it comes to adapting to a user’s network constraints, one could detect connection type and instruct an image CDN to vary compression according to connection quality. Here’s how one might go about it in React:

import React, { useState, useEffect } from 'react'

const useConnectionType = (defaultConnectionType) => {

  const isSupported = navigator?.connection?.effectiveType
    ? true
    : false

  const [connectionType, setNetworkStatus] = useState(
    isSupported
      ? navigator.connection.effectiveType
      : defaultConnectionType
  )

  useEffect(() => {
    if (isSupported) {
      const { connection } = navigator
      const updateConnectionType = () => {
        setNetworkStatus(connection.effectiveType)
      }

      connection.addEventListener('change', updateConnectionType)

      return () => {
        connection.removeEventListener('change', updateConnectionType)
      }
    }
  }, [])

  return [ connectionType, setNetworkStatus ]
}

const imageCDNHost = 'images.foo.com

function ConnectionAwareComponent () {

  const [ connectionType ] = useConnectionType()

  let compressionLevel = 0

  switch (connectionType) {
    case 'slow-2g':
      compressionLevel = 65
      break
    case '2g':
      compressionLevel = 50
      break
    case '3g':
      compressionLevel = 30
      break
    case '4g':
      compressionLevel = 0
      break
  }

  return (
    <div>
      {/* Apply variable compression via dedicated directive */}
      <img src={`${imageCDNHost}/?imgeng?=cmpr_${compressionLevel}`} />
    </div>
  )
}

One can take this idea even further to accommodate those on really sluggish and wonky networks by rendering blurred images and offering an option to download a higher resolution version on demand. Or devise a performance score system and adjust what is sent based on that. 

On the other hand, the fact that the user is on a “speedy” 4G connection doesn’t necessarily mean they aren’t interested in saving data as they might be accessing a website in roaming. Enabling Client Hints on one’s website will let site owners detect the presence of a data saver flag and take necessary steps to adjust to the user’s preferences.

Reasons for Faster Images

Mediocre CPU, modest amounts of memory and a low-grade connection aren’t imaginary constraints. They pose real user experience challenges potentially affecting hundreds of millions of users worldwide. Some companies began to bake inclusive experiences into their products: streaming services like Netflix and Spotify adjust the streaming quality based on your network conditions, while many others are doing automatic image optimizations behind the scenes for users.

Developing regions, where fast networks aren’t yet accessible to everyone and everywhere, might not be one’s target market. Meanwhile, someone browsing from a rural area in a developed country will likely have a jarring experience if they are served a fully-fledged version of a website. We can be more considerate and intentional by adjusting what we send / display to our users with only a couple of small tweaks.

Using an image CDN like ImageEngine simplifies the image optimization process and automatically responds to the Client Hints for network constraints. The result is a better experience for a network-constrained visitor and an elegant workflow for developers.