Page Speed Optimization at Scale: Fixing a Whole Catalog, Not Just the Homepage
Run PageSpeed Insights on any store owner's homepage and there's a decent chance it scores respectably — because that's the page everyone tests, so that's the page everyone fixes. Now test a product page three categories deep. That's where the 2.8MB gallery images live, the third-party review widget that blocks rendering, the layout that jumps when the price loads in. And that's the page your customers actually land on: for most stores, organic and paid traffic enters overwhelmingly through product and category pages, not the front door. Core Web Vitals are assessed on real visitor data across the site — Google groups similar pages and scores them by template — which means a fast homepage attached to a slow catalog still fails where it counts.
The numbers to hit haven't changed: LCP under 2.5 seconds, INP under 200 milliseconds, CLS under 0.1 — measured at the 75th percentile of real visits, mostly on mid-range phones over cellular. What changes at scale is the unit of work. You can't hand-tune a thousand pages. You fix the templates and the pipelines that all thousand pages flow through.
Think in templates, not pages
A catalog has maybe five page types that matter: home, category, product, cart, checkout. Every speed defect on a product page exists on every product page, because they're all the same template rendering different data. This is bad news and good news in equal measure — the debt is multiplied by the catalog size, but so is every fix. Our approach starts by pulling field data per template group from the Search Console Core Web Vitals report: which page groups fail, on which metric, on which device. A store failing LCP on mobile product pages and CLS on category pages has two different projects, and knowing that before touching anything is the difference between a targeted fix and a month of guessing. The full metric breakdown is in our Core Web Vitals guide; this is how the repair work scales.
LCP: the image pipeline is the whole game
On product and category templates, the LCP element is almost always an image — the main product photo or the first row of category thumbnails. Fixing it once per page is hopeless; fixing the pipeline fixes the catalog:
- Format at the source. Every catalog image converted to WebP or AVIF — typically 30–40% smaller than the JPEG it replaces at identical visual quality. On a 1,000-product catalog with five gallery images each, that's five thousand conversions, which is exactly why it never gets done by hand-picking pages.
- Dimensions matched to display. A 2400-pixel original squeezed into a 700-pixel slot wastes most of its bytes. The template should request the rendered size, and the pipeline should serve it — CDN-resized on BigCommerce, generated sizes on WordPress, and in both cases verified against what the template actually asks for, because a misconfigured theme happily requests the original.
- Priority for the LCP image, lazy loading for everything else. The main product photo must never be lazy-loaded — delaying the LCP element is self-sabotage — while every below-the-fold gallery image, related-product thumbnail, and footer badge should be. Stores routinely have this exactly backwards.
- Server response as the floor. LCP can't beat the time-to-first-byte it sits on. Cheap shared hosting that takes 800ms to start responding caps every template on the site, and no image work claws that back.
CLS: reserve space for everything dynamic
Layout shift on catalog templates comes from a short, predictable list: images without width and height attributes, web fonts swapping in late and reflowing product titles, and content injected after load — sale banners, cookie notices, the review-count line that pops in above the price and shoves the buy button down. The fixes are template-level: explicit dimensions on every image slot, font preloading with a matched fallback so the swap doesn't reflow, and fixed-size containers reserved for anything that loads late. One template edit, a thousand pages stop jumping.
INP: the third-party tax
Interaction delay on stores is dominated by script weight — and most of it is third-party. Review widgets, chat bubbles, heatmaps, three generations of analytics tags, a pixel for a campaign that ended last year: each one costs 200–500ms of main-thread work, and they accumulate silently because each was added one at a time and none was ever removed. The scale fix is an audit with teeth: inventory every third-party script, attribute its cost, and make each one justify its quarter-second tax on every page load, on every page, forever. What survives gets deferred so it loads after the page is interactive. Render-blocking CSS and JavaScript from the theme itself gets the same treatment — critical styles inlined, the rest loaded without blocking first paint. This is usually the least glamorous and most contested part of the work, because every script has an internal owner who insists it's essential. The field data settles the argument.
Verify on field data, then hold the line
Lab tests confirm a fix works mechanically; only field data confirms it worked for customers. After a catalog-wide pass, the Search Console groups take a few weeks of real visits to reflect the change — LCP improvements show first, CLS follows as the 28-day window rolls over. And the gains decay without a hold: every new app, widget, and banner added over the following year erodes them, which is why re-measuring monthly is part of the job, not an afterthought. The revenue math for why this is worth doing at all — the 7%-per-second conversion cost of delay — is laid out in our piece on speed and conversion, and it applies with most force on exactly the catalog pages nobody tests.
Our team runs the full catalog pass — template-level triage from field data, the image pipeline, layout stabilization, and the script audit — as one performance engagement, alongside the technical SEO work that speed depends on. The homepage was never the problem. Fix the templates and the whole store gets fast at once.