Core Web Vitals on a small site: what moved ours, measured
Rishabh Pandey

Lighthouse told us our home page's Largest Contentful Paint (LCP), one of the three Core Web Vitals, fell from 6.1 seconds to 1.9 in eleven days. Run a second way, with the slow connection applied during the load, the same page went from 2.49 seconds to 2.37. What we had really sped up was a blog post, whose LCP fell by half in both modes, and the JavaScript that blocked every page, which both modes saw drop to almost nothing. The third vital, layout shift, never needed fixing.
We know which change did what because we rebuilt buffermint.com at seven points in its git history, served each copy the same way, and ran Lighthouse 141 times. This post gives the numbers, shows which ones a small site can trust, and ends with the order we'd fix things in next time.
The three Core Web Vitals, and the score that isn't one of them
Google's Core Web Vitals are three measurements of real visits:
| Vital | Measures | Good |
|---|---|---|
| Largest Contentful Paint (LCP) | when the biggest thing on screen appears | 2.5 s or less |
| Interaction to Next Paint (INP) | how fast the page responds to taps and clicks | 200 ms or less |
| Cumulative Layout Shift (CLS) | how much the layout jumps around | 0.1 or less |
A page passes when it meets all three at the 75th percentile of visits, with phones and desktops judged separately. INP replaced First Input Delay on 12 March 2024, so advice that still talks about FID is out of date.
The Lighthouse score is a different thing. Since Lighthouse 10 it has been built from five lab metrics: Total Blocking Time (TBT) 30%, LCP 25%, CLS 25%, First Contentful Paint 10% and Speed Index 10%. TBT carries the most weight, and it isn't a Core Web Vital. It stands in for INP, which Lighthouse can't measure on a page load because nobody taps anything. web.dev's TBT page says a low TBT "often correlates" with a good INP, and that it is no substitute for measuring INP. So your score can rise through TBT while no vital moves.
A small site gets no field data
Google ranks on field data: what Chrome users actually experienced, collected in the Chrome UX Report (CrUX). A page or a site only gets into CrUX once it passes a popularity threshold, and Google doesn't publish the number. The data covers a 28-day window, so even a site that qualifies waits weeks to see a fix show up.
Our site gets a few hundred counted pageviews a week (530 in the week of 23 to 29 October 2026, from our own GoatCounter logs). We don't expect to be near the threshold. If PageSpeed Insights shows no real-user data for your site, this is why, and the lab numbers under it are all you have. Even web.dev's INP guide allows for this: "It's entirely possible, however, that you don't have field data."
Lab data has known gaps. A Lighthouse run is one device, one network and one location, starting with an empty cache, as web.dev puts it. It doesn't scroll or tap, so it misses layout shifts further down and anything that happens after a click. DebugBear notes that Lighthouse's mobile network profile is slower than most real connections, so lab LCP tends to look worse than what visitors get. Use the lab to compare versions of your own page, not to grade it.
What we tested
We rebuilt the site at seven commits, from 24 October to 4 November 2026, each from a clean checkout with the same build tools. We served each build from our own server with Brotli compression and ran Lighthouse 13.5.0 (Chrome 156) on its mobile settings: seven builds, three pages, five runs each, 105 runs, taking the median as Lighthouse's variability guide recommends. The pages were the home page, the About page and one blog post whose text didn't change in that period.
| Build | What changed |
|---|---|
| 1. Start (24 Oct) | the site as it was |
| 2. Image cap (24 Oct) | uploaded images resized to at most 1,600 px wide |
| 3. WebP (25 Oct) | WebP copies offered through <picture>, width and height on images, other markup fixes |
| 4. Vendor trim (25 Oct) | unused libraries dropped: vendor.js 479 KB → 104 KB |
| 5. WebP covers (27 Oct) | post cover backgrounds offered as WebP |
| 6. No Vue (28 Oct) | Vue 2 removed: main.js 123 KB → 19 KB |
| 7. Latest (4 Nov) | new lightweight post covers; an old testimonial section removed from the home page |
Those 105 runs used Lighthouse's default, simulated throttling: it loads the page on a fast connection and estimates how long it would take on a slow phone. We then ran four of the builds again, three runs each, with DevTools throttling, which slows the connection and CPU during the load itself. Builds 3 and 7 each bundled several changes, so for those we name the part we think moved the numbers, and why.
The results
Simulated throttling, median of five runs. Weight is what the page transferred during the test.
| Build | Home: score, LCP, TBT | About: score, LCP, TBT | Post: score, LCP, TBT | Home weight |
|---|---|---|---|---|
| 1. Start | 72, 6.08 s, 295 ms | 87, 3.78 s, 146 ms | 71, 5.48 s, 361 ms | 1,124 KB |
| 2. Image cap | 71, 5.70 s, 330 ms | 87, 3.71 s, 153 ms | 83, 4.22 s, 175 ms | 998 KB |
| 3. WebP | 75, 5.18 s, 257 ms | 89, 3.55 s, 139 ms | 82, 3.75 s, 314 ms | 818 KB |
| 4. Vendor trim | 79, 4.73 s, 210 ms | 96, 2.66 s, 83 ms | 88, 3.15 s, 241 ms | 718 KB |
| 5. WebP covers | 79, 4.73 s, 220 ms | 96, 2.66 s, 81 ms | 92, 2.85 s, 196 ms | 718 KB |
| 6. No Vue | 84, 4.58 s, 2 ms | 97, 2.48 s, 7 ms | 96, 2.70 s, 3 ms | 682 KB |
| 7. Latest | 99, 1.86 s, 0 ms | 97, 2.41 s, 7 ms | 99, 2.16 s, 8 ms | 144 KB |
DevTools throttling, median of three runs:
| Build | Home: score, LCP, TBT | About: score, LCP, TBT | Post: score, LCP, TBT |
|---|---|---|---|
| 1. Start | 81, 2.49 s, 493 ms | 85, 2.20 s, 456 ms | 63, 6.36 s, 521 ms |
| 4. Vendor trim | 88, 2.53 s, 270 ms | 92, 2.21 s, 229 ms | 78, 4.14 s, 305 ms |
| 6. No Vue | 94, 2.50 s, 62 ms | 96, 2.21 s, 71 ms | 86, 3.82 s, 53 ms |
| 7. Latest | 95, 2.37 s, 53 ms | 96, 2.24 s, 53 ms | 92, 3.12 s, 49 ms |
Median CLS was 0 to 0.003 everywhere, in both modes, and no single run went above 0.01.
Where the two modes disagree: text LCP
On the home page and the About page, the largest element is text. With DevTools throttling, that text appeared with the first paint or within about a tenth of a second of it, at 2.2 to 2.5 seconds, in all four builds we tested that way. Nothing we changed moved it.
Simulated throttling put the home page's LCP at 4.6 to 6.1 seconds for six builds, and then 1.86 s once build 7 deleted an old testimonial section. In our WebP test we traced that to one 504 KB PNG in the section, a logo beside a testimonial shown 32 pixels tall, and saw the two modes disagree about it then too. The simulation estimates a slow load from a fast one, and Lighthouse's throttling docs say it can be inaccurate. We didn't trace its reasoning. What we can say is that a large file on the page moved the simulated LCP of a paragraph by seconds, and the applied-throttling LCP of the same paragraph by almost nothing.
Deleting that section was still worth doing: it took the home page from 682 KB to 144 KB, which a visitor on a metered connection pays for. It just didn't make the headline appear sooner. If your lab LCP element is text and your simulated LCP is far behind your first paint, check it in DevTools mode before you rebuild anything.
Where they agree: an image LCP got much faster
The blog post's LCP element was a photo, and both modes say it improved a lot: 5.48 to 2.16 s simulated, 6.36 to 3.12 s with DevTools throttling. In DevTools mode that's still above the 2.5-second line, so we can't call it good yet.
That photo was a parallax background. A script set it after the page loaded, so the browser couldn't start fetching it early. It weighed 380 KB at the start, 209 KB after the 1,600-pixel cap, and 146 KB as WebP. In simulated mode the cap took 1.26 s off (it also shrank a second image on the page), and the switch to a WebP cover in build 5 took 0.30 s. Today the cover is an ordinary image element of 21 KB.
The WebP build also took 0.47 s off the post without touching that photo, which was still a JPEG then. Three card images further down stopped loading during the test, about 180 KB that the photo no longer had to share the connection with.
All three already had loading="lazy". The only change to their image tags was the width and height we added; they also gained a WebP alternative, which changes the format, not whether they load. web.dev explains why that matters: an image with no dimensions starts out as 0×0 pixels, so a whole row of them can look as if it fits on screen, and the browser may load them all. With real dimensions, the cards took up their space and fell outside the range Chrome loads ahead. Lazy loading without dimensions can quietly do nothing.
TBT: the gain both modes saw
Between the start and build 6, TBT fell from 456 to 521 ms to 53 to 71 ms in DevTools mode on all three pages, and from 146 to 361 ms to under 10 ms simulated. The simulated runs show where it happened. In the image builds TBT bounced around without a trend (175 to 361 ms on the post); it fell when we dropped 374 KB of unused libraries (build 4) and almost vanished when we removed Vue (build 6).
The full Vue build had been compiling every page in the browser on each load, though only the blog search box used it. In DevTools mode, main-thread work on the post fell from 2.59 s at the start to 1.83 s at build 6.
This is the change most likely to matter for real visitors: pages that answer taps sooner, which is what INP measures. It's also the change our lab test can't fully show, because INP needs real taps. In the score it was worth the most: in DevTools mode the home page went from 81 to 94 between the start and build 6 with its LCP, first paint and layout shift all flat, so the rise came from TBT alone.
What didn't move
- Text LCP, in DevTools mode, as above. Simulated First Contentful Paint also stayed at 1.35 s on the home page and the post, and 1.65 s on About, in all seven builds. That held even when build 4 cut the stylesheets from 49 to 40 KB transferred. We haven't yet traced what holds the first paint back.
- CLS was never a problem in the lab. Setting
widthandheighton images is still right, because it prevents shifts a visitor sees while scrolling, but it didn't change a lab number for us.
Does any of this matter for search?
Some, but less than relevance. Google's page experience documentation says Core Web Vitals "are used by our ranking systems", and in the same document that it shows the most relevant content "even if the page experience is sub-par". It adds that chasing a perfect score just for SEO "may not be the best use of your time". And for a site with no field data, Google has no Core Web Vitals data of its own to judge you on. Fix them for the visitors who arrive.
A failing grade is common. The 2025 Web Almanac found 48% of mobile sites passed all three vitals in July 2025. LCP was the one most often missed: 62% had good LCP, 77% good INP and 81% good CLS. The same chapter put median mobile TBT at 1,916 ms, up 58% on the year before. Our worst build had a TBT of 521 ms in DevTools mode.
The order we'd fix things in next time
- Find your LCP element. Lighthouse and PageSpeed Insights both name it. If it's text, images won't speed it up. If it's an image, its size and how early it starts loading are most of your LCP.
- Sort the page's requests by size and open the biggest. Our heaviest file was a logo that had sat in our repository since 2021. If an image is far larger than its displayed size, resize it before you think about formats.
- Make the LCP image small and load it early. Use an ordinary image element with
widthandheight, not a background a script sets. Then compress it; our image compressor runs in the browser. - Stop loading what's below the fold. Lazy-load images further down, with
widthandheightset, so they don't compete with the LCP element. - Delete JavaScript you don't use before you optimize what you keep. It's the main lever on TBT, and TBT is how the lab approximates INP. A JavaScript minifier or a CSS and HTML minifier helps once the dead code is gone.
- Run each test five times, and check big wins in DevTools mode too. Compare versions of your own page, not one score against a target.
- Switch to field data when you get it. Once PageSpeed Insights shows real-user data for your site, that is the number Google uses.
Our own next job is the first paint, the one number that barely moved in either mode.
Sources
- web.dev: Web Vitals (the three metrics and thresholds, updated October 2024), Interaction to Next Paint (updated September 2025), Total Blocking Time (updated October 2025), Why lab and field data can be different, Browser-level image lazy loading and INP becomes a Core Web Vital on March 12.
- Chrome for Developers: Lighthouse performance scoring, CrUX methodology and the CrUX API.
- Lighthouse on GitHub: Score variability and Network throttling.
- Google Search Central: Understanding page experience.
- HTTP Archive: Web Almanac 2025, Performance (July 2025 data, published January 2026).
- DebugBear: Why does Lighthouse lab data not match field data? (updated January 2026; DebugBear sells monitoring).
- Our measurements: seven builds of buffermint.com from its git history; Lighthouse 13.5.0 and Chrome 156 on our server; 105 runs with simulated throttling and 36 with DevTools throttling, November 2026. Traffic from our GoatCounter logs.
Building a software product?
Talk it through with us on a free 30-minute call, or email [email protected]. You can also try our free tools.
Suggested Articles
Here are a few more articles you might like.


