---
title: Debugging performance with metric gaps
description: >-
  Analyze the gaps between TTFB, FCP, and LCP in RUM data to narrow down root
  causes before opening a lab testing tool.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/performance-gaps
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/performance-gaps.md
api_name: liquid
---

# Debugging performance with metric gaps

Use your [Real User Monitoring (RUM)](https://web.dev/articles/vitals-field-measurement-best-practices) data to diagnose performance problems before you open any lab testing tool. As the Shopify Performance Team puts it: "The first step to debugging a slow site should not be to open up a lab-based testing tool... Instead, we should be looking at our real user monitoring (RUM) data to identify and prioritize our biggest opportunities." The primary loading metrics, [TTFB](https://web.dev/ttfb/), [FCP](https://web.dev/fcp/), and [LCP](https://web.dev/lcp/), share the same starting point (navigation start), so the gaps between them reveal where problems are concentrated.

***

## Visualizing the gaps

Use a RUM tool that provides a distribution view, like the Shopify Web Performance Dashboard or the free TREO Site Speed tool:

1. Visit [`https://treo.sh/sitespeed`](https://treo.sh/sitespeed).
2. Enter your domain.
3. Toggle to the **Distributions** view.
4. Look at the stacked bar charts.

Good performance shows mostly green across all three metrics. Poor performance shows yellow or red. Comparing the three reveals where issues concentrate. Analyze by page type (home, product, and collection) and device (mobile and desktop) separately for better specificity.

***

## How to find your gaps

Work from field data to a single suspect phase before you open a lab tool:

1. Pick one page type and one device category. A home page on mobile and a product page on desktop are different problems with different fixes.
2. Read TTFB, FCP, and LCP for that segment at the same percentile. Use the Shopify Web Performance Dashboard for your own store, or TREO Site Speed and [PageSpeed Insights](https://pagespeed.web.dev/) for CrUX data on any public domain.
3. Subtract to get the three gaps: TTFB itself, then FCP minus TTFB, then LCP minus FCP.
4. Take the largest gap as your suspect phase, and match it to a pattern below.
5. Reproduce the phase in a lab tool. Configure [WebPageTest](https://www.webpagetest.org/) or the Chrome DevTools **Performance** panel with a device, connection, and location that resemble the segment you picked, then read the waterfall for that phase only.
6. Fix one thing, then confirm the gap closed in field data before moving to the next phase.

If you can't get field data for a page, because it's new or low-traffic, then measure it in the lab, but treat the numbers as a hypothesis rather than a baseline. See [Lab vs. field data](https://shopify.dev/docs/storefronts/themes/best-practices/performance/lab-vs-field) for why the two disagree.

***

## Gap patterns

Each diagram below is a schematic timeline, not a measurement. All three metrics start at navigation start, so the distance between the markers is the gap you're diagnosing:

```text
|--->|   time spent in a phase
TTFB     the first byte of the HTML document arrives
FCP      the first content is painted
LCP      the largest content is painted
```

### Pattern 1: Slow TTFB, then quick FCP and LCP

```text
navigation                                        TTFB  FCP  LCP
|------------- waiting on the server --------------->|--->|--->|
```

Problem area: server response or complex Liquid rendering. The browser can't start work it hasn't received.

Common causes on Shopify storefronts:

* Expensive Liquid: deeply nested loops, filters or metafield lookups repeated inside loops, and nested `render` calls.
* Overfetching: paginating too deeply, or loading every variant when the page shows one.
* A proxy in front of the Shopify CDN, which adds a network hop to every request and can defeat edge caching.
* App proxies or server-side app logic in the request path.

Where to go next:

* [Liquid performance patterns](https://shopify.dev/docs/storefronts/themes/best-practices/performance/liquid-performance-patterns)
* [Avoid deeply nested Liquid loops](https://shopify.dev/docs/storefronts/themes/best-practices/performance/avoid-deeply-nested-liquid-loops)
* [Move metafield access outside loops](https://shopify.dev/docs/storefronts/themes/best-practices/performance/move-metafield-access-outside-loops)
* [Limit pagination depth](https://shopify.dev/docs/storefronts/themes/best-practices/performance/limit-pagination-depth)
* [Avoid request proxies](https://shopify.dev/docs/storefronts/themes/best-practices/performance/avoid-request-proxies)

### Pattern 2: Fast TTFB, slow FCP

```text
navigation    TTFB                                   FCP  LCP
|-------------->|--- rendering blocked or delayed ---->|--->|
```

Problem area: the HTML arrived quickly, but something is standing between it and the first paint.

Common causes on Shopify storefronts:

* Render-blocking stylesheets and synchronous scripts in `theme.liquid`, including app-injected tags you didn't add.
* Anti-flicker snippets from A/B testing tools, which deliberately hide the page until their script runs.
* Too many separate stylesheets, so the browser waits on a long chain of requests.
* A large DOM before the first paint, most often a mega menu duplicated for mobile and desktop.
* Blocking requests to third-party origins that need a fresh DNS lookup, TLS handshake, and connection.

Where to go next:

* [Defer non-critical scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-scripts)
* [Load critical CSS synchronously](https://shopify.dev/docs/storefronts/themes/best-practices/performance/load-critical-css-synchronously)
* [Reduce stylesheet count](https://shopify.dev/docs/storefronts/themes/best-practices/performance/reduce-stylesheet-count)
* [Manage A/B testing impact](https://shopify.dev/docs/storefronts/themes/best-practices/performance/disable-ab-testing-when-inactive)
* [Remove or optimize apps causing render-blocking issues](https://shopify.dev/docs/storefronts/themes/best-practices/performance/remove-render-blocking-apps)
* [Merge duplicate mobile and desktop menus into one](https://shopify.dev/docs/storefronts/themes/best-practices/performance/reduce-mega-menu-dom-overhead)
* [Warm up third-party connections early with `preconnect`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-preconnect)

### Pattern 3: Fast TTFB and FCP, slow LCP

```text
navigation    TTFB    FCP                                 LCP
|-------------->|----->|--- LCP element discovered and --->|
                          loaded late, or revealed late
```

Problem area: the page paints something quickly, but the largest element arrives late. Split this gap in two: the browser either found the resource late (a discovery problem) or found it on time and displayed it late (a render problem).

Common causes on Shopify storefronts:

* The LCP image carries `loading="lazy"`, often from a theme setting or a section that lazy-loads everything by default.
* The LCP image is a CSS background, so the preload scanner can't discover it until the stylesheet is parsed.
* JavaScript renders the LCP element, or the Section Rendering API fetches it after the initial paint.
* A fade-in, carousel transition, or scroll animation hides the image after it has downloaded.
* A dialog, cookie banner, or email capture becomes the LCP element instead of your hero.
* The image is much larger than the space it fills, because you didn't set `widths` and `sizes`.

Where to go next:

* [Never lazy-load the LCP image](https://shopify.dev/docs/storefronts/themes/best-practices/performance/never-lazy-load-lcp-image)
* [Mark the LCP image with `fetchpriority="high"`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/set-fetchpriority-high-on-lcp-image)
* [Don't use CSS `background-image` for LCP content](https://shopify.dev/docs/storefronts/themes/best-practices/performance/avoid-background-images-hero)
* [Render essential content server-side](https://shopify.dev/docs/storefronts/themes/best-practices/performance/render-essential-content-server-side)
* [Don't hide the LCP image behind animations](https://shopify.dev/docs/storefronts/themes/best-practices/performance/dont-hide-lcp-image-behind-animations)
* [Prevent dialogs from hijacking LCP](https://shopify.dev/docs/storefronts/themes/best-practices/performance/prevent-popups-hijacking-lcp)
* [Serve correctly sized images with `srcset` and `sizes`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-responsive-images)

### Pattern 4: Multiple gaps

```text
navigation                     TTFB            FCP        LCP
|---- slow server -------------->|-- blocked --->|-- late -->|
```

Indicates: multiple problems need addressing.

Prioritization: Fix FCP-related issues first, because they also impact LCP. However, if you see an obvious and easy-to-fix LCP issue, such as lazy loading the LCP image, fix that first.

When every phase is slow, suspect a single cause with reach across all of them before you plan three separate projects. A proxy in front of the Shopify CDN, a heavy script that every page loads, or a third-party tool that both blocks rendering and delays images can produce this shape on its own. Audit what's shared across page types first. See [Audit and remove third-party scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/audit-remove-third-party-scripts) and [Finding and ranking your worst JavaScript offenders](https://shopify.dev/docs/storefronts/themes/best-practices/performance/finding-worst-offenders).

***

## References

* [Debugging common causes for slow loading in Shopify Liquid storefronts](https://performance.shopify.com/blogs/blog/debugging-common-causes-for-slow-loading-in-shopify-liquid-storefronts)
* [Lab vs. field data](https://shopify.dev/docs/storefronts/themes/best-practices/performance/lab-vs-field)
* [Build a sustainable performance practice](https://shopify.dev/docs/storefronts/themes/best-practices/performance/sustainable-performance)
* [Defer non-critical scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-scripts)
* [Never lazy-load the LCP image](https://shopify.dev/docs/storefronts/themes/best-practices/performance/never-lazy-load-lcp-image)
* [Testing for performance](https://shopify.dev/docs/storefronts/themes/best-practices/performance/testing-for-performance)
* [Core Web Vitals thresholds](https://web.dev/articles/defining-core-web-vitals-thresholds)

***
