Recently we were contracted by an agency for a performance optimization project for a newly created site on Shopify. We had some great results, which we'd like to share.
We began with a performance audit, analyzing how the page loads and renders for various devices and under various network conditions. The goal is to identify all the areas of the site which are contributing to poor performance, and then rank them by two factors: by the magnitude of the negative performance impact, and by the difficulty of correcting or changing them. This allows us to begin with the lowest hanging fruit, taking a pareto approach, looking for the 20% of things which will result in 80% of the performance improvement.
A note on performance improvement: Improving site performance is an unbounded function. Put another way, the ideal endpoint for optimization is impossible (i.e. no site can load in zero time). At some point, there's a tipping point where further optimization is not worthwhile.
Once we've identified and sorted the available optimizations, we outline a list of recommended improvements. In this project, we discovered..
Initial load time wasn’t the worst (~4.3s to first render & available for interaction, but frame rates still low till ~10-15 seconds). Fully loaded time is quite high.
We also discovered that some background images were unnecessarily large, with some being served at a higher size than displayed. The large background images for the homepage slider were quite heavy and were formatted as pngs.
A note on image file formats: Media formats on the web are an important and can dramatically impact performance, but care should be taken when considering the content of the image and lossless, lossy, and vector file types. More on this later.
We also discovered that a background animation in the second section on the homepage (below the fold), was composed of 108 jpg images that are fetched in the background. These are about ~55KB per image and add up to 5.8MB (108 images * 55 KB / 1024KB). The implementation was meant to be a performance-friendly solution, but fell short in practice in a few areas I'll outline further on.
We also discovered a few areas for improvement to bring the site up to speed on some best practices, which included removing a few unused font files (probably left over from an early development phase), and combining many css and scss files together to cut down on a few requests.
With these optimizations uncovered and outlined, we set out to see how we could improve the performance.
Image optimization is often the lowest hanging fruit in performance optimization, and we optimized or further optimized the images served over AWS/S3, as well as those served via the Shopify CDN, both theme assets and via the Files interface.
A note on image optimization in Shopify: There are apps to "optimize all your images" - don't trust these apps. There are several different places images are stored within Shopify, and these apps don't account for them all. There are backend images - associated with products, variants, blog articles, etc. There are Files - which are images uploaded via Settings > Files or via Themes > Customize, and are stored at the store-level. There are also theme assets, which are stored in the theme's asset directory, accessible via admin under Themes > [theme] > Edit Code > Asset's folder. Additionally - there may be other locations from which images are served to your site, which you may or may not have access to - the Networks panel in DevTools is your friend.
For the image optimization, our preferred tool is ImageOptim - not only does it have a drag and drop interface, in our experience it also gets the best results from any tools we've tried (we've tried a lot). We highly recommend using Shopify's theme development to download the theme image assets via the API. We've written a tutorial for this which you can check out here.
Another big win came from switching the format of the homepage png slider images to progressive jpg format. These images are vital for the initial page load experience since they're literally the first the a user will see, and the progressive jpg format is ideal for this type of scenario.
Image Formatting quick tips: PNG is lossless, but heavy, especially when there's a large number of colors like in a gradient or photograph - use this only when necessary for super crisp images which would suffer from jpg artifacts, or when transparency is present. JPG is better for large or colorful images, and can be automatically converted to Progressive JPG (PJPG) by shopify's img_url liquid filter. SVG or vector formats are the best, but most commonly used for logos or icons. Implementation is a little more challenging and browser support somewhat flakey, but good resources exist for the brave and motivated.
The background animation was using a library called sequence.js to load the images, but had a few issues: it was render blocking, so the site had to wait for all the images to load before it rendered the section and began the animation, it served the images over http, which created a bottleneck for concurrent http requests (chrome caps out at 6), and the AWS configuration was missing expiration headers.
Between manual app implementations and combined css, we reduced the critical render request chain length from 39 to 28, which means only 28 requests are required before the page can first be rendered.
Finally, we were ready to run the site against the same set of benchmarks performed prior to the project, and compare results to find out how we did.
A note on performance metrics: Accurately representing the performance of a Shopify site can be challenging due to a number of confounding variables. The tools for measurement cater to all types of websites using different technologies, and are often unaware of ecommerce best-practices and Shopify-specific infrastructure. On the flipside, ecommerce sites are accessed across a diverse range of devices, network conditions, browsers, and operating systems - an idealized test-case scenario isn’t that meaningful of a measure when we’re trying to estimate performance and optimize for real-world site users.
We use several different tools to reach a good approximation of site performance, averaging together multiple measurements from each to account for variances between measurements from the same tool. I'll provide a short description of each tool and it's role in our workflow.
Google PageSpeed Insights
While made by google, it is a one-size-fits-all-sites tool, and suggests many things which are not appropriate and/or relevant for shopify sites. It also does not take into account any empirical size or timing numbers - it strictly a measure against google’s “best practices” (so, a site that loads in 45s can score higher than a site that loads in <1). However, site speed is increasingly a factor in their SEO rankings, so it is a good idea to cater somewhat to this measurement tool.
Old Scores: Mobile: 25, Desktop: 19
New Scores: Mobile: 60, Desktop: 80
Good for tracking and averaging page weight (total page size) & request count. Fully loaded time is a measure of when all the scripts end (not necessarily important - especially considering analytics tracking code that will continue to fire until user is idle). These tests use a throttled connection approximating a worse-than-average 3G network.
Page Size (weight) & request count averages
12.6MB -> 8.24MB (34% reduction)
300 requests -> 264 (12% reduction)
Performance grade is the most applicable to shopify in terms of best practices & legitimate optimization opportunities. Their Load time is a good measure of the time to first render/time to interactive (perceived speed).
Time to first render & Time to interactive
Approx. 4.3s -> 1.5s - 2.2s (48-65% reduction on a <100ms 20MB/s connection)
We were quite pleased with the results. The site is and feels significantly faster, especially while it's loading. The client was "over the moon", which we love to hear. This project was a successful round of optimization - there are many other optimizations we could make, but we achieved significant results with minimally technical and involved improvements. It will be up to the client and their business analytics to determine whether further optimization of the site is cost-effective, but for a 25 hour project, this was certainly the Pareto effect we were hoping for.