Prismic Page Audit Free online audit tool
Home › Notes › Why every platform's pages score badly on PageSpeed — and why "score" is the wrong thing to look at

Why every platform's pages score badly on PageSpeed — and why "score" is the wrong thing to look at

I've spent the last few years doing performance work on Next.js, Prismic, Shopify and WordPress builds. This is what I've learned about why the numbers refuse to agree — and which ones I actually report.


#The question I get on almost every project

A client once asked me: "why are our scores so low?"

The site felt fast. It looked fast. My own Lighthouse run on my laptop said 98.

PageSpeed Insights said 71.

Neither number is wrong. But two things nobody had told them:

  1. Those two tools do not measure the same thing.
  2. The score is not a property of their site. It's a reading — taken on one machine, on one network, at one moment.

That second point is the one I now lead with.


#1. What you are actually measuring

Local Chrome Lighthouse and PageSpeed Insights differ in four ways at once:

  • Network. Local: your broadband, often partly cached. PageSpeed: fixed Slow 4G.
  • CPU. Local: your own machine. PageSpeed: 4× CPU throttling.
  • Cache. Local: easy to keep warm. PageSpeed: cold start, every run.
  • Geography. Local: usually close to the CDN. PageSpeed: Google's lab → your host, so worse TTFB.

Same page, 98 and 71. The gap isn't a bug in either tool — it's four variables changing together, and only one of them is your code.

What I do: when I report a number, I say which tool and which profile produced it. A number without that context isn't information.


#2. Three ways I've watched people measure it wrong

Testing the dev server. npm run dev is uncompressed and running a hot-reload loop. I have seen a mobile score around 52 on a page that sits in the 80s in production. That's not a baseline, it's noise.

Testing in a browser you've already visited. Your cache is absorbing costs your visitors will pay. Incognito, cache disabled — or don't trust the result.

Testing a deployment that's already been replaced. You fixed the code, but the URL you tested is the previous build. This happens constantly with preview deploys.

What I do: before I touch anything, I write down the tool, the profile, the URL and the build. Half of all "performance regressions" I've been asked to fix turned out to be one of these three.


#3. Why every platform fails

I work across four stacks, and they break in different ways. But they share one root cause:

Each of these platforms lets code you did not write run on your critical path.

Shopify — third parties dominate the score. On a Shopify store the theme is rarely the problem. Booking apps, review widgets, chat, heatmaps, pixels — they inject at runtime and they own the main thread.

Here is the clearest example I have. A booking app pulled jQuery from a Google CDN. On a weak connection that request was slow or failed outright, and the button sat on "Loading…" forever. The fix wasn't in the app. It was in the theme:

  • self-host jQuery in the theme and load it early on product templates
  • preconnect to the app's CDN
  • disable the sticky add-to-cart that was covering the modal on mobile
  • fix the modal's z-index and mobile scroll lock

And the reproduction mattered more than the fix: that missing button only appeared when you navigated from a collection page into a product page on a weak network. Testing the collection page alone proves nothing.

What I do: on Shopify I test the page where the script actually injects — not the page that's convenient.

WordPress — plugin sprawl. Email, gift cards, forms, payments: each brings its own front-end JavaScript and CSS, and the stack adds up faster than anyone expects. Caching is a trap too — logged-in, cart and checkout pages usually bypass it, so I measure both states and say which one I'm reporting.

Next.js and content sites — three repeat offenders. The same asset downloaded twice (a mobile-only and a desktop-only <img> of the same file); a CSS background-image that only becomes discoverable after the stylesheet parses; too much JavaScript in the first-load packet.

What I do: on content sites I ask one question first — is the LCP element discoverable in the initial HTML? In most of my slowest cases, it wasn't.


#4. Where the points actually are

Approximate Lighthouse 10 performance weights:

  • TBT — about 30%. The main thread is blocked by long tasks.
  • LCP — about 25%. The largest element paints late.
  • CLS — about 25%. The layout jumps.
  • FCP — about 10%. First contentful paint.
  • SI — about 10%. Visual completeness.

TBT plus LCP is more than half the score. When I'm asked to "fix performance", I work on those two and I say so out loud. Spending a week on FCP and Speed Index is working on 20% of the problem.

And I do it on mobile. Desktop scores look fine and hide all of it.


#5. Two things that still surprise people

A solid background colour is not FCP. First Contentful Paint needs actual content — text, an image, a gradient, an SVG. Paint a page with one background colour and it has no first contentful paint at all, however good it looks.

font-display: optional can win you CLS and LCP — on a fast connection. On a slow one, the entire visit stays in the fallback font. To the client that isn't a trade-off I chose; it looks like a bug.


#6. The uncomfortable part I now say early

Here is a real chain from one project, in order:

  • Local broadband Lighthouse: up to 98
  • PageSpeed Insights, mobile: 71–75
  • Temporary image downsizing: ~91 — rejected by the client as blurry
  • High-quality imagery restored: settled at 82–85

So I say this at the start of the project now:

With "no quality loss, no structural change" as a hard requirement, a mobile score rarely locks at 90.

Something has to give: bytes, motion, or images. My job is to tell you which one I'd give up and what it costs. If nobody agrees on that, we will argue about the score forever — and the score is the one number that depends on the machine it was measured on.


#7. What I report instead

I stopped treating the score as the goal. It's an environment-dependent reading.

Page weight and LCP are properties of the page itself. They travel. They are the same whether Google or I run the test. So those are what I measure, and I show before and after, taken back to back on the same machine.

A score tells you how one machine on one network felt about your page.

Page weight and LCP tell you what your page actually is.


#8. Three checks you can run yourself

  1. DevTools → Network → Img, then reload. Find the largest image. Compare the file's real width with the size it's displayed at. If the file is 2–3× bigger than the slot, that's your first win — and it's usually the cheapest one.
  2. Run Lighthouse mobile three times and report the median. Never a single run. A single run is a coin flip.
  3. Search your HTML for two <img> tags pointing at the same file. That's a duplicate download, and it costs nothing to fix.

#The one-line version

Measure production, not your dev server. Make the LCP element discoverable and single-request. Keep first-load JavaScript and fonts off the critical path. Remember a solid colour isn't FCP. Test Shopify apps on the page they actually load on. And agree the quality trade-off before you promise anyone a number.


I build and fix content-driven front-ends — Next.js, Prismic, Shopify and WordPress — and I measure the result instead of asserting it. If you want to know whether your site is actually slow, or just being measured badly, run it through prismicaudit.com and send me what it finds.