In short
The site you are reading went from 73 to 99 on mobile PageSpeed in one night. Six fixes were applied, each measured on its own. Two changed nothing and were removed. That is the part nobody writes about, and the one worth your time: without a measurement before and after, those two changes would still be in place today, costing something for nothing.
And once the work was done, two runs of the same tool, on the same site, one minute apart, with not a single line changed in between, returned 96 and then 100.
The starting point, and what it already said
Starting score: 73. The usual reflex is to read that number and ask what to optimise. The right reflex is to open the breakdown, because it names the culprit before you touch anything.
| Metric | Value | What it says |
|---|---|---|
| Total blocking time | 0 ms | JavaScript is not the problem |
| Layout stability | 0.004 | Nothing jumps on screen |
| Largest contentful paint | 3.7 s | Here is the whole problem |
| Speed index | 10.1 s | And it is severe |
Two perfect metrics, two disastrous ones. The reading is immediate: the site was not computing too much, it was waiting. Any JavaScript optimisation would have been wasted effort on a site already faultless in that department. That is the first lesson, and it is free: you do not fix the score, you fix its components.
The four fixes that paid off
1. Fonts were blocking the display
The theme loaded its two typefaces from Google’s font service. A widespread practice, and long recommended. The measured cost here: 2,070 ms of estimated blocking, because the browser has to open two extra connections to two external domains before it knows which typeface to write with.
The files were moved onto the site’s own domain and preloaded in the head. On their own, they were the most expensive item in the entire audit.
2. No expiry headers at all
The home page’s seven static files, stylesheets, scripts and images, were fetched from the server on every visit. Not one carried a caching instruction. A visitor coming back the next day downloaded the whole site again.
Three lines of server configuration settled it. It is the least spectacular fix on the list, and probably the one that helps real visitors most, since they do not discover the site afresh on every page.
3. Weight for nothing
| Item | Before | After |
|---|---|---|
| Logo | 23.7 KB, a 1,819 px image displayed at 173 px | 4.8 KB |
| Site icon | 21.9 KB to display 32 pixels | 2.5 KB |
| Emoji detection | 6.7 KB on every page | removed |
The logo is the textbook case: a file 1,819 pixels wide served for a 173 pixel display. Nobody had spotted it because nothing breaks. The page renders, the logo is crisp, and the browser downloads ten times what it needs. The site icon tells the same story: the original file was declared as is for all three sizes browsers ask for, because its smaller versions had never been generated.
4. Contrast, which is not a performance topic
Since we were measuring anyway, the accessibility tab sat at 96. Five elements fell below the minimum contrast ratio: a call to action button in white on the brand colour, at 3.96 to 1 where the rule asks for 4.5, plus four footer mentions. Ratios calculated, not judged by eye.
A slightly darker button background and two opacity values raised: accessibility at 100, without the brand colour moving anywhere else on the site.
The trap only measurement could find
This one deserves its own section, because no visual audit would have caught it.
After the fonts were brought in house, the report still flagged a 14.5 KB file downloaded on the critical path. An extended character set, the one that serves Central European languages, on a French and English site. The real cause, found by comparing the declarations one by one: in the original stylesheet, the basic Latin declaration comes after the extended one. Rewriting them had flipped that order.
The two character ranges overlap, and when two declarations cover the same character, the last one wins. The result: the browser downloaded 14.5 KB of extra font to render a single character, the “oe” ligature in a French phrase, while the already preloaded file contained it.
One optimisation can create another. The only way to know is to measure again after each change, not at the end.
The two fixes that did nothing
Here is the part case studies leave out.
First false good idea: the consent banner animation. It covers 40 % of the screen on mobile and appears with a 350 ms animation. The hypothesis held up: until it settles, the screen is not stable, so the perceived display metric suffers. The animation was disabled and two measurements followed. Result: no change, to within a tenth of a second. Removed.
Second false good idea: inlining the stylesheets into the page. That is the standard recommendation when a tool flags render blocking requests. It was implemented properly and measured four times. The stylesheets did leave the render blocking list, the warning disappeared from the report, and no metric moved: first contentful paint, largest element, perceived speed, all identical.
In exchange, every page carried 17.5 KB more, since the stylesheet was no longer cached from one page to the next. On a site where people read several articles in a row, that is the wrong side of the trade. Removed as well.
Those two changes had three things in common: a tool recommended them, they sounded logical, and they were useless on this particular site. Without a measurement framing each move, they would still be in place, costing bandwidth and maintenance debt for no benefit.
What the score does not tell you
Once the work was finished, four consecutive runs on the same site, with nothing changed between them:
| Run | Score | Speed index |
|---|---|---|
| 1 | 100 | 1.5 s |
| 2 | 97 | 4.2 s |
| 3 | 99 | 1.8 s |
| 4 | 97 | 4.2 s |
Same page, same minute, same code. The gap comes from a two second display stall that shows up on some runs and not others, with a strictly identical network profile. It is not the server, it is not the files: the measurement itself hesitates. The same trap lives elsewhere in your dashboards: a number that appears without an error is not necessarily a correct number.
The practical conclusion, and it applies to your site as much as to ours: a single run proves nothing. Re-running the tool until you get the number you wanted is an exercise in self persuasion. What counts is the median of several runs, and above all what your real visitors experience.
The method, applicable this week
- Measure before touching anything, and keep the record. Without a written starting point, you will never know whether you improved or degraded.
- Read the breakdown, not the score. Five metrics make up the number. Two can be perfect while the other three sink. They are not fixed the same way.
- One change at a time, one measurement after each. Three fixes applied together give an uninterpretable result: no way to tell which one paid off, or which one hurt.
- Remove whatever does not show up in the numbers. An optimisation with no measurable effect is not neutral: it is extra code to understand and maintain, forever.
- Aim at the visitor, not the score. Some fixes earn no points and change everything for someone on an entry level phone. In our case, an animation looping endlessly in the background was dividing the processor’s workload by three, for a single point of score. Speed is only one of the frictions that cost conversions, and the others are often more profitable to fix.
This week’s self diagnosis, with no tool and no developer: open PageSpeed Insights on your home page, run it three times in a row, and write down the three scores. If the spread exceeds two points, you already know the number you have been watching did not deserve that attention. Then open the detailed metrics section and find the one in red: it is the only usable piece of information on the page.
Market approaches, and what they are worth
| Approach | What it delivers | Who it suits |
|---|---|---|
| Caching plugin | The best effort to result ratio on most sites. Fixes nothing that is badly built | Everyone, first |
| Targeted work after measurement | Addresses the real causes, one by one. Requires reading a report properly | Sites with traffic and a conversion stake |
| Technical rebuild | Fixes everything, including what was not broken. Cost on another scale entirely | Sites whose structure is the problem |
| Doing nothing | Defensible if your field data is green | Lean sites that are already fast |
These approaches combine. Caching first because it costs little, measurement next to find out whether anything is left to do, a rebuild only once the first two have shown their limits.
The tooling, and its limit
Two families of tools, often confused. Lab measurements, PageSpeed Insights and Lighthouse, simulate a mid range phone on a throttled network. They are roughly reproducible, available right away, and that is where causes are read. Field measurements, the ones Google collects from real Chrome visitors, do not lie about the lived experience but need traffic to exist, and look 28 days back.
The rule: the lab to diagnose and fix, the field to decide whether the subject deserves attention at all. A site whose field data is green does not have a speed problem, whatever number the lab displays.
No tool will tell you which of your fixes was useless. That answer only comes from measuring before and after, at every move. It is the heart of our work on data and performance: deciding with numbers, including when they say the change is not worth keeping.
What this says more broadly
Web performance has become a field where recipes get applied. Best practice lists circulate, plugins promise to apply them in one click, and you end up stacking optimisations nobody ever verified on the site concerned. Two out of six, in our case, were useless.
The same flaw runs through analytics, search and advertising: you adopt what is recommended, you do not measure what it delivers, and the debt piles up quietly because none of those decisions causes an outage. A site never looks broken because it carries three useless optimisations. It is merely a little heavier, a little harder to evolve, and a little more expensive to maintain, every month.
Sources
- Lighthouse performance scoring, Chrome for Developers documentation
- Core Web Vitals, web.dev
- unicode-range, MDN documentation on character set selection
- Measurements in this article: Lighthouse 12, mobile profile, dotsland.com home page, 11 and 12 August 2026
FAQ
My PageSpeed score changes on every run, is that normal?
Yes, and the spread can reach several points without a single line of code changing. On this article’s site, four consecutive runs returned 100, 97, 99 and 97. Run the measurement three times and keep the median. If you see a spread of more than two points, draw no conclusion from any single run.
Should you aim for 100 out of 100?
No. The score is a lab indicator, not a measurement of what your visitors experience. Above 90, the remaining points often cost more in complexity than they return in real speed. The only goal that matters is that your field data, collected from your actual visitors, is green.
How do you know whether an optimisation actually helped?
By measuring just before and just after, on the same page, with nothing else changed in between, and repeating the measurement two or three times to smooth out the spread. If the numbers do not move, remove the change: code that serves no purpose still has to be maintained indefinitely.
Can Dotsland help us with this?
Yes. We measure what exists, identify the real causes rather than generic recommendations, and we also tell you what is not worth fixing. Start with the self diagnosis described above, it takes ten minutes and you will already know whether the subject deserves support. Let’s talk about your project.

