← Blog

E-commerce

Shopify LCP killers: a field guide to the slow seven

You open PageSpeed Insights at midnight, the product page hits 4.2s LCP, and the theme isn't the culprit. The seven apps you installed last quarter are.

Jacob Molkenboer· Founder · A Brand New Company· 4 Jun 2026· 7 min
Half-unwrapped craft parcel with seven twine knots, brass postal scale, green wax seal, red stamp on ivory desk.

Where the 1.8 seconds hides

You open PageSpeed Insights at midnight, the product page hits 4.2s LCP, and Dawn isn't the culprit. The hero image is fine. The fonts are preloaded. The seven Shopify apps you installed last quarter, each one promising "minimal impact on store speed" on its app-store listing, are collectively a second and a half of third-party JavaScript fighting for the main thread.

This is a field guide to the usual offenders. The numbers below come from real audits we have run on real stores on throttled 4G, on the product page that actually matters (the one your ads point to). Your mileage will vary by theme and app version, but the shape is consistent across every Shopify store we've looked at since 2024.

Largest Contentful Paint is the moment the largest above-the-fold element finishes painting. On a typical Shopify product page that element is the product image. Every script that contends for the main thread before that image decodes is taxing your LCP, even if the script itself loaded asynchronously. Async means non-render-blocking. It does not mean free.

The review widget

Judge.me, Loox, Yotpo. Pick your poison. Star ratings near the product title are above-the-fold revenue, so the widget has every incentive to render synchronously. Loox in particular ships its own font, its own carousel library, and a poll loop that scans the DOM for review hooks every 250ms until it finds them.

Typical LCP cost we see in audits: 200ms to 400ms. The fix is rarely "uninstall". It is usually one of three things:

  • Replace the live widget with server-rendered star markup that the app hydrates after LCP.
  • Move the photo-review carousel below the fold so it doesn't compete for paint.
  • Use the app's Theme App Extension block instead of its legacy ScriptTag injection, which gives you control over placement and timing.

The currency and geolocation switcher

If you sell internationally and you still use a third-party currency app (anything other than Shopify Markets), this one will bite you. The pattern is predictable: the app fetches the visitor's IP, hits its own geolocation API, then re-renders every price on the page. That's a layout shift you'll see in CLS plus a render-blocker you'll see in LCP.

Shopify Markets made most of these apps redundant. Markets handles currency through the storefront API and Shopify's CDN with no extra client script. If you migrated to Markets last year and forgot to uninstall the old converter, you're paying for both.

The email pop-up

Privy, Klaviyo Forms, Justuno. The pop-up shows after seven seconds, so you might think it can't affect LCP. It can. The library ships on load. It parses your A/B test config. It sets up event listeners on every clickable element on the page. Klaviyo's onsite forms bundle alone is around 90KB gzipped before any of your form code runs.

Warning

An "async" pop-up script still executes on the main thread once it arrives. The reason your LCP fires later isn't that the script blocked the parser. It's that the script blocked the renderer the moment it started running, around the same time your hero image was trying to decode.

The chat bubble

Tidio, Gorgias Chat, Shopify Inbox, Tawk.to. The chat bubble is, in our experience, the single biggest third-party cost on most Shopify pages. The widget loads, opens a websocket, registers service workers, and on some stacks loads a second iframe for the actual chat surface.

If you're not answering chats within five minutes during business hours, the bubble is costing you LCP and converting nothing. We have moved several clients to a static contact form for off-hours, with the chat widget lazy-loaded only on the contact page itself. LCP recovered 300ms to 500ms on every other page in the store, including the product pages the ads actually pointed to.

The cart drawer and upsell engine

ReConvert, Bold Upsell, Honeycomb. These apps inject a cart drawer and an upsell modal on every page, not just the cart. The drawer's CSS is render-blocking. The modal's product feed is fetched on page load so it's "ready" the instant the visitor adds something to the cart.

None of that needs to be ready before LCP fires. A modern cart drawer can be lazy-loaded the instant the visitor clicks "add to cart". The 200ms to 300ms you save up front is yours to keep on every page view that doesn't end in a conversion, which is most of them.

The page builder

PageFly, Shogun, GemPages. Page builders solve a genuinely hard problem: the marketing team wants to ship landing pages without touching Liquid. They also nest the entire builder runtime into every page they generate. A PageFly homepage routinely ships 600KB of builder-specific CSS and JS before any of your content arrives.

The shift to Theme App Extensions plus Shopify's section-rendering API means most page-builder use cases can be served by native sections now. If your landing pages all share the same skeleton (hero, three columns, video, CTA) you don't need a builder. You need three Liquid sections and a Slack thread with your developer.

The trust strip and countdown bar

The "Free Shipping / 30-Day Returns / Only 3 Left!" strip. Usually a 30KB widget for what could be three Liquid spans and a CSS animation. The countdown timer reads inventory via AJAX on page load, which means an extra round-trip before LCP can paint if the strip lives above the hero.

If you have to keep a third-party trust strip, put it below the fold. The visitor will see it before they scroll past it. They do not need it during the initial paint.

The 30-minute audit you can run today

Start by pulling every ScriptTag your store has injected. Most merchants are surprised to find apps they uninstalled months ago still injecting scripts, because uninstall sometimes leaves ScriptTags orphaned and Shopify's app cleanup is the app developer's responsibility, not Shopify's.

curl -s "https://yourstore.myshopify.com/admin/api/2024-04/script_tags.json" \
  -H "X-Shopify-Access-Token: $TOKEN" | jq '.script_tags[] | {id, src, event}'

You'll get a list like this:

[
  {"id": 81923, "src": "https://cdn.judge.me/widget.js", "event": "onload"},
  {"id": 81924, "src": "https://static.klaviyo.com/onsite/js/klaviyo.js", "event": "onload"},
  {"id": 81925, "src": "https://app.tidio.co/talk.js", "event": "onload"}
]

Cross-reference against your installed apps. Anything that doesn't match a currently installed app is an orphan. Delete it through the same endpoint (DELETE /script_tags/{id}.json). Shopify's ScriptTag API docs cover the auth, pagination, and the response codes you'll want to handle.

Then run Lighthouse against your highest-traffic product page (the one ads point to, not the homepage) with the network throttled to the connection your visitors actually use:

npx lighthouse https://yourstore.com/products/$YOUR_TOP_SKU \
  --only-categories=performance \
  --throttling-method=simulate \
  --form-factor=mobile \
  --output=json --output-path=./before.json

Uninstall one app. Re-run. Diff the LCP number. Repeat. You will be done by lunch and you will know which of the seven apps you are paying for, in seconds, every time a visitor lands on a product page.

When we rebuilt the Shopify front-end for HorizonCanvasCo earlier this year, the thing we ran into was that three of the seven apps on this list were technically uninstalled but still injecting scripts via orphaned ScriptTags. We solved it the way you would: API call, list, delete, retest. It's the kind of operations cleanup our web work usually starts with before any new design touches the storefront.

Key takeaway

Shopify LCP problems are rarely the theme. They're seven small apps each adding 200ms above the fold, often including orphans from apps you already uninstalled.

FAQ

Does uninstalling a Shopify app remove its ScriptTags?

Usually but not always. Some apps clean up on uninstall, others leave ScriptTag entries orphaned. Check the admin API and delete any that don't match a currently installed app.

Is Shopify Markets enough to replace a third-party currency converter?

For most stores, yes. Markets handles currency, geolocation, and tax via Shopify's CDN with no extra client script. The third-party app is usually redundant after migration and just adds load time.

Will lazy-loading the chat widget hurt support response time?

Only if your team actually answers chats within minutes during business hours. If you don't, lazy-loading the bubble onto the contact page recovers LCP everywhere else with no measurable conversion loss.

Why does an async script still affect LCP?

Async means non-render-blocking at load time. Once the script arrives and executes, it occupies the main thread, which is the same thread that decodes your hero image. The contention shows up in your LCP number.

e-commerceoperationsarchitectureseotooling

Building something?

Start a project