The article this pairs with covers why slow costs you customers and ranks the levers worth pulling: images, hosting, and cutting code you don't use. Guide 01 step 4 covers how to measure, why field data beats the lab score, and what the thresholds are. Neither is repeated here.
This is the part in between, where most speed advice quietly stops being useful. Knowing that images matter doesn't tell you which image, and a list of twelve possible causes isn't a diagnosis. Every step here narrows the problem to one thing before touching anything. The worked example is a Toronto restaurant site, illustrative rather than a real client, failing all three metrics.
The numbers you're aiming at
Guide 01 gives the passing thresholds. A repair guide needs the other end too, because there's a middle band and knowing which one you're in changes how hard to push.
| Metric | Good | Poor | What it measures |
|---|---|---|---|
| LCP | 2.5s or less | Over 4.0s | How long until the main thing appears |
| INP | 200ms or less | Over 500ms | How long until a tap does something |
| CLS | 0.1 or less | Over 0.25 | How much the page jumps around |
Between good and poor is needs improvement, and it's the band worth being calm about. A site at 2.8 seconds isn't broken. A site at 5 seconds is losing people before the page paints. Each is judged at the 75th percentile, so you're graded by your slower quarter of visitors rather than your average one.
Pick one metric and work only on that
Take your three numbers and find which fail. Then pick one and ignore the other two until it is fixed.
This isn't a productivity tip, it's the only way to learn anything. The three have different causes and different fixes, and changing five things at once leaves you unable to say which helped and which made something else worse. That matters here because speed fixes genuinely trade against each other: deferring scripts to help loading can hurt responsiveness.
If more than one fails, work in this order:
- CLS first. Usually the cheapest to fix, often a few attributes, and the most visibly annoying to a human. Quick confidence.
- LCP second. Usually one image, usually one of three specific causes, and the diagnosis is well signposted.
- INP last. Hardest, most likely to be architectural, and most likely to end in a conversation about the theme rather than a fix you apply this afternoon.
How to know it worked You have written down one metric name, its current number, and today's date. That date is what step 8 counts 28 days from, so it's worth writing rather than remembering.
Common trap Fixing everything in one sitting because you have the site open anyway. You'll improve the numbers and learn nothing about your site, and the next time it slows down you'll be starting from zero again.
Find your actual LCP element
Nearly everyone assumes they know which element is their LCP. Most are wrong, and acting on the assumption is how people spend an afternoon compressing an image that was never the problem.
You don't have to guess, because the tool names it:
- Run your page through PageSpeed Insights.
- Scroll past the score to the Diagnostics section.
- Open the audit called Largest Contentful Paint element. It names the exact element, with its selector.
It's often not the hero image. With a big headline above the photo, the headline text is frequently the LCP element, and no amount of image compression will move it. With a background image set in CSS, it may be a block of text sitting on top. Read the audit, not the page. Write down the element and its URL if it has one, since step 3 needs to know which request to look at.
How to know it worked You can name your LCP element out loud, specifically. Not the hero, but the img at the top of the homepage serving banner-2024.jpg, or the H1. If you're still describing it by where it sits on the page rather than what it is, open the audit again.
Common trap Testing only the homepage. The LCP element differs per template, so your service pages and your blog posts each have their own, and they're often worse than the homepage because nobody ever looked at them. Run your top three landing pages, not just the front door.
Read the breakdown before you change anything
This is the step that turns a slow number into a specific job, and it's the one almost nobody opens.
The same audit splits your LCP into four consecutive phases. web.dev gives target proportions for each, and the phase that's oversized relative to its target is your problem:
- Time to first byte, target around 40%. Waiting for the server to answer at all.
- Resource load delay, target under 10%. The gap between the page starting and the browser beginning to fetch your LCP image. Time when nothing is loading.
- Resource load duration, target around 40%. Actually downloading it.
- Element render delay, target under 10%. Downloaded, but not yet on screen.
The principle underneath, in web.dev's words, is that the vast majority of the LCP time should be spent loading the HTML document and LCP source. That's why the two delay phases have such small targets: they're dead air.
Each phase points at a different fix. A large resource load delay means the browser didn't know it needed the image, which is a priority problem. A large resource load duration means the file is too big. A large time to first byte means the file is fine and your hosting is slow. Compressing an image can't fix hosting, which is why this step comes before any editing.
| Phase | This page | Target | Reading |
|---|---|---|---|
| Time to first byte | 0.5s / 12% | ~40% | Fine |
| Resource load delay | 1.9s / 46% | under 10%1 | The problem |
| Resource load duration | 1.5s / 37% | ~40% | Acceptable2 |
| Element render delay | 0.2s / 5% | under 10% | Fine |
How to know it worked You can name the one phase that's oversized against its target, and say in a sentence what that implies. Two phases over target is fine and means two jobs. All four roughly on target with a bad total means the page is uniformly heavy, which is a hosting and weight conversation rather than a single fix.
Common trap Reading the seconds and ignoring the percentages. A 1.5 second load duration sounds terrible in isolation, but at 37% of a 4.1 second LCP it is roughly where it should be, and it isn't what you fix first. The proportions are the diagnosis.
Apply the LCP fix that matches the phase
Now, and only now, change something. Match the fix to the phase from step 3.
Resource load delay too high. The browser found out too late. Three causes, most common first:
- The LCP image is lazy-loaded. web.dev is blunt about this: never lazy-load your LCP image, as that will always lead to unnecessary resource load delay. Lazy loading is correct below the fold and actively harmful on the one image that defines your LCP. Many themes apply it to every image indiscriminately.
- It has no priority signal. Add
fetchpriority="high", which web.dev recommends when an image is likely to be the LCP element. - It's referenced from CSS or JavaScript rather than the HTML, so the browser can't see it until that file is parsed. Preload it with a high fetch priority.
Resource load duration too high. The file is too big for what it displays. Serve it at the size it renders at rather than camera resolution, in a modern format. The artifact below has the settings.
Time to first byte too high. Not a page problem. It's hosting, or server-side work happening before a byte is sent, and it's the one phase you can't fix in your HTML.
Change one thing, re-run, then change the next.
How to know it worked Re-run the audit and the phase you targeted has shrunk in proportion. That's the immediate signal, and it's a lab signal. The real one is 28 days away. If the phase didn't move, you changed something other than what the breakdown pointed at.
Common trap
Adding fetchpriority="high" to several images at once. Priority is relative, so marking everything high is identical to marking nothing high, and you have spent the signal. One image per page, the one the audit named.
The free audit runs the speed checks alongside the rest of your site, so you can see whether the slow page is the only problem or a symptom of a heavier one.
RUN THE FREE AUDITFind what's actually shifting
CLS is the metric people describe rather than measure. Everyone knows the page jumps; almost nobody knows which element jumped or by how much.
Two ways to find out, and it's worth doing both:
- PageSpeed Insights has an Avoid large layout shifts audit that lists the shifted elements and how much each contributed. Start here, since it needs no setup.
- Chrome DevTools, Performance panel, has a Layout Shifts track that shows each shift as a purple bar on a timeline. Record a page load, then click a bar to see exactly what moved. This is the one that makes it obvious.
Throttle the connection while you record. On fast broadband everything arrives so quickly the shift is invisible even though it still counts, while your visitor on a phone gets the full experience of it.
Watch particularly for shifts happening late, several seconds in. Those are the expensive ones, because they arrive after somebody has started reading or reached for a button, and a mistap on a phone is how a layout shift becomes a lost booking.
How to know it worked You can list the elements that shift, in order of contribution, and you have reproduced at least the biggest one with your own eyes on a throttled load. A CLS number with no named element behind it isn't a diagnosis.
Common trap Testing with an ad blocker on, or with the cookie banner already dismissed. Both suppress the two most common causes of shifting on a small business site. Test in a fresh private window, the way a first-time visitor arrives.
Reserve the space and the shifting stops
Nearly all layout shift is one mistake wearing different clothes: something arrives late, and no space was set aside for it, so everything below moves down. The fix is always to reserve the space in advance.
- Images without dimensions. Put
widthandheightattributes on every image. Browsers derive the aspect ratio from those two numbers and hold the space open while the file downloads. They don't control displayed size, so it costs you nothing. This one attribute pair fixes most CLS on most small business sites. - Ads, embeds and iframes. Same problem, but you usually can't set a height on third-party content. Wrap it in a container with a
min-heightsized to what it usually becomes. - Injected content. Cookie banners, promo bars, review widgets. Reserve space with
min-heightoraspect-ratio, and place late-loading content lower in the viewport where you can. - Web fonts. The page renders in a fallback, the web font arrives, everything re-lays out. Specify a fallback in the stack, preload the critical font, and use
size-adjustto close the size gap so the swap moves nothing.
On fonts there's a trade to make consciously. font-display: optional avoids the re-layout entirely, at the cost of sometimes never showing your web font on a slow connection. Right when stability matters more than typography, wrong when the font is the brand. Decide rather than inheriting whatever the theme set.
How to know it worked Record the same throttled load again in DevTools and the purple bars you targeted are gone. CLS is the one metric where the lab result is genuinely trustworthy, because a shift either happens or it doesn't.
Common trap Setting width and height in CSS but not as HTML attributes. The browser needs them in the markup, before the stylesheet is parsed, to reserve the space at the right moment. CSS alone is too late for the very shift you're trying to prevent.
Work out what's blocking the interaction
INP is the hardest of the three and the one most likely to end in an honest no. It measures the delay between someone tapping and the screen visibly responding, so it's the metric that most directly matches what a person means by slow.
An interaction has three parts, and naming which one is large tells you what kind of problem you have:
- Input delay. Time from the tap until your code starts running. Large means the main thread was already busy with something else, usually scripts still executing during page load.
- Processing duration. Time your event handlers take. Large means the work you do on tap is too heavy.
- Presentation delay. Time until the browser paints the result. Large usually means a very heavy DOM, or too much being rendered at once.
web.dev's method is field first, then lab: use field data to learn that interactions are slow, then reproduce them in DevTools during page load, when the main thread is busiest and real people are tapping and getting nothing.
The fixes are mostly one idea: stop doing long uninterrupted work. Break event handler work into separate tasks so the browser can paint between them, batch DOM reads and writes rather than alternating, and reduce script evaluation during load.
Here's the honest part. On most small business sites this JavaScript isn't yours. It's the theme, a page builder, or four tracking scripts added over three years. Removing what you no longer use is real work with real gains. Rewriting how a commercial theme handles events isn't, and if the breakdown points there you have found a ceiling rather than a task.
How to know it worked You can name the slowest interaction on the page and which of the three parts dominates it. If the answer is that a script you didn't write and can't edit is holding the main thread, that's a legitimate result and the next move is a decision, not a fix.
Common trap Deferring every script to fix input delay. It reliably improves the loading metrics and can push work into exactly the moment someone taps, making INP worse. This is the clearest case of the metrics trading against each other, and the reason step 1 insists on one at a time.
Wait 28 days, then re-measure
The last step is doing nothing for a month, and it's the one most likely to be skipped, which is why real fixes get reverted by people who think they failed.
Field data is a rolling 28 day window. The day after you ship a fix, 27 of those 28 days still contain the old version of the page. The number barely moves. A week later it has crept. At 28 days the entire window is the new page, and you finally see the truth.
So: ship the fix, write down the date, set a reminder 28 days out linked to your measurement log. In between, the lab score is the only feedback available and it's a proxy, useful for confirming you changed what you meant to and worthless as proof.
At 28 days, re-run and record the field numbers next to the old ones. Three outcomes, all useful:
- Moved into good. Done. Log it and start on the next metric.
- Improved but still failing. The diagnosis was right and there's a second cause. Back to the breakdown, which will now point somewhere new.
- Didn't move. The fix wasn't the bottleneck. This isn't wasted effort, it eliminates a suspect, which is exactly what a diagnosis is for.
How to know it worked Your log has two dated rows for the same metric, 28 days apart, and you can say which change sits between them. One row isn't a measurement, it's a reading.
Common trap Re-checking at day three, seeing nothing, and undoing the fix. The window guarantees that outcome regardless of whether the fix worked. Nobody who hasn't been told about the 28 days would ever guess it, which is why it's written here in bold.
The whole thing, worked
The restaurant site, failing all three. Figures illustrative, but the pattern is the ordinary one.
Starting point: LCP 4.1s (poor), INP 340ms (needs improvement), CLS 0.28 (poor). Step 1 ordered the work CLS, LCP, INP.
CLS 0.28 to 0.04, in about twenty minutes. The Layout Shifts track showed two culprits: menu photos with no width or height, and a reservation widget injecting itself above the fold two seconds in, pushing the page down after people had started reading. Dimensions on the images, a min-height container for the widget, and it stopped.
LCP 4.1s to 2.1s, from one attribute. Step 2 named the hero food photo. Step 3 is where it got interesting: resource load delay was 46% against a target under 10%, while load duration sat near target, so the image wasn't oversized. The theme had applied loading="lazy" to every image including the hero, so the browser deliberately waited before fetching the one thing the page is judged on. Removing it and adding fetchpriority="high" took two seconds off.
That's the breakdown earning its place. Without it the obvious move is compressing the hero, which would have addressed a phase that was already fine.
INP 340ms to 180ms, and the last part was a decision. Input delay dominated, meaning the main thread was busy during load. Two tracking scripts from a former agency were still loading on every page, unnoticed for two years. Removing them got INP to 180ms. The rest sits in the theme's menu handler, which needs a new theme, and at 180ms it passes, so it stays.
At 28 days the field data confirmed all three in the good band. The lab score, for the record, went from 71 to 88, which was the least interesting number in the whole exercise.
Copy and paste
Three artifacts. The decision table is the one to keep open while you work.
PageSpeed Insights -> Diagnostics ->
"Largest Contentful Paint element"
Read the PERCENTAGES, not the seconds.
PHASE TARGET IF OVERSIZED, THE CAUSE IS
Time to first byte ~40% hosting / server work.
NOT fixable in your HTML.
Resource load delay <10% the browser found out late:
1. LCP image is lazy-loaded
2. no fetchpriority="high"
3. referenced from CSS/JS,
not the HTML -> preload
Resource load duration ~40% file too big for its
displayed size. resize +
modern format.
Element render delay <10% render-blocking CSS/JS, or
waiting on a web font.
RULE
All four near target but a bad total?
The page is uniformly heavy. That is a
weight and hosting conversation, not one fix.
Two phases over target = two jobs, not one.
Do them one at a time.
NEVER
lazy-load the LCP image
put fetchpriority="high" on more than one
image per page (priority is relative;
marking everything high marks nothing)
<!-- LCP image: the one at the top.
NO loading="lazy". fetchpriority high.
width/height = the file's real pixels. -->
<img src="/img/hero.webp"
width="1600" height="900"
fetchpriority="high"
alt="...">
<!-- Every OTHER image: lazy is correct here,
but keep width/height or it will shift. -->
<img src="/img/dish-3.webp"
width="800" height="600"
loading="lazy" decoding="async"
alt="...">
<!-- Third-party embed: reserve the space,
since you cannot set its height. -->
<div style="min-height:420px">
<!-- widget injects here -->
</div>
/* Fonts: stop the swap re-laying out the page */
@font-face {
font-family: "Brand";
src: url("/fonts/brand.woff2") format("woff2");
font-display: swap; /* or: optional */
size-adjust: 97%; /* tune to match fallback */
}
body { font-family: "Brand", system-ui, sans-serif; }
WIDTH/HEIGHT ARE HTML ATTRIBUTES, NOT CSS.
CSS is parsed too late to reserve the space.
Setting them in CSS alone does not fix CLS.
They do not control displayed size. CSS still does.
font-display TRADE
swap ..... font always shows, brief re-layout
optional . no re-layout, font may never show
Pick deliberately. Do not inherit the theme's.
DATE | PAGE | METRIC | FIELD | LAB | WHAT CHANGED | +28d
One row when you ship. One row 28 days later.
Never one row on its own.
FIELD .......... the number Google grades you on
LAB ............ a proxy. useful between the two
rows, worthless as proof
WHAT CHANGED ... ONE thing. if you cannot fit it
in the cell, you changed too much
WHY 28 DAYS
Field data is a rolling 28 day window. The day
after a fix, 27 of those days are still the OLD
page. It will look like nothing happened.
That is the window, not the fix.
AT 28 DAYS, THREE OUTCOMES
moved into good .......... log it, next metric
improved, still failing .. right diagnosis,
second cause. re-read
the breakdown
did not move ............. wrong suspect. still
progress: one cause
eliminated
ORDER, when more than one fails
1. CLS cheapest, often just attributes
2. LCP usually one image, well signposted
3. INP hardest, often architectural
One metric, start to finish
Where this stops
Two of the three are properly DIY. CLS is often an afternoon of adding attributes, and it's the most satisfying work here because the fix is immediate and visible. LCP is usually one image and one of three well-signposted causes, with the breakdown doing most of the thinking.
INP is where it stops, and not because the technique is hard. The JavaScript holding the main thread usually came with the theme or the page builder. Removing scripts you no longer use is often most of the win. Changing how a commercial theme handles a tap isn't something configuration reaches.
That's where speed work becomes the rebuild conversation. The useful part is that you arrive at it with evidence: a named metric, a named phase, a named script. Better basis for a decision than a sense that the site feels slow.
If you'd rather have the diagnosis done for you, the free audit covers speed alongside the rest of the site, and the web design work is where the architectural version gets solved properly.
Questions people ask
Why is my mobile score so much worse than desktop?
Because the mobile test isn't the same test. It simulates a mid-range phone on a throttled connection, while the desktop run assumes a capable machine on a decent link, so the same page produces very different numbers. That gap isn't a bug and not something to explain away: Core Web Vitals are assessed separately for mobile and desktop, and your customers are mostly on phones. Work on the mobile numbers and treat desktop as a bonus. The gap is widest on sites carrying a lot of JavaScript, since a phone processor takes far longer to execute the same script, which is why heavy pages fail on responsiveness long before loading.
My score went up but the field data hasn't moved. Did the fix fail?
Almost certainly not, you're just reading it too early. Field data is a rolling 28 day window, so on the day after a fix, 27 of the 28 days behind the number still contain the old, slow version of the page. The metric moves gradually as old days fall out of the window, which means a real improvement looks like nothing for a week and then a slow drift in the right direction. Note the date you shipped the fix and set a reminder for 28 days later. If the field number hasn't moved at all by then, the fix genuinely didn't work on real devices, and only at that point is it worth re-opening. Reverting at day three is how people undo fixes that were working.
How do I fix speed on a site I can't edit the code of?
More than you'd think. Re-uploading images at the size they actually display, in a modern format, is the single biggest win and needs no code at all, since most slow small business sites are shipping camera-resolution photos. Removing apps, plugins and embeds you no longer use is second, and it's usually where the interaction delay lives. Most platforms also expose a lazy-loading toggle. What you generally can't reach is fetchpriority on the hero image, the font loading strategy, and how the theme bundles its JavaScript. If the breakdown points there and the platform won't let you near it, you have found a real ceiling rather than a skill gap, and that's a genuine input to the rebuild decision.
Should I install a speed optimisation plugin?
Only after you know what's actually slow, and then only for the specific job. These plugins bundle a dozen behaviours, several of which fight each other, and they're usually installed as a substitute for diagnosis rather than a result of it. Aggressive script deferral to fix a loading problem can easily make responsiveness worse, and you won't know because you changed ten things at once. If the breakdown says your hero image loads late, the fix is on that image. Where they do earn their place is caching and file compression, which are fiddly to hand-roll. Install it for that, turn on one feature at a time, and re-measure between each.
Is it worth fixing speed if my site already ranks well?
Yes, but not for the ranking. Speed is a real but small ranking input, and a page that already ranks is unlikely to jump on speed alone. The reason to fix it is that everyone who arrives has to wait, and waiting has a cost that never appears in any report, because a visitor who leaves before the page paints is invisible to you and indistinguishable from someone who never searched at all. Speed work protects the value of traffic you've already earned rather than winning more. On a site that ranks well and converts poorly, it's one of the first things worth checking.