How to Do an In-Depth Liquid Render Analysis with Shopify Theme Inspector

shopify theme inspector

With Shopify, you have lots of flexibility to build themes representing the brand of a merchant’s online store. However, like with any programming language, you might not be aware of the performance impact of the code that you write. Whether it be the performance impact on Shopify’s servers or observable performance impact on the browser, ultimately, it’s the customers that experience the slowness. 

The speed of server-side rendering is one of the most important performance timings to optimize for. While server-side rendering completes, customers wait on a blank screen—not a good experience for them. Even though we’re working hard to make server-side rendering as fast as possible, bottlenecks may still originate from the Liquid source itself.

Luckily, there are tools available to help you analyze Liquid render performance. Specifically, the Shopify Theme Inspector Chrome extension can help you debug performance and make your themes fast. In this article, we’ll look at how to interpret the flame graphs generated by the inspector, how unoptimized Liquid code patterns show up in the flame graphs, and share tips for spotting and avoiding these performance issues.

1. Install the Shopify Theme Inspector

Using a Google Chrome browser, install the Shopify Theme Inspector extension. Jump into our previous article on using the Shopify Theme Inspector to get started with the extension and get to a point where you can produce a flame graph on your store like the one shown below.

shopify theme inspector: example of a flame graph
An example of a flame graph created by the Shopify Theme Inspector.

The flame graph produced by this tool is a data representation of the code path and the time it took to execute. With this tool, as a developer, you can find out how long a piece of code took to render.

You might also like: How to Refactor a Shopify Site for Javascript Performance.

2. Start with clean code

We often forget what clean implementation looks like. As time passes, code becomes complicated, especially as you find workarounds and ways to achieve your goals. But to get an accurate picture of render speeds, we need to go back to the clean implementation to understand why it takes the time it does to render.

"We often forget what clean implementation looks like."

The simple code above creates the following flame graph when run through the Theme Inspector:

shopify theme inspector: 10 item pagination
Flame graph for a 10-item paginated collection.

The template section took 13 ms to complete rendering. But, let’s dig in to get a better understanding of what we are seeing here.

shopify theme inspector: highlighted flame graph depicting a 10 item pagination
Highlighted flame graph for a 10-item paginated collection.

The area where the server took the time to render is where the code for the pagination loop is executed. In this case, we rendered 10 product titles. Then, there’s a block of time that seems to disappear—this is actually the time spent on Shopify’s side collecting all the information that belongs to the products in the paginate collection.

Template Icon

3. Take a look at inefficient code

To know what’s inefficient code, you need to know what it looks like, why it’s slow, and how to recognize it in the flame graph. This section walks through a side-by-side comparison of code and its flame graphs, and how a seemingly simple change can result in bad performance.

Heavy loop

Let’s take that clean code example and make it heavy.

What I’ve done here is accessed attributes in a product while iterating through a collection. Here’s the corresponding flame graph:

shopify theme inspector: 10 item pagination with accessing attributes
Flame graph for a 10-item paginated collection with accessing to its attributes.

The total render time of this loop is now at 162 ms, compared to 13 ms from the clean example. The product attributes access changes a less than one ms render time per tile to 16 ms render time per tile. This produces exactly the same markup as the clean example, but at the cost of 16 times more rendering time. If we increase the number of products to paginate from 10 to 50, it takes 800 ms to render.

Tips:

  • Instead of focusing on how many one millisecond bars there are, focus on the total rendering time of each loop iteration
  • Clean up any attributes that aren’t being used
  • Reduce the number of products in a paginated page (potentially AJAX the next page of products)
  • Simplify the functionality of the rendered product

You might also like: Working with Product Variants When Building a Shopify Theme.

Nested loops

Let’s take that clean code example and make it render with nested loops.

This code snippet is a typical example of iterating through the options and variations of a product. Here’s the corresponding flame graph:

shopify theme inspector: with two nested loops
Flame graph for two nested loop example.

This code snippet is a two-level nested loop rendering at 55 ms.

Nested loops are hard to notice when just looking at code because they’re separated by files. But with the flame graph, we see additional rows representing them.

shopify theme inspector: single loop on a product
Flame graph of a single loop on a product.

As highlighted in the screenshot above, the two inner `for` loops stack side by side. This is okay if there are only one or two loops. However, each iteration’s rendering time will vary based on how many inner iterations it has.

Let’s look at what a three-nested loop looks like.

shopify theme inspector: 10-item pagination with three nested loops
Flame graph for three nested loops.

This three-level nested loop rendered at 72 ms. This can get out of hand really quickly if we aren’t careful. A small addition to the code inside the loop could blow your budget on server rendering time.

Tips:

  • Look for a sawtooth shaped flame graph to target potential performance problems
  • Evaluate each flame graph layer and see if the nested loops are required

Mix usage of multiple global Liquid scope

Let’s now take that clean code example and add another global scoped Liquid variable.

And here’s the corresponding flame graph:

shopify theme inspector: flame graph when there's 1 item in the cart, rendering at 45s
Flame graph of when there’s one item in the cart with a rendering time at 45 ms.
shopify theme inspector: flame graph showing 10 items in the cart
Flame graph of when there are 10 items in the cart with a rendering time at 124 ms.

This flame graph is an example of a badly nested loop, where each variation is accessing the cart items. As more items are added to the cart, the page takes longer to render.

Tips:

  • Look for hair comb or sawtooth shaped flame graphs to target potential performance problems.
  • Compare flame graphs between having one item and multiple items in the cart.
  • Don’t mix global Liquid variable usage. If you have to, use AJAX to fetch for cart items instead.

You might also like: How We Improved Theme Development Tooling Using Checksums.

4. Understand what is fast enough

When using the Theme Inspector extension to measure rendering time, try to aim for 200 ms, but no more than 500 ms total page rendering time. We didn’t just pick a number out of the hat: it’s made with careful consideration of what other processes require page render time, and how time is allocated between those to meet our performance goals.

"When using the Theme Inspector extension to measure rendering time, try to aim for 200 ms, but no more than 500 ms total page rendering time."

Google Web Vitals has stated that a good score for Largest Content Paint (LCP) is less than two and a half seconds. However, the largest content paint is dependent on many other metrics, like time to first byte (TTFB) and first content paint (FCP).

So, let’s make some time allocation! Also, let’s understand what each metric represents:

shopify theme inspector: black infograph depicting the process

  • Network overhead time is the time required from Shopify’s server to communicate with a browser. It varies based on the network the browser is on. For example, whether the user is navigating the store on 3G or Wi-Fi.
  • From a blank browser page (TTFB) to showing anything on that page (FCP) is the time the browser needs to read and display the page.
  • From the FCP to the LCP is the time the browser needs to get all other resources (images, CSS, fonts, scripts, video, etc.) to complete the page.

The goal is an LCP of less than two and a half seconds:

  • Server → Browser: 300 ms for network overhead
  • Browser → FCP: 200 ms for the browser to do its work
  • FCP → LCP: one and a half seconds for above-the-fold image and assets to download

This leaves us with 500 ms for total page render time.

Does this mean that as long as we keep server rendering below 500 ms we can get a good LCP score? Unfortunately no—there are other considerations, like critical rendering path, that aren’t addressed here. But, at least this gets us half of the way there.

Tip:

  • Optimizing for critical rendering path on the theme level can bring the 200 ms requirement between the browser to FCP timing down to a lower number

So, we have 500 ms for total page render time, but this doesn’t mean you have all 500 ms to spare. There are some mandatory server render times that are dedicated to Shopify and others that the theme dedicates to rendering global sections like the header and footer. Depending on how you want to allocate the rendering resources, the available rendering time you leave yourself with for the page content varies. For example:

Total

500 ms

Shopify (content for header)

50 ms

Header (with menu)

100 ms

Footer

25 ms

Cart

25 ms

Page content

300 ms



I mentioned trying to aim for a 200 ms total page rendering time—this is a stretch goal. By keeping ourselves mindful of this goal, it’s much easier to start recognizing when performance starts to degrade.

A stronger overall performance

By using the Shopify Theme Inspector Chrome extension, you can run in-depth analyses like the ones you’ve seen in this article to make sure your clients’ stores are performing at their best, helping them lose fewer conversions and make more sales.

If you are experimenting with the Shopify Theme Inspector, please consider sharing your experience with us and let us know how we can improve. You can also tweet us at @shopifydevs.

Grow your business with the Shopify Partner Program

Learn more