Ayan Ali.
9 min readUpdated

Core Web Vitals for Shopify Liquid Themes (LCP, CLS, INP)

Each Core Web Vital has a different usual cause on Shopify: the hero image for LCP, app widgets and fonts for CLS, and JavaScript for INP. Here is what to change for each.

ShopifyPerformanceLiquidSEO
Three frosted glass columns of different heights on a dark plane, the tallest edged in lime, with the Shopify logo on an inset panel at the base of the centre column.

Short answer: on a Shopify Liquid theme, LCP is usually an image loading problem, CLS is usually missing dimensions, app-injected content or font swapping, and INP is usually too much JavaScript on the main thread. Fix whichever metric fails in your real-user data, starting with the page that fails worst. Code for each fix is below. Checked against Shopify's developer documentation, October 2026.

What are the Core Web Vitals thresholds for a Shopify store?

Google's "good" thresholds are LCP at 2.5 seconds or less, INP at 200 milliseconds or less and CLS at 0.1 or less. A page passes when real users meet the threshold for the metric, not when a single test run does.

LCP (Largest Contentful Paint) measures when the largest visible element finishes loading. INP (Interaction to Next Paint) measures how long the page takes to respond visually after a tap, click or keypress. CLS (Cumulative Layout Shift) measures how much visible content moves unexpectedly. Shopify's Built for Shopify requirements use 0.1 for CLS and 200 milliseconds for INP, which match Google's thresholds.

Should I use Lighthouse or real-user data?

Use real-user (field) data to decide what to fix and to confirm that a fix worked, and use Lighthouse to debug. Shopify's testing documentation says Lighthouse scores can differ significantly from real-user data, because a lab test runs on one device with simulated network throttling while real visitors use many devices and connections.

Check field data for the home, collection and product pages separately in PageSpeed Insights, since each page type fails for different reasons. Field data is a rolling window, so a fix shows up gradually rather than the next day. On a new, low-traffic or development store, field data may not exist, and Lighthouse is the fallback.

How do I fix a slow LCP on a Shopify theme?

Load the LCP image eagerly with high priority, and render it as an <img> in Liquid. Shopify's performance documentation says never to lazy-load the LCP image, because loading="lazy" deprioritizes it and delays the download.

{{ section.settings.image
  | image_url: width: 1600
  | image_tag:
      loading: 'eager',
      fetchpriority: 'high',
      widths: '800, 1200, 1600',
      sizes: '(min-width: 1000px) 1200px, 100vw' }}

Provide an explicit sizes attribute on LCP images. Calculating sizes with JavaScript, as some lazy-loading libraries do, delays the download because the browser cannot pick a source until the script runs. Do not use CSS background-image for hero content, because the browser's preload scanner finds an <img> earlier. Do not hide the LCP image behind a fade-in, because animations delay the LCP event even after the image has loaded.

What else delays LCP besides the image?

Three other causes show up often: content rendered by JavaScript, render-blocking resources, and overused preloads. Shopify's docs say moving product info, hero content or navigation into client-side JavaScript delays LCP, because Liquid renders on the server before the browser does anything.

Render the hero, product title and navigation in Liquid and HTML. Place first-paint stylesheets and fonts above {{ content_for_header }}, since Shopify streams everything above it to the browser while Liquid runs. Use preload for only one or two resources the browser discovers late, because overusing it competes with the browser's own prioritization and can slow the page.

How do I fix layout shift (CLS) on Shopify?

Start with images, then app widgets, then fonts. Images need width and height so the browser can reserve space. Shopify's image_tag filter adds both automatically, so a theme that outputs raw <img> tags without dimensions should switch to it.

App widgets are the usual second cause. Shopify's documentation describes the sequence: the page renders from theme HTML, the app's JavaScript loads, the script injects content, and the browser shifts existing content to make room. Review stars under the product title, trust badge rows, and shipping estimate widgets are the common offenders. Reserve their height in CSS.

/* Every app block in the product info column */
.product__info-container .shopify-app-block { min-height: 28px; }

@media screen and (max-width: 749px) {
  .product__info-container .shopify-app-block { min-height: 56px; }
}

Measure the widget's real height in DevTools (its offsetHeight) on both desktop and mobile, then use that value or slightly more. Content injected below the first screen does not count toward CLS, so moving a widget lower on the page is also a fix. Cookie banners and chat bubbles shift layout only when they render in normal flow, so make them position: fixed instead of reserving space.

How do fonts cause layout shift?

A web font that loads after the fallback font can change text size and move the lines below it. The cleanest fix is system fonts, which need no download and cause no swap. If the brand needs a custom font, use font-display: swap with a fallback font adjusted to match.

@font-face {
  font-family: "Brand Font Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}
body { font-family: "Brand Font", "Brand Font Fallback", sans-serif; }

Those values are Shopify's example and must be measured for your own font and fallback pair. Fontaine and Capsize generate them. Shopify's docs suggest tackling this after other CLS sources such as images without dimensions and injected content, unless real-user data shows font swapping is the main contributor.

What makes INP slow on a Shopify theme?

INP is slow when the main thread is busy. Shopify's documentation splits each interaction into three phases: input delay (waiting for a busy main thread), processing time (running event handlers from the theme and apps), and presentation delay (style, layout and paint).

Shopify lists the interactions to check first: variant selection, cart drawer open and close, mega menu expansion, search input, and filter application on collection pages. Profile one in the Chrome DevTools Performance panel, look for long tasks marked with red corners, and note whether scripting, rendering or painting dominates. That tells you which phase to fix.

How do I reduce JavaScript to improve INP?

Audit apps before touching code, because every installed app can add main-thread work. Remove apps no longer used, check whether removed apps still inject code into the theme, and look for apps that duplicate each other's features. The steps are in how to speed up a Shopify store without apps.

Then check which third-party scripts attach event listeners. In DevTools, select an element and open the Event Listeners tab in the Elements panel. Analytics scripts that run synchronous code inside click handlers add processing time to every interaction.

How do I fix specific slow interactions?

Each common interaction has its own fix. Three cover most themes.

Variant selector. Theme JavaScript often updates price, availability, images and button text at once, and each DOM update can trigger layout. Batch DOM reads before writes, and apply the visual updates in one requestAnimationFrame call.

Cart drawer. A drawer animated with width, height or top triggers layout on every frame. Animate transform instead.

.cart-drawer { transform: translateX(100%); transition: transform .25s ease; }
.cart-drawer.is-open { transform: translateX(0); }

Search input and mega menu. Debounce the search handler so it runs after the visitor stops typing, and keep mega menu content in the DOM and toggle its visibility rather than inserting elements on hover.

function debounce(fn, wait) {
  let t;
  return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), wait); };
}
searchInput.addEventListener('input', debounce((e) => performSearch(e.target.value), 300));

Which Core Web Vital problem has which fix?

The table maps each metric to its usual Shopify cause and the first fix to try.

| Metric | Usual cause on Shopify | First fix | |---|---|---| | LCP | Lazy-loaded or background-image hero | loading: 'eager', fetchpriority: 'high', <img> via image_tag | | LCP | Content built by JavaScript | Render it in Liquid | | CLS | Images without dimensions | Use image_tag | | CLS | Review stars, badges, shipping widgets | min-height on the app block | | CLS | Font swap | System fonts, or a matched fallback font | | INP | App and tracking JavaScript | Remove apps, audit listeners | | INP | Cart drawer, variant picker, filters | transform, batched DOM updates, debounce |

What did I do on real stores?

I write storefront sections in Liquid rather than adding page-builder apps, which keeps the amount of JavaScript on the page under my control. Zaiqa uses a premium theme with almost all sections custom coded, and Naturabites uses custom Liquid sections for the landing, about and product pages. Scroll effects on Naturabites are covered in Shopify parallax scrolling without hurting speed.

I have not published before-and-after Core Web Vitals numbers for these stores and will not invent them. See the Naturabites and Zaiqa case studies for the work itself.

When should I hire help with Core Web Vitals?

Hire help when the failing metric traces to theme code you do not want to edit, such as the variant picker, cart drawer or hero section, or when the audit shows apps that need replacing with custom sections. Bring field data for your three main page types and a list of installed apps.

If you want your Core Web Vitals diagnosed and fixed, see my Shopify development services or get in touch with your store URL.

Sources

Frequently asked questions

What are good Core Web Vitals scores?

Google's 'good' thresholds are LCP of 2.5 seconds or less, INP of 200 milliseconds or less and CLS of 0.1 or less. Shopify's Built for Shopify requirements use 0.1 for CLS and 200 milliseconds for INP.

What is the LCP element on a Shopify store?

Usually an image: the hero on the home page, the main product image on a product page, or the first collection card images. Shopify's performance docs say images are typically the LCP element.

Why does my Shopify store have layout shift even with image dimensions set?

App widgets that inject content after the page loads are a common cause, such as review stars, trust badges and shipping estimates. Reserve their space with a min-height in CSS.

What slows INP on Shopify?

Main-thread JavaScript. Shopify lists variant selection, cart drawer open and close, mega menu expansion, search input and collection filters as the slow interactions to check first.

Should I trust my Lighthouse score or real-user data?

Use real-user (field) data to decide what to fix and to confirm a fix worked. Use Lighthouse to debug a specific problem. Shopify's docs note that lab scores can differ significantly from field data.

Store loading slowly?

I fix Shopify performance by hand — images, scripts, app bloat, theme code — without installing another app to fix the apps. Send me your store URL and I'll tell you what is actually costing you.

Read next

How to Add an AI Chatbot to Shopify Grounded in Your Product Catalogue
A frosted speech-bubble form above a grid of product boxes, connected by thin lime lines, with the Shopify logo set into the floor and the OpenAI logo on the bubble.
Shopify

How to Add an AI Chatbot to Shopify Grounded in Your Product Catalogue

A Shopify chatbot that does not invent products needs four parts: a synced catalogue index, retrieval, a grounded prompt, and a Liquid section that talks to your backend. Here is each part.

Read
How to Build an AI Product Finder Section for Shopify
A wide field of dark cubes receding into shadow with a narrow lime light picking out exactly three, and the Shopify logo on a plate in the foreground.
Shopify

How to Build an AI Product Finder Section for Shopify

A product finder takes 'a waterproof jacket for light hiking under $150' and returns matching products. It needs vector search and filters, and it does not need a chat model.

Read
How to Make Shopify Color Swatches Link to Separate Product Pages
Five matte spheres in a row, each linked by a thin lime line to its own separate product panel below, with the Shopify logo on a plinth in the foreground.
Shopify

How to Make Shopify Color Swatches Link to Separate Product Pages

A swatch that opens a different product page needs one product per color, a metaobject that groups them, and a short Liquid snippet. Here is the full build, and when not to bother.

Read

Got a store or a build in mind?

Tell me what you're trying to ship — a Shopify section, a full storefront, a chatbot, or a web app. I'll tell you what it takes, honestly, before you commit.

ayanrjpoot@gmail.com