It’s not me, it’s you.
Whether you’re in our store, at home or at the trailhead, REI gets you the gear and advice you need for your next outdoor adventure. REI’s Web Performance team focuses on customer experience at the trailhead. The WP team knows optimizing REI.com for poor network conditions and/or slower devices creates a better experience for everyone.
I’m Casey Carroll (he/him/his), a Web Performance Engineer new to the co-op. Off the clock, I adventure around the PNW on a gravel bike. Since I often end up in remote areas, I can attest to the frustrating experience of visiting a website on a poor connection. A poor network connection shouldn’t necessitate a bad user experience, though. We can build resilient websites that efficiently deliver content to the browser despite connection speed or device power.
Today, developers have access to many performance enhancement techniques. They can tell browsers when to prioritize different resources on the network, defer heavy work loads or lazy load assets required for uncommon user paths. Some techniques have gone the way of the dinosaur. Unfortunately, HTTP/2 Server Push is the latest.
What is HTTP/2?
HTTP/2 is a major evolution of the HTTP/1.1 protocol. HTTP/2 contains a faster version of TLS and laid the groundwork to replace TCP with QUIC in HTTP/3. These improvements have been a net positive for the web. Unfortunately, one of its most exciting features, Server Push, had questionable performance gains and Chrome intends to remove it.
What is Server Push?
When you visit a webpage, your browser asks the server for the HTML. The HTML tells the browser everything else it needs, so the browser goes back to the server and asks for each asset one by one. This process has bottlenecks and can be painfully slow on underpowered devices and poor internet connections.
Simplified HTTP/1.1 Diagram
Server Push circumvents the bottlenecks by “pushing” critical assets to the browser before it asks for them. With less round trips, the browser can start rendering a page and reach interactivity sooner. On paper, this feature would improve performance metrics across the board.
Simplified Server Push Diagram
You might think caching would become a headache. Fortunately, some servers have a cache aware sever push implementation. Our CDN handles Server Push caching effectively, but other CDNs or servers may not. This is just one of the complexities that comes with Server Push.
Server Push at REI
In 2020, REI implemented Sever Push as a “set it and forget it” enhancement. After all, the web developer community advocated for Server Push as a quick win to optimize a page’s critical rendering path. The only voice of concern I can recall is Jake Archibald’s 2017 article, “HTTP/2 push is tougher than I thought”. He uncovered bugs related to caching. By 2020, it was safe to assume most issues were ironed out. The performance wins seemed clear and simple: The faster you push critical assets to a browser, the better, right?
In practice, Server Push eagerly delivered assets and flooded the browser. REI observed critical assets and non-critical assets all competing for network and main thread resources. This hindered browsers’ prioritization efforts and ultimately delayed page render. This magical remedy turned out to have a negative impact on REI’s site performance.
Request Waterfall with Server Push Enabled
The browser must manage ~8 assets all at once, not including the fonts that come shortly after the initial push. The browser doesn’t utilize many of these assets until later, as noted by the pink rectangles to the right of the network bars. Despite delayed utilization, the main thread devotes itself to downloading and parsing these assets. The encumbered main thread can’t spare the resources to render the page. This leads to REI pages taking longer to load.
In the end, only 0.05% of HTTP/2 sessions on Chrome browsers used Server Push. Challenging configuration, server support or uncompelling performance improvements could explain Server Push’s low adoption. We chose to disable it once we observed these performance impacts and became aware of Chrome’s intention to remove Server Push.
Request Waterfall with Server Push Disabled
With Server Push disabled, the browser follows the order of asset requests in the HTML and optimizes the order it pulls in, parses and executes them. Instead of managing a flood of assets, the browser relies on decades-old queuing algorithms to render the page quickly.
Admittedly, the improvement to First Contentful Paint astounded me. Our tests revealed a 50% reduction in time to first paint and a closer gap between first paint and First Contentful Paint. We decided to disable the font preloading feature, too. Results remained positive.
Server Push Visual Comparison
Now the browser has more breathing room to render the page. The faster we can signal to the user that the page is loading, the better. Bounce rate probability increases to ~32% when a site takes up to three seconds to load. Bounce rate increases to 90% as we approach 5 seconds. Slow loading sites have been known to increase users’ heart rate, too. It’s akin to watching a horror movie!
As an aside, we could reach an optimal middle ground by only pushing CSS assets. We decided against this configuration due to Chrome’s removal announcement and the potential maintenance cost.
“Early Hints” as a Push Replacement
Chrome 103 introduced support for a new HTTP status code named “103 Early Hints”. The server sends this status code as a hint to the browser. While the server works on returning the main resource, the browser uses these hints to warm up connections and request critical sub-resources like stylesheets, JS bundles or key images. These hints can improve page load times. Shopify observed Largest Contentful Paint occur a full second earlier with 103 Early Hints.
Unlike Server Push, Early Hints inverts control back to the browser. While some CDNs solved the “over-pushing” issue, Server Push had a fundamental design flaw that led to servers pushing resources the browser already had cached. With Early Hints, the browser has full discretion over fetching and prioritization. The server can suggest downloading a CSS file and the browser can determine if it should pull it from cache or the network.
While we see promise in this new feature, REI doesn’t have immediate plans to implement it. Once our CDN fully supports Early Hints, we’ll assess the amount of work and maintenance required to support it. Google suggests limiting Early Hints to stable assets, but most REI pages update frequently. In some cases, developers push updates multiple times a day. Additionally, Early Hints work best for servers that require think-time to return the main request. We use effective CDN cache policies that practically eliminate server think-time, so Early Hints might not make sense for REI at all.
REI disabled Server Push in production in early June 2022. The change made no impact on site reliability. Since then, we’ve seen an uptick in performance metrics like Largest Contentful Paint and First Contentful Paint. These improvements shine brightest on low powered devices and/or weak connections.
I’m quite satisfied with this quick win. Disabling Server Push also enables more control over the priority of assets on the page. We plan to experiment with restructuring the head of the document and carefully adding priority hints to key assets to improve First Contentful Paint and Largest Contentful Paint.
If you’re a developer leveraging Server Push, I recommend reevaluating its performance. You might be surprised by what you find! Server Push does work for some sites, but considering support will drop soon, you might as well disable it and ensure asset priorities align with your goals.
Special thanks to Harry Roberts (@csswizadry) for pointing out Server Push’s flaws. He proposed disabling Server Push after auditing REI’s site in May.