{"id":"mxy5h2y0663r7l5","title":"Why PageSpeed Scores Change Every Run (And What to Fix First)","slug":"why-pagespeed-scores-change-every-run","summary":"PageSpeed and Lighthouse scores jump between runs on the same URL—that is normal lab behavior. Here is what moves the number, what to fix first, and how to verify scores honestly.","imageUrl":"https://briancrabtree.me/images/journal-pagespeed-variance.webp","category":"Performance","date":"2026-06-02T18:00:00.000Z","featured":false,"likes":10,"author":"Brian Crabtree","content":"<h2>Lab scores are simulations, not receipts</h2>\n\n<p>PageSpeed Insights runs Lighthouse in a controlled environment: emulated mobile or desktop, throttled CPU, throttled network, a cold-ish load profile, and a single pass through your page. That is useful. It is also not what every visitor experiences. Your real users arrive on different devices, cached assets, background tabs, and networks that have nothing to do with Google's default 4G profile.</p>\n\n<p>When someone quotes \"we got 100 on mobile\" without linking to the run, ask which run. When a score drops twenty points overnight without a deploy, ask whether the lab conditions shifted before you ask whether the developer broke production. Lab data answers a narrow question: under this profile, right now, how does the page behave? It does not answer \"is my business fast for everyone forever.\"</p>\n\n<pre><code>// Same URL, two lab runs — LCP can shift seconds\n// Fix the LCP element, not the headline score</code></pre>\n\n<p><figure>\n  <img src=\"/images/journal-inline-pagespeed-variance.webp\" alt=\"Line chart showing PageSpeed score variance across multiple lab runs on same URL\" width=\"1200\" height=\"675\" loading=\"lazy\" />\n  <figcaption>Variance is normal — fix the LCP element, not the headline number.</figcaption>\n</figure></p>\n\n<h2>Why the same URL scores differently</h2>\n\n<p>Several things move the performance number between runs on an unchanged site. Network timing jitter affects Largest Contentful Paint and Speed Index—a hero image that finishes at 2.4s on one pass and 3.5s on the next can swing the category score hard. Main-thread work from third-party scripts, analytics beacons, or edge security checks shows up inconsistently depending on when they execute relative to the measurement window.</p>\n\n<p>Lighthouse weights change over time. A score you saved six months ago is not comparable to today's score even if your byte count is identical. Total Blocking Time and Interaction to Next Paint can look fine on desktop while mobile still punishes you for JavaScript that hydrates too early. None of that means the tool is useless. It means treating a single integer as a permanent grade is sloppy engineering.</p>\n\n<h2>What actually moves the needle</h2>\n\n<p>When I dig into a regression, I read the audits, not the headline number. LCP tells me whether the primary content—usually a hero image or headline block—shows up in time. Speed Index tells me how quickly the page visually fills in. TBT and INP tell me whether JavaScript is stealing the main thread before the page feels responsive. CLS tells me whether layout is stable enough to trust a tap target.</p>\n\n<p>On React single-page apps, the usual LCP culprits are predictable: hiding a prerender shell before the real hero paints, loading Firebase or grid chunks during the lab window, font preloads competing with the LCP image, and render-blocking CSS that arrives after module JavaScript starts. Fixing those does not require stripping the design. It requires respecting paint order and deferring work that is not on the critical path. That is the difference between a cosmetic perf pass and one that survives the next PSI run.</p>\n\n<h2>Lab data vs field data (CrUX)</h2>\n\n<p>The Chrome User Experience Report section in PageSpeed Insights is field data: real Chrome users over a rolling window. Low-traffic sites often see \"No Data\" there. That is not a failure. Google needs enough eligible Chrome visits to publish origin- or URL-level percentiles without leaking individual behavior. You cannot simulate CrUX with bots or synthetic monitors. You earn it with real traffic over time.</p>\n\n<p>Until field data exists, lab scores are the honest proxy—provided you publish them honestly. I treat CrUX as the long game and Lighthouse as the regression alarm. When a client has traffic, we compare both. When they do not, we still fix LCP and interaction before arguing about a badge in the footer.</p>\n\n<h2>What to fix first (without killing visuals)</h2>\n\n<p>My order has not changed in years. Identify the LCP element and make sure it can paint early: preload the right image, reserve its space, do not hide a static shell before the React version is ready. Stop below-fold JavaScript from downloading during the first seconds—lazy routes help only if you also defer mounting the trees that pull Firebase and public API calls. Audit font loading: one critical face on mobile beats preloading every display weight. Then chase third-party scripts clients insist on adding after launch.</p>\n\n<p>Copy is still part of performance. A fast page that hides the contact path is slow where it matters. I mention that because teams sometimes chase a green gauge while the offer stays buried. Fix paint first. Fix clarity second. Both show up in conversion.</p>\n\n<h2>How to publish scores you can defend</h2>\n\n<p>On this site I publish lab snapshots with links to the exact PageSpeed analysis used—not a cropped screenshot from a lucky run. If mobile is 100 today and 86 tomorrow, both numbers are true for their runs. The linked report lets a skeptical hire verify the audit trail. That policy costs ego and wins trust.</p>\n\n<p>If you are evaluating a vendor, ask for the PSI URL, the date, and the form factor. Run your own pass on the same hostname. Compare waterfalls. If they refuse, ask why. Performance proof should be reproducible the same way a deploy script should be rerunnable.</p>\n\n<h2>Verify it yourself</h2>\n\n<p>Run PageSpeed on <a href=\"https://briancrabtree.me/\">briancrabtree.me</a> and read the LCP breakdown. Open the mobile lab report we used when the homepage gauges were last updated. Read <a href=\"/journal/website-performance-audit-2026-react/\">Website Performance Audit Checklist (2026)</a> for the full ordered pass on React sites, and <a href=\"/journal/performance-checks-before-handoff/\">Performance Checks Before Handoff</a> for how I document handoff. If you want the same discipline on your stack, <a href=\"/contact?ref=journal\">send a brief</a> with your URL and what feels slow—not the score you wish you had, the behavior you actually see.</p>","tags":["pagespeed-insights","core-web-vitals","lighthouse","react"],"views":69}