Updated
A diagnostic-first approach to store speed: which apps cost most, how to fix LCP and INP on themes you cannot control, and what scores hide.
Shopify speed optimization starts by measuring the slow page and interaction. Images, app scripts, render-blocking resources and theme code can each be the main bottleneck. A performance trace should determine the order of work; no fixed time saving applies to every store.
This is a diagnostic sequence rather than a checklist, because the order in which you look determines whether you find the real cost.
Use the current Shopify web performance report
Shopify provides web performance reporting around Core Web Vitals. Older guidance focused on a single Lighthouse store score; use the current report and distinguish real-user measurements from lab diagnostics.
For page-experience diagnostics, inspect Core Web Vitals from real users, including the Chrome User Experience Report. Lab scores describe a particular synthetic test; field measurements reflect visitors, devices and connections over a reporting period. The two can disagree without either measurement being broken.
Work from field data. In Search Console, the Core Web Vitals report shows real-user LCP, INP, and CLS. That is the measurement that matters. Lab tools are for diagnosis; field data is for judgement.
The thresholds:
LCP (Largest Contentful Paint) good <= 2.5s
INP (Interaction to Next Paint) good <= 200ms
CLS (Cumulative Layout Shift) good <= 0.1You need the 75th percentile to pass, not the median. Optimising for your own fast laptop on office wifi is how stores end up failing while looking fine locally.
Measure app scripts alongside theme code
Third-party apps are a useful investigation target because their code and network requests may be outside the theme developer's control. Confirm their contribution from the store's trace before removing a feature.
Check where each app actually loads. An app embed may run on templates where its feature is unused, while other integrations are scoped to particular blocks or surfaces. Checkout has separate extension constraints, so do not assume a storefront script also runs there.
Audit properly. Open Chrome DevTools, load a product page, and inspect JavaScript transfer sizes in Network. Then use Coverage while exercising variant selection, cart updates and relevant widgets. Unused code during initial load may support a later interaction; remove it only after checking those paths.
For each app, answer three questions:
Does it need to load on *this* page type, or only on some?
Does it need to load before first paint, or can it defer until interaction?
Is it earning its cost? An app adding 400ms to every page view to display badges is a measurable revenue trade, not a free feature.
Uninstalling is not enough. Shopify apps frequently leave theme code behind — script tags, snippets, and Liquid includes that persist and continue loading against endpoints that may no longer respond. After removing an app, search your theme for its handle and remove the residue manually.
LCP: usually the hero image, sometimes the font
On collection and product pages the LCP element is nearly always the main image. Three things dominate it:
Discovery time. If the image is loaded by JavaScript — a slider, a lazy-load library — the browser cannot begin fetching until that script parses and runs. Preloading the LCP image in the document head fixes this:
{%- if template.name == 'product' -%}
<link rel="preload" as="image"
href="{{ product.featured_image | image_url: width: 800 }}"
imagesrcset="{{ product.featured_image | image_url: width: 400 }} 400w,
{{ product.featured_image | image_url: width: 800 }} 800w"
imagesizes="(max-width: 768px) 100vw, 50vw">
{%- endif -%}Never lazy-load the LCP image. loading="lazy" on an above-the-fold hero delays it by design. Lazy-load everything below the fold; eager-load what is visible immediately.
Font blocking. If the LCP element is text, a webfont without font-display: swap blocks rendering until the font arrives. Shopify serves fonts from its CDN reasonably, but custom fonts added via theme code frequently lack the directive.
INP: the metric that replaced FID
Interaction to Next Paint measures responsiveness across the whole session, not just the first interaction. It is stricter than FID was, and many stores that passed FID comfortably fail INP.
The dominant cause is main-thread congestion from app scripts. When a visitor taps "add to cart" and the main thread is busy executing a personalisation script, the interaction waits.
Practical fixes:
Defer non-critical scripts. Anything not needed for initial render gets
defer, or loads on first interaction.Break up long tasks. Any task over 50ms blocks interaction. In DevTools Performance, long tasks appear with red corners.
Reduce event handler work. Handlers doing layout reads and writes in sequence force synchronous reflow.
Subscribe to fewer scroll and resize events, and throttle those you keep.
Attribute long tasks to the actual script and interaction. Theme code, third-party integrations and the amount of DOM work can all affect responsiveness.
CLS: usually cheap to fix
Layout shift comes from a small set of causes, all straightforward:
Images without dimensions. Always set width and height, or an aspect ratio, so the browser reserves space:
<img src="{{ image | image_url: width: 800 }}"
width="{{ image.width }}"
height="{{ image.height }}"
alt="{{ image.alt | escape }}"
loading="lazy">Injected banners. Announcement bars, cookie notices, and promotional strips inserted after paint push content down. Reserve their space in the initial layout or position them so they do not displace content.
Webfont swap. A fallback font with substantially different metrics causes reflow when the webfont loads. size-adjust and ascent-override in the @font-face declaration reduce this considerably.
The theme itself
Some themes are simply heavy — extensive section options, large bundled JavaScript, multiple carousel libraries. If the theme is the constraint, no amount of app pruning rescues it.
Signals that the theme is the problem: over 300KB of theme JavaScript before apps, multiple animation libraries, or a bundled jQuery still in use.
Migrating themes is disruptive and sometimes correct. An Online Store 2.0 theme built for performance, with apps reinstalled deliberately rather than restored wholesale, often produces a larger improvement than months of incremental tuning.
What to expect
Record the result of each isolated change in a repeatable test:
Change Evidence to compare
App script removal Transfer size, long tasks, cart functionality
LCP discovery/eager loading Request start time and LCP
Script deferral Interaction trace and feature availability
Reserved image/banner space Layout-shift entries and CLS
Image sizing/compression Download size, image quality and LCPPrioritise changes by measured contribution and business impact. Keep the same device, network, consent state and page content when comparing runs, then confirm cart behaviour and analytics still work after deployment.
Measure product journeys beyond the landing page
A quick homepage does not establish a quick shopping journey. Sample collection filtering, variant selection, add-to-cart, and account or checkout transitions on real mobile conditions. Record which app or theme change was deployed so changes in the field report can be interpreted against release history.
For stores serving Pakistan and overseas customers, compare device and network segments where enough data exists. A single global average can hide a problematic market. When field data is sparse, use a repeatable lab profile for diagnosis and state that it is a synthetic test rather than a user-population result.
Record the slow interaction and its long tasks.
Check the LCP element on each template.
Keep consent behavior consistent between tests.
Verify analytics and cart behavior after script removal.
Frequently asked questions
Why is my Shopify store slow despite a good speed score? A lab score and real-user measurements answer different questions. Inspect the current Shopify web performance report and Search Console data by page type and device; a good score does not guarantee rankings or conversions.
Which apps hurt performance most? Anything injecting scripts on every page regardless of use — popups, currency converters, review widgets, personalisation tools, and live chat. Audit with Chrome DevTools Coverage to see what proportion of each script actually executes.
Does uninstalling an app remove its code? Frequently not. Apps leave script tags and theme snippets behind. After uninstalling, search your theme files for the app's handle and remove the remnants manually.
Should I go headless for speed? Rarely for that reason alone. A tuned standard theme with disciplined app usage performs excellently. Headless adds substantial engineering commitment and is justified by custom UX requirements, not by page speed.
How long until Core Web Vitals improve in Search Console? Field reporting uses a rolling collection window, commonly 28 days for CrUX-based reports. New observations replace older ones over time, and pages with insufficient traffic may have no field result. Lab tests can verify a change sooner but do not establish that real-user Core Web Vitals have passed.
Further reading
Related
Written by
Moueen Togarvi
Founder & CEO at Voquarn Code, focused on product engineering, search growth, and practical AI systems.
