Cumulative Layout Shift in Shopify

Shopify stores commonly score poorly on CLS due to product image handling, app-injected scripts, and theme architecture decisions. This guide covers every major cause of CLS on Shopify stores and the specific steps to fix each one.

Why Shopify Stores Have CLS Problems

Shopify's app ecosystem and theme marketplace create a performance environment similar to WordPress — many stores layer multiple third-party apps on top of their theme, each injecting its own scripts, styles, and DOM elements. The result is that a Shopify store's actual page experience is determined not just by the theme code but by the combined behavior of every app installed, many of which inject elements above existing content or load resources that shift the layout after the initial render.

The most common CLS sources on Shopify stores are product images without declared aspect ratios, announcement bars and cookie consent banners injected above the header, app-installed chat widgets and popup builders, image carousels and product gallery sliders, and dynamically loaded upsell or cross-sell panels that appear after the initial product page render.

Diagnose before you fix: Run your store's product pages, collection pages, and homepage through the free CLS checker on this site. Product pages and homepages are the highest-priority pages for CLS on e-commerce sites because they carry the most traffic and have the highest conversion value.

Fix CLS Caused by Product Images

Product images are the most common CLS source on Shopify stores, and they are also the most straightforward to fix. When an <img> tag does not include width and height attributes, the browser cannot reserve the correct amount of space in the layout before the image downloads, causing the content below the image to shift when the image arrives.

Adding Dimensions to Images in Liquid Templates

In Shopify's Liquid templating language, images rendered through the img_url filter or the image_tag helper should include explicit dimension attributes. The image_tag helper (available in Shopify 2.0 themes) automatically outputs width, height, and loading="lazy" attributes:

{% comment %} Recommended: image_tag helper outputs width, height automatically {% endcomment %} {{ product.featured_image | image_url: width: 800 | image_tag: loading: 'lazy', width: product.featured_image.width, height: product.featured_image.height, alt: product.featured_image.alt }}

If you are using an older theme that outputs images via the img_url filter with a manual <img> tag, add the width and height attributes explicitly:

{% assign img_url = product.featured_image | img_url: '800x' %} <img src="{{ img_url }}" alt="{{ product.featured_image.alt | escape }}" width="{{ product.featured_image.width }}" height="{{ product.featured_image.height }}" loading="lazy">

Aspect Ratio Preservation for Responsive Product Images

Shopify themes often display product images in containers with CSS that overrides the declared dimensions. When CSS sets width: 100% on images, the declared height attribute is ignored unless the browser can derive the aspect ratio from both attributes. Modern browsers do this automatically, but older CSS in some themes uses a padding-based aspect ratio trick that conflicts with the native aspect ratio derivation.

The safest approach is to combine declared dimensions in HTML with CSS that respects the aspect ratio:

/* In theme.css or the relevant section stylesheet */ .product-image-wrapper img { width: 100%; height: auto; /* allows browser to use declared width/height for aspect-ratio */ display: block; }

Fix CLS Caused by Shopify Apps

Shopify apps are the second-largest source of CLS on most stores, and they are also the hardest to fix because the app code is not always accessible or modifiable. The first step is identifying which apps are contributing to shifts.

Identifying App-Related CLS

Use Chrome DevTools' Performance panel to record a page load and look at the Experience row for Layout Shift markers. Click each marker to see the source elements. App-injected elements are usually identifiable by their class names, which typically contain the app vendor's name or a recognizable app-specific prefix. Run the CLS checker on this site and look at the shift source selectors to identify which app is responsible.

Cookie Consent and Announcement Bar Apps

Apps that add announcement bars, cookie consent notices, or age verification overlays above the header are a major CLS source. These elements push the entire page down when they appear. Review the settings of any such app for an option to display the bar at a fixed position (overlaying content rather than displacing it), or to pre-render the bar in the theme layout at a fixed height so no shift occurs when the app script initializes.

If the app does not support fixed positioning, contact the app developer — this is a known CWV issue that reputable app developers have addressed in their products. As a workaround, add a CSS rule to make the bar fixed-position:

/* Force announcement bar to fixed position — adjust selectors to match your app */ .announcement-bar, [data-announcement-bar] { position: fixed !important; top: 0; left: 0; right: 0; z-index: 10000; } /* Push content down by the bar's height to prevent overlap */ body { padding-top: 40px; /* match the bar's height */ }

Chat Widgets and Support Apps

Live chat apps — Tidio, Gorgias, Re:amaze, Zendesk, Intercom, and similar — inject a launcher button into the page. Most modern implementations use position: fixed by default and do not cause CLS. However, if the chat widget is configured to appear inline in the page rather than as a fixed overlay, or if its script loads slowly and causes a late-appearing element, it can shift content.

Review your chat app's settings for a "floating" or "fixed position" option. If the widget cannot be configured to avoid CLS, consider loading the chat script only after user interaction — for example, after the user has scrolled 50% of the page. This delays the widget appearance to a point where the user is engaged enough that the shift has less impact on their experience, and the shift is less likely to count as CLS because it may occur after user input.

Upsell, Cross-Sell, and Dynamic Content Apps

Apps that inject upsell recommendations, recently viewed products, or "frequently bought together" sections after the initial page render can cause significant CLS on product pages. These apps typically insert a new section into the page flow after the JavaScript initializes, pushing other product page elements downward.

The fix is to ensure the app's container element is present in the initial HTML at a fixed height, even before the app script populates it with content. Many upsell apps support a placeholder or skeleton configuration — check the app's documentation for this option. Alternatively, place upsell sections below all other product page content (below the fold) where they are less likely to shift viewport-visible elements.

Fix CLS Caused by Theme Sliders and Carousels

Shopify homepage templates commonly feature hero sliders and product carousels that are significant sources of CLS. The slider container typically starts at zero height or an indeterminate height until the theme's JavaScript initializes and sets the final dimensions — at which point all content below the slider shifts.

Set a minimum height on the slider section in your theme's CSS, matching the height you want the slider to occupy. For Online Store 2.0 themes, you can do this in the theme editor under the section's style settings, or in the theme's assets/base.css file:

/* Hero slider — reserve height before JS initializes */ .slideshow, .hero-slider, [data-section-type="slideshow"] { min-height: 500px; /* match your configured slider height */ } /* For mobile, adjust proportionally */ @media (max-width: 768px) { .slideshow, .hero-slider { min-height: 280px; } }

Online Store 2.0 Themes and CLS

Shopify's Online Store 2.0 architecture (introduced in 2021) significantly improves CLS performance compared to older theme structures, primarily because OS2 themes use JSON templates and section rendering that makes it easier to output image dimensions correctly and control the rendering order of content.

If your store is running a legacy theme (one that does not use JSON templates), upgrading to a modern OS2 theme — such as Shopify's free Dawn theme or any OS2-compatible theme from the theme store — is likely the most impactful single action you can take for CLS improvement. OS2 themes are designed with Core Web Vitals in mind and typically output image dimensions correctly by default.

Dawn, Shopify's reference OS2 theme, consistently achieves CLS scores below 0.1 in Lighthouse testing on clean installations. If your store's CLS is significantly higher than 0.1 and you are on a legacy theme, the theme architecture itself may be the root cause rather than any specific element.

Verifying CLS Fixes on Shopify

After implementing changes, test the same pages you tested before: the homepage, a collection page, and a product page. Pay particular attention to the product page, since it is the most complex template in terms of the number of elements and app injections it typically receives.

Also test in an incognito or private browser window without any browser extensions active. Browser extensions — ad blockers, password managers, accessibility tools — can inject elements that affect your CLS measurement. Testing in incognito ensures you are measuring what your customers experience.

Track your fixes in Google Search Console's Core Web Vitals report over the following 28 days. Shopify stores with many product pages may see improvement appear gradually as Google re-crawls and re-evaluates the affected URL groups.

Test Your Shopify Store's CLS Score

Enter any Shopify page URL to get an instant CLS score, field data from real Chrome users, and a breakdown of the specific elements causing layout shifts.

Check My Shopify CLS

Related Resources