
Almost every slow website we are asked to look at has already had performance work done on it. Images were compressed, a CDN was added, something was lazy-loaded. The site is still slow, and the team has concluded that it is simply a heavy site.
It usually is not. The work targeted a layer that was not the bottleneck.
Measure the thing users feel
A synthetic score is a proxy. What a visitor experiences is the time until the page shows the thing they came for, and the time until it responds to being touched. Optimising a score without moving those two numbers is common and pointless.
The order that works
- Server response. If the document takes 800ms to arrive, nothing downstream can rescue it. Measure this first, on a cold cache, from the region your users are in.
- Render-blocking resources. Every synchronous stylesheet and script in the head is a gate. Count them before you optimise any of them.
- The largest element. Usually a hero image or a webfont-dependent headline. Fix its loading, priority and dimensions.
- JavaScript cost. Not bundle size — execution time on a mid-range device, which is where most of your traffic is.
- Layout stability. Reserved space for images, ads and embeds. Cheap to fix, disproportionately annoying when wrong.
Work the list in order and stop when the number moves. Teams that start at step four because it is the interesting one usually spend a sprint to gain nothing.
The unglamorous wins
In our experience the largest single improvement is rarely a code change. It is caching something that was being recomputed per request, or an image that was 4000px wide being served into a 600px slot, or a third-party tag nobody could name loading synchronously in the head.
Keeping it
Performance regresses silently because no one is watching. Add a budget to the build, measure on real devices, and treat a regression the way you would treat a failing test.




