Booking 2 new partners for Q3 — strategy calls open this week.
← All insights

Performance

How we shaved 1.6s off LCP on a 40k-product Shopify Plus store

Six weeks, two sprints, and a methodical impact-by-effort prioritization that beat the conventional 'ship a CDN and pray' approach. Here's exactly what moved.

April 22, 2026·11 min·By The founder

Performance work on Shopify is usually presented as a list of "tips" — install a CDN, lazy-load images, defer your scripts. Most of those tips are correct. None of them are the work.

The work is figuring out which of the 40 things you could do will actually move LCP for your store, in priority order, before you waste a sprint on the wrong thing. Here's how that played out on a recent engagement.

The starting point

A 40,000-product Plus store. Beautiful design. Mobile LCP at 4.1s on a mid-tier Android over LTE in the Gulf — their fastest-growing market. Lighthouse mobile score of 41. RUM showed the slowest 25% of sessions in the region were closer to 6.8s.

The previous agency had delivered a polished theme. The implementation was carrying:

  • 14 third-party scripts loaded synchronously
  • An unoptimized hero image at 1.4MB
  • A Liquid template doing 11 product lookups per page render
  • A font loader with 9 weights preloaded
  • Two duplicate marketing pixels that nobody owned

Step 1: Don't sprint yet. Audit.

We spent two days on the audit. Not benchmarking on a MacBook — benchmarking on actual mid-tier Androids over LTE in the regions that mattered. RUM data from DebugBear over the previous 30 days. Search Console for crawl-time signals. A chrome://tracing capture of the slowest PDP we could find.

The output: every issue ranked by impact × effort. Not impact alone. Not effort alone. The product.

The top 5 issues accounted for 78% of the available improvement. Everything below that was diminishing returns we'd come back to in a quarterly tune-up.

Step 2: Sprint 1 — the obvious wins

Here's what we shipped in two weeks, in priority order:

Hero image pipeline rebuilt — -1.0s LCP

The hero was a single 1.4MB JPEG, served at full size to mobile. We rebuilt the pipeline using srcset + Cloudflare Image Resizing, returning device-appropriate AVIF or WebP, with 384/768/1280/1920 widths and a sensible sizes attribute.

The hero now ships ~85KB on mobile vs 1.4MB. That single change gave us a full second of LCP on its own.

Render-blocking JS removed — -300ms TBT

GTM was loading inline at the top of the head. Six tags inside it were configured to fire on window.load. The browser was parsing all of that before doing useful work.

We moved GTM to fire on user interaction with a fallback at 3s, audited the tags inside it, and gave each one a custom trigger. The marketing team agreed to drop two pixels that hadn't fired meaningfully in 90 days.

Liquid query budget enforced — -180ms TTFB

The PLP template was making 11 product lookups per render — most of them N+1 patterns hidden in section files that had been added incrementally over years. We profiled the template, eliminated 8 redundant lookups by passing data through section settings, and added a comment in the theme runbook flagging the pattern.

TTFB on PLP went from 720ms to 540ms.

Font loading optimized — -120ms first paint

font-display: swap. Preload only weight 400. The other 8 weights load on demand. Variable fonts where we could.

Small win on its own. Cumulative across the page, ~120ms.

End of sprint 1: LCP 2.5s. Mobile Lighthouse 84. We agreed on a sprint 2 if the partner wanted to chase the rest.

Step 3: Sprint 2 — the harder wins

PDP fold prioritization — -250ms LCP

The PDP review carousel was loading above the fold visually, but its JS was render-blocking the main image. We moved it logically below the fold, deferred its JS until intersection, and let the main image win the LCP race.

Critical CSS budget

Inline critical CSS for above-the-fold styles, async-load the rest. Standard, but we measured the budget per template type — PDP, PLP, cart, account — and tuned each.

Marketing tag triage round 2

Two more tags came off. The growth team and marketing lead agreed in a 45-min call that they weren't earning their weight. This is the work that's hardest in agencies that don't talk to growth — most performance work dies because nobody has the political capital to remove tags.

Lighthouse CI added to the PR pipeline

Performance only stays good if you protect it. We added Lighthouse CI to their GitHub Actions pipeline, with budgets per template that block PRs which regress more than 5% on key metrics.

End of sprint 2: LCP 1.5s. Mobile Lighthouse 98. CLS effectively zero. INP under 200ms p95.

What changed in conversion

Six weeks after kickoff:

  • Mobile CVR: +47% (statistically significant at p < 0.01 over a 4-week window)
  • Bounce rate on PDP: -22%
  • Add-to-cart rate: +18%

Were all of those gains from the perf work? Probably not all of them — some design tweaks shipped in the same window. But the magnitude is in line with what Google's research predicts for that LCP delta, and they all moved together.

What I'd tell another agency doing this work

  1. Audit on real devices, in real regions. A MacBook on fiber is not your customer.
  2. Prioritize impact × effort, not impact alone. The 4-hour wins are usually the right place to start.
  3. Talk to growth. Half the performance work in a typical Plus store is removing marketing tags that nobody on the dev team has authority to remove.
  4. Protect the gains in CI. Lighthouse budgets in PR checks are the difference between a sprint and a permanent improvement.
  5. Report in numbers, not vibes. Before, after, and quarterly. If you can't show the delta, the work didn't happen.

Take the call

Stop renting Shopify help.
Hire a partner.

30-minute strategy call. Founder on the line. We'll dig into your stack, your goals, and whether we're the right team — no high-pressure sales pitch.