<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Apogee Watcher</title>
    <description>The latest articles on DEV Community by Apogee Watcher (@apogeewatcher).</description>
    <link>https://dev.to/apogeewatcher</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3769723%2Fa33f1555-0cd4-4f44-b524-a9608ed39a2c.png</url>
      <title>DEV Community: Apogee Watcher</title>
      <link>https://dev.to/apogeewatcher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apogeewatcher"/>
    <language>en</language>
    <item>
      <title>When should you lazy load images (and when does it hurt LCP)?</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Thu, 15 Oct 2026 07:36:30 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/when-should-you-lazy-load-images-and-when-does-it-hurt-lcp-356d</link>
      <guid>https://dev.to/apogeewatcher/when-should-you-lazy-load-images-and-when-does-it-hurt-lcp-356d</guid>
      <description>&lt;p&gt;A theme update or optimisation plugin turns on lazy loading for every image. Bandwidth on long articles looks better in the waterfall, yet PageSpeed Insights still names a deferred hero as Largest Contentful Paint, or lab LCP gets worse than last month. That outcome is common when &lt;code&gt;loading="lazy"&lt;/code&gt; is treated as a global performance switch instead of a per-image choice.&lt;/p&gt;

&lt;p&gt;The full decision guide, including iframes, video, and lab-versus-field checks, lives on our blog in &lt;a href="https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=when-lazy-load-images-hurt-lcp" rel="noopener noreferrer"&gt;Lazy Loading for LCP and CLS: When to Use loading="lazy" (and When Not To)&lt;/a&gt;. Formats, sizing, and CDN work sit beside that in &lt;a href="https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=when-lazy-load-images-hurt-lcp" rel="noopener noreferrer"&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt;. What follows is the short checklist we use in reviews: when lazy loading images helps, when it hurts LCP, and which CMS habits to watch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three checks before you lazy-load an image
&lt;/h2&gt;

&lt;p&gt;These three questions usually decide whether &lt;code&gt;loading="lazy"&lt;/code&gt; belongs on an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is it in the first viewport on phone and desktop?&lt;/strong&gt; If yes for either primary breakpoint, leave it eager.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Could PageSpeed Insights or Chrome name it as LCP?&lt;/strong&gt; If it is the hero, primary product shot, or large above-the-fold banner, omit lazy, or set &lt;code&gt;loading="eager"&lt;/code&gt; when a plugin injects lazy by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the markup reserve space?&lt;/strong&gt; Width and height attributes or an aspect-ratio rule should be present before you defer the fetch, so Cumulative Layout Shift does not replace the LCP problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the template or page builder does not make those answers obvious, identify the first-screen image before you change attributes. A plugin toggle is not a substitute for knowing which image paints first. Note the exclusions in the work item so the next theme update has a clear list.&lt;/p&gt;

&lt;h2&gt;
  
  
  When lazy loading images helps bandwidth without hurting LCP
&lt;/h2&gt;

&lt;p&gt;Lazy loading images is usually right for content that starts offscreen: article body photos after the fold, related-product grids, footer logos, long category galleries, and comment avatars. Those bytes should not compete with the critical path on first paint. On a long post with many images, native lazy loading can cut early mobile bandwidth sharply without changing what the user sees first.&lt;/p&gt;

&lt;p&gt;Eager versus lazy works better as a short policy per template than as a single sitewide switch. Eager fits the LCP candidate and other first-screen images on common breakpoints. Lazy fits everything that needs scroll or a tab change before it matters. Check phone width as well as desktop: an image that looks “below the fold” on a large monitor can sit in the first screen on a phone, and that traffic often dominates field data.&lt;/p&gt;

&lt;h2&gt;
  
  
  When &lt;code&gt;loading="lazy"&lt;/code&gt; hurts Largest Contentful Paint
&lt;/h2&gt;

&lt;p&gt;LCP marks when the largest above-the-fold content element becomes visible. If that element is an image marked &lt;code&gt;loading="lazy"&lt;/code&gt;, the browser may delay the request even though the image is already on screen. Lab tools show that as higher resource load delay and a worse LCP. Google’s guidance and support threads still treat “do not lazy-load the LCP image” as a first triage step, not a rare edge case.&lt;/p&gt;

&lt;p&gt;The fix is usually small. Remove &lt;code&gt;loading="lazy"&lt;/code&gt; from the named LCP image (and matching sources in &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;). &lt;code&gt;fetchpriority="high"&lt;/code&gt; fits when the LCP URL is known early and other resources are not already marked high. Preloading and lazy-loading the same URL fights itself. A reasonably sized eager hero usually beats a huge lazy hero on LCP, even when a plugin dashboard calls the waterfall optimised.&lt;/p&gt;

&lt;h2&gt;
  
  
  CMS and theme traps that lazy-load the hero
&lt;/h2&gt;

&lt;p&gt;WordPress themes, page builders, and Shopify settings often inject &lt;code&gt;loading="lazy"&lt;/code&gt; on every attachment. Logos, banners, and first product images get deferred with the gallery. Elementor and similar stacks show up often in “lazy load LCP” threads for that reason. A CDN or image plugin that rewrites markup can put lazy back after the theme was fixed once.&lt;/p&gt;

&lt;p&gt;When scores drop after a “performance” plugin install, open the LCP element detail before you change hosting plans. Exclude the first-screen image from auto-lazy rules, or override with eager on that node. Record the exclusion in the monthly notes so the next theme update does not silently put lazy back on the hero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick verify: lab LCP element after a lazy-loading change
&lt;/h2&gt;

&lt;p&gt;After any change that touches image markup or lazy defaults, re-run PageSpeed Insights or your scheduled lab profile on the homepage and other priority pages. Check which element is LCP, whether that element is still lazy-loaded, and whether deferred below-the-fold images reserve space with width/height or aspect-ratio. One green Lighthouse run on a staging URL is not enough if production themes differ by template.&lt;/p&gt;

&lt;p&gt;Comparing the same lab profile before and after the change, kept in monitoring history, is how agencies catch a theme update that re-applies sitewide lazy loading three weeks later, when nobody remembers the original ticket. Scheduled runs on the homepage and other priority pages are more reliable than another one-off Insights paste after each deploy. That habit turns a one-time attribute fix into something the next quarterly review can still prove.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Should every image use &lt;code&gt;loading="lazy"&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Offscreen images are the usual fit. Keep the LCP candidate and other first-viewport images eager. Sitewide lazy loading is a common cause of worse lab LCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does lazy loading fix Cumulative Layout Shift?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not by itself. Reserve space with width and height or aspect-ratio CSS. Lazy loading without reserved space can make CLS worse when images appear late and push the layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the HTML &lt;code&gt;loading&lt;/code&gt; attribute enough, or do we still need a JavaScript library?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For ordinary images, native lazy loading is usually enough in modern browsers. Older themes still ship JavaScript lazy libraries; check whether those libraries also defer the hero. Knowing which mechanism is in use belongs in the work item before anyone blames hosting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we know which image is LCP?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use the LCP element detail in PageSpeed Insights or Lighthouse on phone and desktop widths. Do not guess from the design mockup alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  CTA
&lt;/h2&gt;

&lt;p&gt;If lazy loading is already “on” everywhere, treat the toggle as incomplete until the LCP image is named. Below-the-fold images usually stay lazy; the hero stays eager; space is reserved; theme and plugin changes get a retest. For the longer guide with iframes, video, and lab-versus-field detail, use the Watcher lazy-loading post linked above. For formats and sizing that keep eager heroes small enough to ship, use the image optimisation piece. When you need scheduled lab history across many client pages so a theme update cannot silently defer the hero again, run continuous PageSpeed checks in &lt;a href="https://apogeewatcher.com/?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=when-lazy-load-images-hurt-lcp" rel="noopener noreferrer"&gt;Apogee Watcher&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute" rel="noopener noreferrer"&gt;Lazy Loading for LCP and CLS: When to Use loading="lazy" (and When Not To)&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores" rel="noopener noreferrer"&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/articles/browser-level-image-lazy-loading" rel="noopener noreferrer"&gt;Browser-level image lazy loading for the web&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading" rel="noopener noreferrer"&gt;Lazy loading&lt;/a&gt; (MDN Web Docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/blog/common-misconceptions-lcp" rel="noopener noreferrer"&gt;Common misconceptions about Largest Contentful Paint&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>pagespeed</category>
      <category>lighthouse</category>
    </item>
    <item>
      <title>Brotli compression is on: why is PageSpeed / LCP still slow?</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Tue, 13 Oct 2026 08:49:26 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/brotli-compression-is-on-why-is-pagespeed-lcp-still-slow-3792</link>
      <guid>https://dev.to/apogeewatcher/brotli-compression-is-on-why-is-pagespeed-lcp-still-slow-3792</guid>
      <description>&lt;p&gt;The CDN panel shows Brotli enabled and the host checklist ticks compression, yet PageSpeed Insights on the homepage or checkout URL still shows a slow Largest Contentful Paint, or the Performance score barely moves after the change. Those two facts can both be true. Brotli compression shrinks text on the wire; it does not change the LCP element, a slow origin response, or a lab path that never negotiated &lt;code&gt;br&lt;/code&gt; on the files that matter.&lt;/p&gt;

&lt;p&gt;How to turn compression on without breaking scores is already covered on our blog in &lt;a href="https://apogeewatcher.com/blog/brotli-gzip-compression-pagespeed?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=brotli-on-pagespeed-lcp-still-slow" rel="noopener noreferrer"&gt;Brotli and Gzip Compression: Shrink Text Assets Without Breaking PageSpeed Scores&lt;/a&gt;. Caching and reuse sit beside that work in &lt;a href="https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=brotli-on-pagespeed-lcp-still-slow" rel="noopener noreferrer"&gt;Cache-Control Headers for Web Performance&lt;/a&gt;. What follows here is the triage we run when the toggle is already green and the lab result is still poor: confirm encoding on the critical path, then address the bottlenecks compression was never going to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confirm Brotli is actually on the critical path
&lt;/h2&gt;

&lt;p&gt;A dashboard labelled “Brotli” often means the edge &lt;em&gt;can&lt;/em&gt; compress. Lighthouse and PageSpeed Insights care whether the HTML document and the render-blocking CSS and JavaScript on that URL arrived with &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt;. Those are different claims. Open the Network panel (or &lt;code&gt;curl -sI&lt;/code&gt; with &lt;code&gt;Accept-Encoding: br, gzip&lt;/code&gt;) on the document URL and on each large text resource in the critical path. Look for &lt;code&gt;content-encoding&lt;/code&gt; and for transfer size versus content size. If the document is compressed but the main stylesheet is not, the Enable text compression audit can still fail, and paint can still wait on uncompressed bytes.&lt;/p&gt;

&lt;p&gt;Partial coverage is the usual miss after a “we enabled Brotli” ticket. Origin middleware compresses HTML; the CDN serves fingerprinted CSS from a bucket that never negotiated Brotli; fonts and JSON follow yet another path. Agencies also see the reverse: the lab client hits a cache or region where encoding differs from the URL the engineer tested by hand. Until you can name the encoding on the document and the two or three largest text blockers, treat the toggle as incomplete evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Brotli can leave Largest Contentful Paint unchanged
&lt;/h2&gt;

&lt;p&gt;LCP measures when the largest visible element finishes rendering, not when every text file is as small as possible. Compression helps when download time for HTML, CSS, or critical JavaScript was a meaningful slice of that path. It does nothing useful for an LCP image that is still a multi-megabyte JPEG, lazy-loaded by mistake, or discovered late after client-side rendering. Decode and layout work on the main thread also sit outside what compression can fix: a smaller JavaScript transfer still costs the same parse and execute time once the bytes arrive.&lt;/p&gt;

&lt;p&gt;In our experience, teams over-credit the compression ticket because it is easy to mark done. The lab waterfall still shows a late LCP resource, a long Time to First Byte, or render-blocking scripts that compression only shortened by tens of milliseconds. When transfer size was never the bottleneck, expecting a Core Web Vitals step-change from Brotli alone is the wrong bet. Use the LCP element detail in PageSpeed Insights or Lighthouse: if the element is an image or a late text block waiting on fonts and scripts, compression is support work, not the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  When enabling Brotli makes PageSpeed Insights worse
&lt;/h2&gt;

&lt;p&gt;Compression can raise Time to First Byte (TTFB) when the origin or edge encodes HTML on every request at a high Brotli quality level. Smaller bodies help only after the first byte is available. If CPU queues behind dynamic compression, every paint metric starts later even though transfer size looks healthier in the waterfall. That pattern shows up after someone raised Brotli quality to the maximum on dynamic pages without precompressing static assets or without a moderate quality setting for HTML.&lt;/p&gt;

&lt;p&gt;Other regressions are quieter. Double compression (a gzip wrapper around an already-Brotli body, or filters stacked at origin and edge) burns CPU without shrinking useful bytes. Compressing JPEG, PNG, WebP, AVIF, or MP4 as if they were text adds work for almost no gain. Missing or wrong &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; on shared caches can mix encodings across clients and produce flaky lab runs that look like random PageSpeed noise. When the score drops after the toggle, compare Time to First Byte and the server-response audit before chasing image formats again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to fix next when the LCP element is not a text file
&lt;/h2&gt;

&lt;p&gt;Once Content-Encoding looks correct on the critical path, return to ordinary LCP triage. Identify the LCP element. If it is an image, check discovery (preload or early HTML), format and dimensions, and whether &lt;code&gt;loading="lazy"&lt;/code&gt; was applied to the hero by mistake. If Time to First Byte is high, compression will not hide a cold origin, an uncached HTML document, or a slow application query. If render-blocking CSS and JavaScript dominate, shrinking them with Brotli helps a little; removing or deferring work that is not needed for first paint usually helps more.&lt;/p&gt;

&lt;p&gt;Keep compression and caching as paired delivery checks rather than as a substitute for element-level work. Cache-Control decides whether repeat views reuse bytes; Brotli and gzip decide how small the first download of text is. Neither replaces a late LCP image or a client-only render of the hero. For agencies, a clear client update is: compression is done and verified; the remaining LCP risk is named (image, Time to First Byte, or blocking scripts) with an owner and a retest plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  How agencies verify compression and LCP across a client portfolio
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;curl&lt;/code&gt; on staging is not enough evidence across a client portfolio. After deploys that touch CDN, origin, or build output, re-check Content-Encoding on each client’s homepage and other priority pages, then re-run the same lab profile you use for monthly reporting. Scheduled PageSpeed monitoring catches the case where Brotli is on in one region and missing in another, or where a theme update reintroduces uncompressed CSS while the dashboard still says compression is enabled. Pair those runs with a short note in the monthly report: encoding verified on the document and main CSS/JavaScript; LCP element and Time to First Byte trend unchanged or improved.&lt;/p&gt;

&lt;p&gt;That habit keeps the compression ticket from being closed while LCP is still slow. It also stops the next quarterly review from reopening “we turned Brotli on months ago” when the real issue was always the hero image or the origin. Include compression checks in the same monitoring cadence you already use for Core Web Vitals regressions. A separate ritual that nobody opens after launch week does not help.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does Brotli always improve Largest Contentful Paint?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. It can shorten download time for text on the critical path when that download was a real bottleneck. It will not fix a slow LCP image, a late-discovered hero, or a high Time to First Byte caused by origin work. Before-and-after lab runs on the same profile show whether the change mattered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does Enable text compression still fail after we turned Brotli on?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The Lighthouse audit looks at individual text resources above a size threshold, not at a single CDN toggle. HTML may be compressed while CSS or JavaScript is not, or the lab path may differ from the URL you checked by hand. Confirm &lt;code&gt;Content-Encoding&lt;/code&gt; on each flagged URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Brotli make PageSpeed scores worse?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. High-quality dynamic compression on every HTML response can raise Time to First Byte. Double compression and compressing already-compressed media waste CPU without helping LCP. Prefer precompressed static assets and moderate settings for dynamic HTML, then retest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is gzip still needed if Brotli is enabled?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes as a fallback. Keep gzip for clients or hops that do not take &lt;code&gt;br&lt;/code&gt;. Verify both encodings on the homepage and other priority pages rather than assuming the dashboard covers every path after a CDN or origin change.&lt;/p&gt;

&lt;h2&gt;
  
  
  CTA
&lt;/h2&gt;

&lt;p&gt;If the toggle is green and LCP is still slow, treat compression as verified delivery work and name the next bottleneck in plain language. Confirm encoding on the critical path, then put image discovery, Time to First Byte, and render-blocking scripts on the work item with an owner. For enablement detail and MIME allow-lists, use the Watcher compression guide linked above; for caching that sticks beside those bytes, use the Cache-Control piece. When you need scheduled lab history across many client URLs so the next deploy cannot silently drop &lt;code&gt;Content-Encoding&lt;/code&gt;, run continuous PageSpeed checks in &lt;a href="https://apogeewatcher.com/?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=brotli-on-pagespeed-lcp-still-slow" rel="noopener noreferrer"&gt;Apogee Watcher&lt;/a&gt; rather than another one-off Insights paste.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/brotli-gzip-compression-pagespeed" rel="noopener noreferrer"&gt;Brotli and Gzip Compression: Shrink Text Assets Without Breaking PageSpeed Scores&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks" rel="noopener noreferrer"&gt;Cache-Control Headers for Web Performance: CDN and Browser Caching That Sticks&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression" rel="noopener noreferrer"&gt;Enable text compression&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/articles/lcp" rel="noopener noreferrer"&gt;Largest Contentful Paint (LCP)&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Brotli" rel="noopener noreferrer"&gt;Brotli&lt;/a&gt; (MDN Web Docs)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>pagespeed</category>
      <category>lighthouse</category>
    </item>
    <item>
      <title>Why CrUX Has No Data for Your Site</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Tue, 13 Oct 2026 08:43:52 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/why-crux-has-no-data-for-your-site-55fi</link>
      <guid>https://dev.to/apogeewatcher/why-crux-has-no-data-for-your-site-55fi</guid>
      <description>&lt;p&gt;“No data” in the Chrome User Experience Report (CrUX) is not a single bug. It is a set of eligibility gates. Google only publishes field percentiles when enough opted-in Chrome sessions meet privacy and quality rules for that origin or URL. PageSpeed Insights and Search Console inherit those gaps. Lab scores from Lighthouse can still look complete on the same screen, which is why teams often treat a blank field block as a tool failure instead of an eligibility outcome.&lt;/p&gt;

&lt;p&gt;The sections below walk those gates for client sites: when an origin is missing from CrUX entirely, when a URL is thin while the origin still has data, what to say to the client, and what to monitor until field samples exist. Keep &lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-no-cls-inp-for-url" rel="noopener noreferrer"&gt;When PageSpeed Insights Shows No CLS or INP for Your URL&lt;/a&gt; open for metric-level gaps on a URL that may already show other field rows. For how lab and field clocks differ, use &lt;a href="https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026" rel="noopener noreferrer"&gt;What Are Core Web Vitals? A Practical Guide for 2026&lt;/a&gt; and &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt; as context.&lt;/p&gt;

&lt;h2&gt;
  
  
  What “no CrUX data” means on a site
&lt;/h2&gt;

&lt;p&gt;CrUX is Google’s public field dataset for how real Chrome users experience popular destinations. It is also the field source behind PageSpeed Insights “Discover what your real users are experiencing” and related Search Console Core Web Vitals views. When CrUX has no data for a query, tools typically show a missing field section, an API &lt;code&gt;NOT_FOUND&lt;/code&gt; style response, or a message that Chrome UX Report data was not found. That is different from a red or amber field category. There is no percentile to classify yet.&lt;/p&gt;

&lt;p&gt;Agencies usually meet three patterns of “no data” that get mixed together in client chat: (1) &lt;strong&gt;origin absent&lt;/strong&gt; (&lt;code&gt;https://www.client.com&lt;/code&gt; or the wrong scheme/host variant is not in the dataset at all); (2) &lt;strong&gt;URL thin, origin present&lt;/strong&gt; (the homepage or a landing path has no URL-level field rows, while origin-level field data still exists); (3) &lt;strong&gt;metric missing&lt;/strong&gt; (some field metrics appear and others do not, for example LCP present and INP absent). Pattern (3) is covered in the PageSpeed Insights “no CLS or INP” guide linked above. What follows focuses on (1) and the client conversation around (2). The practical question is not whether PageSpeed Insights is broken; it is which eligibility gate failed, and what you measure until field data exists. Naming the gate early stops the team from chasing Lighthouse scores that never create field rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chrome UX Report eligibility: user, origin, and page
&lt;/h2&gt;

&lt;p&gt;Google’s &lt;a href="https://developer.chrome.com/docs/crux/methodology" rel="noopener noreferrer"&gt;CrUX methodology&lt;/a&gt; describes three layers that must line up before an experience counts toward page-level field data in PageSpeed Insights and the CrUX API: the &lt;strong&gt;user&lt;/strong&gt;, the &lt;strong&gt;origin&lt;/strong&gt;, and the &lt;strong&gt;page&lt;/strong&gt;. Experiences that meet user and origin rules but not page rules can still feed origin-level data. Pages and origins appear and disappear automatically as eligibility changes. You cannot manually submit a site for inclusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User eligibility&lt;/strong&gt; means the visit came from a Chrome user whose settings allow contribution to the statistics dataset. Not every browser, privacy mode, or visitor is included. CrUX is a sample, not a full count of all traffic in analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Origin eligibility&lt;/strong&gt; needs two properties: the origin must be &lt;strong&gt;publicly discoverable&lt;/strong&gt;, and it must be &lt;strong&gt;sufficiently popular&lt;/strong&gt;. Discoverability is about whether the root of the origin can be treated as a public page (indexing and successful HTTP status on the root matter; blocked or failing roots are a common trap). Popularity means enough eligible experiences across the origin’s pages for Google to publish anonymised distributions. The exact threshold is not disclosed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page eligibility&lt;/strong&gt; adds that the specific URL must also be popular enough for URL-level distributions. A thin blog post or campaign landing page can lack URL-level CrUX while the origin still has field data. That is expected on long-tail templates.&lt;/p&gt;

&lt;p&gt;HTTP versus HTTPS and &lt;code&gt;www&lt;/code&gt; versus apex are different origins. So are subdomains. &lt;code&gt;https://shop.example.com&lt;/code&gt; does not inherit CrUX from &lt;code&gt;https://www.example.com&lt;/code&gt;. When someone says “the client site has no CrUX data,” name the origin string you queried, including scheme and host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an origin is missing from CrUX entirely
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wrong origin string.&lt;/strong&gt; When tools say the origin is not in the Chrome UX Report, check the origin string before you promise a timeline for field data, then move on to discoverability and sample size. Teams often query &lt;code&gt;http://&lt;/code&gt;, omit or add &lt;code&gt;www&lt;/code&gt;, or paste a path when the API expects an origin. The CrUX API docs recommend comparing the navigable final URL after redirects with the origin you requested. A 404-style “chrome ux report data not found” response is common when the string is simply wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root not publicly discoverable.&lt;/strong&gt; If the root redirects in a way that systems treat as undiscoverable, or if the root fails indexing / HTTP status checks, the origin can drop out even when inner URLs get traffic. Chromium discussion threads have long noted redirect-heavy roots as a reason PageSpeed Insights may show URL-level data after following a redirect while origin-level data is missing. Fix discoverability before you blame sample size alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not enough eligible Chrome traffic.&lt;/strong&gt; Small sites, brand-new launches, sites that behave like private apps, and niches with little opted-in Chrome usage may never meet popularity. Google does not publish the cut-off. In our experience, waiting a few more PageSpeed Insights refreshes does not create an origin that is structurally ineligible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not a ranking penalty by itself.&lt;/strong&gt; Missing CrUX data is not the same as Search saying the site is slow. It means Google does not have enough public field evidence to publish Core Web Vitals percentiles for that origin or URL slice. Search Console may still show limited or grouped signals. Do not invent a field fail from a blank PageSpeed Insights field block.&lt;/p&gt;

&lt;h2&gt;
  
  
  URL-level gaps when the origin still has field data
&lt;/h2&gt;

&lt;p&gt;If origin-level field data exists but the client’s main URL shows no URL-level CrUX, you are usually looking at popularity at the page layer, not a dead origin. Homepage and key templates often qualify first; checkout steps, locale paths, and campaign URLs lag. PageSpeed Insights may still show origin-level field categories while the URL field rows are empty. Label that clearly in reports so nobody presents a Core Web Vitals pass for a thin URL using only origin-level fallback.&lt;/p&gt;

&lt;p&gt;When the gap is “this metric is missing but others appear,” use the dedicated guide for missing CLS or INP field rows. When the gap is “this URL has no field block but the origin does,” keep synthetic monitoring on that URL and wait for samples. Do not treat origin green as URL green in a client report; say which level the numbers come from.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to tell the client when field data is unavailable
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What we know.&lt;/strong&gt; Use a short script so the conversation stays honest across accounts. CrUX has no (or incomplete) field data for [origin or URL] right now. That usually means eligibility: discoverability, traffic sample size, or the wrong host/scheme, not a broken lab test. We should confirm the origin string before we talk about traffic volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we do not claim.&lt;/strong&gt; We are not saying the page passes or fails Core Web Vitals in the field. We do not have the percentiles yet. Lab scores alone cannot fill that gap in a report to the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we will watch instead.&lt;/strong&gt; Scheduled lab tests on the homepage and other priority URLs (mobile and desktop as separate rows), with budgets and alerts, until URL-level or origin-level field data appears. We will re-check CrUX on a fixed schedule and say when field rows show up. That gives the retainer a measurable trail while field data is empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we need from them.&lt;/strong&gt; Confirm the public origin (HTTPS, www or apex), that the root is indexable, and which URLs matter for the retainer. If the root redirects oddly or blocks indexing, that is an eligibility fix, not a Lighthouse tweak. Without a correct public root, more lab runs will not create CrUX rows. Pair that script with &lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough" rel="noopener noreferrer"&gt;PageSpeed Insights vs Automated Monitoring&lt;/a&gt;: one-off PageSpeed Insights explains a moment, and scheduled runs explain change over time when field data cannot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to monitor instead: synthetic budgets on priority URLs
&lt;/h2&gt;

&lt;p&gt;Until field data is available, synthetic (lab) monitoring is what you can report against week to week. Pick a small URL set: homepage, primary landing templates, and checkout or lead paths. Run the same lab profile on a schedule, store history, and alert when LCP, CLS, or related lab metrics cross a budget. &lt;a href="https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio" rel="noopener noreferrer"&gt;How to Schedule PageSpeed Monitoring&lt;/a&gt; covers frequency and priority across a portfolio. Synthetic versus real-user roles are spelled out in the synthetic vs RUM guide linked earlier.&lt;/p&gt;

&lt;p&gt;Lab data will not replace field eligibility, but it stops the retainer from depending on a blank CrUX panel. When origin or URL field data appears, add it to the same report without throwing away the lab history that covered the gap. In Apogee Watcher, scheduled PageSpeed Insights–backed checks keep that lab trail across client sites while CrUX field rows are absent or partial.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does “CrUX no data” mean the site is slow?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. It means Google does not have enough eligible Chrome samples (or the origin is not publicly discoverable in the way CrUX requires) to publish field percentiles. Lab tools can still diagnose the template while you wait for eligibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we force a site into the Chrome UX Report?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Inclusion is automatic when eligibility is met. You cannot manually submit an origin. Fix discoverability and grow real Chrome traffic, then re-check later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does PageSpeed Insights show lab scores but no field section?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Lab data comes from Lighthouse on demand. Field data comes from CrUX only when eligibility passes. Both can appear on one PageSpeed Insights page, and either side can be missing independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are subdomains included with the main domain?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Each origin is separate. &lt;code&gt;https://blog.example.com&lt;/code&gt; needs its own eligibility. Query the origin the client actually cares about, including scheme and host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long until field data appears after a launch?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
There is no public SLA. CrUX uses a rolling collection window and popularity thresholds. New or low-traffic origins can stay empty for a long time. Plan synthetic monitoring from day one rather than waiting for CrUX before you set budgets.&lt;/p&gt;

&lt;h2&gt;
  
  
  CTA
&lt;/h2&gt;

&lt;p&gt;If a client site shows CrUX no data, name the origin, check discoverability and host/scheme, and say clearly that field percentiles are unavailable. Then put synthetic budgets on the priority URLs so the retainer still has numbers to report on a schedule. For metric-level PageSpeed Insights gaps, use the no CLS/INP guide. For turning one-off PageSpeed Insights into a schedule across many clients, start with &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;Apogee Watcher&lt;/a&gt; or run a check on a public URL from the homepage tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/crux/methodology" rel="noopener noreferrer"&gt;CrUX methodology&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/crux" rel="noopener noreferrer"&gt;Overview of CrUX&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/crux/guides/crux-api" rel="noopener noreferrer"&gt;How to use the CrUX API&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-no-cls-inp-for-url" rel="noopener noreferrer"&gt;When PageSpeed Insights Shows No CLS or INP for Your URL&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026" rel="noopener noreferrer"&gt;What Are Core Web Vitals? A Practical Guide for 2026&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough" rel="noopener noreferrer"&gt;PageSpeed Insights vs Automated Monitoring: When Manual Checks Aren't Enough&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio" rel="noopener noreferrer"&gt;How to Schedule PageSpeed Monitoring: Test Frequency and Priority Across a Portfolio&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>seo</category>
    </item>
    <item>
      <title>Multi-tenant PageSpeed monitoring under $100: what agencies actually buy</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Sat, 10 Oct 2026 07:37:39 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/multi-tenant-pagespeed-monitoring-under-100-what-agencies-actually-buy-akg</link>
      <guid>https://dev.to/apogeewatcher/multi-tenant-pagespeed-monitoring-under-100-what-agencies-actually-buy-akg</guid>
      <description>&lt;p&gt;An agency can open ChatGPT, paste a PageSpeed Insights URL, and get a plausible fix list before lunch. That loop feels like monitoring until the account manager asks for last month’s LCP trend across twenty WordPress clients and nobody has a shared schedule, a named alert owner, or a history that survives holiday leave. Multi-tenant PageSpeed monitoring under $100 is not a cheaper way to run one more free check; it is the purchase of portfolio coverage that still fits a three-digit ops line.&lt;/p&gt;

&lt;p&gt;What agencies actually buy in that band is flatter than the vendor shortlist suggests. They buy pooled site and test caps under one organisation subscription, workspaces that keep client brands separate, and reporting an account team can open without pinging the engineer who wrote the cron. The pricing tables and tier caps live on our blog in &lt;a href="https://apogeewatcher.com/blog/affordable-multi-tenant-performance-monitoring-under-100?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=multi-tenant-pagespeed-under-100-agencies-buy" rel="noopener noreferrer"&gt;Affordable Multi-Tenant Performance Monitoring Under $100/Month&lt;/a&gt;. The day-to-day shape of one dashboard across many client sites is in &lt;a href="https://apogeewatcher.com/blog/product-spotlight-multiple-client-sites-one-dashboard?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=multi-tenant-pagespeed-under-100-agencies-buy" rel="noopener noreferrer"&gt;Multiple Client Sites, One Dashboard&lt;/a&gt;. What follows here is the buying story: what lands on the purchase order when the brief says “keep Core Web Vitals coverage under a hundred dollars.”&lt;/p&gt;

&lt;h2&gt;
  
  
  What agencies mean by multi-tenant PageSpeed monitoring under $100
&lt;/h2&gt;

&lt;p&gt;In agency language, multi-tenant means one customer account that holds many client organisations, sites, and schedules without minting a new invoice line per domain. Under $100 means the list price for that organisation-shaped monitor fits a three-digit monthly ceiling before you add flagship real-user monitoring (RUM) seats. The job is scheduled lab coverage on money URLs, CrUX context where PageSpeed Insights publishes it, budgets and alerts with named responders, and history long enough for a quarterly business review.&lt;/p&gt;

&lt;p&gt;That purchase is easy to confuse with adjacent tools. A free PageSpeed Insights run is a diagnostic, an AI chat that proposes CSS changes is a fix assistant, and an uptime product with a small page-speed monitor allowance is infrastructure health with speed as a sidecar. Agencies that say they want multi-tenant PageSpeed monitoring under $100 usually want the portfolio job, not another one-off score.&lt;/p&gt;

&lt;p&gt;If the roster is still under roughly ten priority URLs and one engineer already owns automation, DIY can still hold for a while. Once account managers need shared history and the URL list grows every campaign week, the under-$100 question becomes whether the maths is flat at the organisation or multiplies per monitored slot. That is the fork most agencies hit before they ever open a pricing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI fix loops are not the same purchase as a portfolio schedule
&lt;/h2&gt;

&lt;p&gt;The confusion shows up often on social threads: someone ships an agent that reads Lighthouse findings and opens a pull request, then treats that as “we have monitoring.” Fix loops are useful on sites you can change, yet they are not a substitute for knowing which client homepage went amber on mobile three Tuesdays ago while the developer who owns the agent was offline. The first job remediates; the second proves the roster stayed inside budget when nobody was watching the chat.&lt;/p&gt;

&lt;p&gt;A scheduled portfolio monitor answers a different question. It keeps URL inventories current, runs PageSpeed Insights (or equivalent) on a cadence the retainer can defend, stores history the account team can export, and routes budget breaches to someone other than the person who wrote the workflow. The AI loop still belongs in the stack as a remediation layer on sites you deploy, yet it does not replace the system of record for twenty client origins. Buying under-$100 multi-tenant coverage while also keeping an AI fix assistant is a sensible layering story, but buying only the assistant and calling the retainer “monitored” is how QBR slides become screenshots again. The SOW reads cleaner when both jobs are named, so the account team knows which tool answers which question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually lands on the purchase order
&lt;/h2&gt;

&lt;p&gt;When the buy is honest, the purchase order or statement of work names jobs, not logos. Logos without owners still leave the retainer on hero labour. In our experience the under-$100 multi-tenant buy usually includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a flat organisation subscription with published site and monthly test caps,&lt;/li&gt;
&lt;li&gt;enough workspaces to separate client brands without a second vendor,&lt;/li&gt;
&lt;li&gt;scheduled lab runs on agreed money URLs (not “every URL we ever shipped”),&lt;/li&gt;
&lt;li&gt;shared history and exports the account team can open,&lt;/li&gt;
&lt;li&gt;budgets and alerts with named owners,&lt;/li&gt;
&lt;li&gt;a clear non-goal: this is not deep RUM on every brochure domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What usually does &lt;strong&gt;not&lt;/strong&gt; land on that same line item: unlimited regions and devices per URL, enterprise RUM seats, or a promise to monitor forty properties when the published site cap is twenty-five. Those gaps belong in a later tier or a thinner URL list, not in silent overages. Saying the non-goals out loud is cheaper than explaining a surprise invoice mid-engagement.&lt;/p&gt;

&lt;p&gt;Procurement still needs plain wording for the row. That is a different essay from the purchase shape itself; for translating milliseconds into finance language, see our Hashnode notes on procurement budgets and selling Core Web Vitals monitoring without calling the line item “latency.” Here the decision is simpler: either you are buying organisation-scoped scheduled coverage under a three-digit ceiling, or you are still assembling DIY layers and should say so in the SOW. Ambiguous wording is how “monitoring” gets approved as a free checker and then fails the first multi-client review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flat organisation caps versus per-site maths
&lt;/h2&gt;

&lt;p&gt;The under-$100 question collapses to how capacity is counted, and the short table below is the decision frame agencies actually use when three vendor demos arrive in the same week.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pricing shape&lt;/th&gt;
&lt;th&gt;How capacity is counted&lt;/th&gt;
&lt;th&gt;Fits under $100 when…&lt;/th&gt;
&lt;th&gt;Breaks when…&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Per monitored URL / slot&lt;/td&gt;
&lt;td&gt;Each URL × device × region consumes a slot&lt;/td&gt;
&lt;td&gt;One client, deep lab work&lt;/td&gt;
&lt;td&gt;Twenty clients each need homepage + checkout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-site SaaS seat&lt;/td&gt;
&lt;td&gt;Billing scales with domains&lt;/td&gt;
&lt;td&gt;Portfolio stays tiny&lt;/td&gt;
&lt;td&gt;Retainer count grows faster than tool budget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flat organisation cap&lt;/td&gt;
&lt;td&gt;Sites, tests, workspaces pool under one subscription&lt;/td&gt;
&lt;td&gt;Roster grows inside published limits&lt;/td&gt;
&lt;td&gt;You exceed site or test caps and need the next tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DIY scripts + API&lt;/td&gt;
&lt;td&gt;Cash cost is low; labour is not&lt;/td&gt;
&lt;td&gt;One engineer owns the pipeline&lt;/td&gt;
&lt;td&gt;Quota, reporting, and on-call become unpaid platform work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Agencies that stay under $100 with multi-tenant coverage almost always pick the flat organisation row and accept published caps. Per-slot tools can still win for a single high-traffic property; they are a poor match for “monitor the whole WordPress roster for under a hundred.” DIY wins on cash until the labour row on the same budget is honest. If you cannot name that labour owner, you are not really choosing DIY; you are deferring the purchase. Apogee Watcher’s Professional tier is built as that flat-cap shape under the $100 line at list pricing, with Agency as the published step when site or workspace caps bite. Current numbers live on the &lt;a href="https://apogeewatcher.com/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;, and the buyer story does not change when a list price moves by a few dollars: you are still choosing organisation caps versus per-site multiplication.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DIY still wins the budget
&lt;/h2&gt;

&lt;p&gt;DIY PageSpeed Insights API scripts, Lighthouse CI, sheets, and a workflow tool still win the purchase when three conditions hold together: the portfolio is small enough that one person can keep URL lists accurate, nobody expects branded client PDFs from the monitoring layer itself, and the team already treats automation ownership as billable engineering time rather than free evenings.&lt;/p&gt;

&lt;p&gt;DIY stops winning the under-$100 comparison when any of these repeat: campaign URLs ship and never join the sheet; the digest dies on leave; account managers rebuild slides from CSV; “nightly for everyone” became “nightly for whoever we remembered” under API quota. At that point a flat-cap portfolio monitor is usually cheaper than the labour you were pretending was free, even when the SaaS line sits at $79 rather than $0. The cash line looks worse; the retainer maths usually looks better. DIY still fits as a layer after the portfolio monitor is in place (Lighthouse CI on templates you ship, manual PageSpeed Insights in teaching conversations), because the purchase under $100 is for the jobs DIY stopped covering reliably, not a mandate to delete every script.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can an agency monitor forty client sites under $100/month?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Often not on a single flat-cap Professional-shaped plan if the published site limit is twenty-five. Realistic under-$100 strategies put priority origins on the paid monitor and leave long-tail pages on free diagnostics, or move to the next published tier when the roster honestly exceeds the cap. Pretending forty equals twenty-five is how retainers over-promise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is an AI agent that fixes Lighthouse issues the same as multi-tenant monitoring?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No: an agent remediates findings on sites you can change, while multi-tenant monitoring schedules checks, stores history, and alerts across many client organisations whether or not you control the repository. Most agencies need both jobs named separately rather than collapsing them into one “AI monitoring” line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should we put on the purchase order so finance understands the buy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Organisation-scoped scheduled PageSpeed / Core Web Vitals coverage, included site and test caps, retention, seats, and reporting are the rows that usually clear finance. A three-digit portfolio monitor is a different purchase from a four-hundred-dollar RUM seat on one flagship property. The SOW reads better when it states what is out of scope as well as what is included.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does multi-tenant PageSpeed monitoring replace uptime tools?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No: uptime and SSL watches answer “is the site reachable,” while portfolio PageSpeed monitoring answers “are LCP, INP, and CLS drifting on money URLs.” Many agencies keep both, because green uptime does not mean green Core Web Vitals, and a green Lighthouse score does not mean the origin stayed up overnight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buy the portfolio job, then layer the rest
&lt;/h2&gt;

&lt;p&gt;What agencies actually buy under $100 for multi-tenant PageSpeed monitoring is organisation-shaped coverage: flat caps, shared schedules, and history the account team can defend in a review. AI fix loops, free checkers, CI gates, and selective RUM stay in the stack as layers, yet they are not the same line item. The pricing maths and tier caps sit in &lt;a href="https://apogeewatcher.com/blog/affordable-multi-tenant-performance-monitoring-under-100?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=multi-tenant-pagespeed-under-100-agencies-buy" rel="noopener noreferrer"&gt;Affordable Multi-Tenant Performance Monitoring Under $100/Month&lt;/a&gt;. For the product shape of many clients in one view, &lt;a href="https://apogeewatcher.com/blog/product-spotlight-multiple-client-sites-one-dashboard?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=multi-tenant-pagespeed-under-100-agencies-buy" rel="noopener noreferrer"&gt;Multiple Client Sites, One Dashboard&lt;/a&gt; is the shorter walkthrough, and you can &lt;a href="https://apogeewatcher.com/check" rel="noopener noreferrer"&gt;run a check&lt;/a&gt; on a client URL before schedules move into a trial.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt; (Google)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/speed/docs/insights/v5/get-started" rel="noopener noreferrer"&gt;PageSpeed Insights API&lt;/a&gt; (Google)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/pricing" rel="noopener noreferrer"&gt;Apogee Watcher pricing&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/affordable-multi-tenant-performance-monitoring-under-100" rel="noopener noreferrer"&gt;Affordable Multi-Tenant Performance Monitoring Under $100/Month&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/product-spotlight-multiple-client-sites-one-dashboard" rel="noopener noreferrer"&gt;Multiple Client Sites, One Dashboard&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>agency</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Lazy Loading for LCP and CLS: When to Use loading="lazy" (and When Not To)</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Sat, 10 Oct 2026 07:35:19 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/lazy-loading-for-lcp-and-cls-when-to-use-loadinglazy-and-when-not-to-45id</link>
      <guid>https://dev.to/apogeewatcher/lazy-loading-for-lcp-and-cls-when-to-use-loadinglazy-and-when-not-to-45id</guid>
      <description>&lt;p&gt;Lazy loading images and a fast Largest Contentful Paint (LCP) pull in opposite directions when the same rule is applied to every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. Deferring offscreen bytes is usually right, but deferring the hero that PageSpeed Insights later names as LCP is usually wrong. The &lt;code&gt;loading="lazy"&lt;/code&gt; attribute is only a browser hint for that trade-off. It is not a global “make the site faster” switch that themes and optimisation plugins can sprinkle without review.&lt;/p&gt;

&lt;p&gt;What follows is a decision guide for agencies and product teams: when lazy loading images helps, when it hurts LCP or Cumulative Layout Shift (CLS), and how to prove the change with scheduled lab checks rather than one green Lighthouse run. For the wider image pipeline (formats, sizing, CDN), keep &lt;a href="https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores" rel="noopener noreferrer"&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; open beside this piece. When text paint competes with the hero, &lt;a href="https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp" rel="noopener noreferrer"&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt; still belongs in the same sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the &lt;code&gt;loading="lazy"&lt;/code&gt; attribute does
&lt;/h2&gt;

&lt;p&gt;The HTML &lt;code&gt;loading&lt;/code&gt; attribute on &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; tells supporting browsers whether to fetch the resource immediately or wait until it is near the viewport. Per &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading" rel="noopener noreferrer"&gt;MDN’s lazy loading guide&lt;/a&gt; and &lt;a href="https://web.dev/articles/browser-level-image-lazy-loading" rel="noopener noreferrer"&gt;web.dev’s browser-level image lazy loading article&lt;/a&gt;, &lt;code&gt;loading="lazy"&lt;/code&gt; is the deferred path and &lt;code&gt;loading="eager"&lt;/code&gt; (or omitting the attribute for images that default to eager) is the immediate path. Native lazy loading replaced most custom Intersection Observer snippets for ordinary image galleries, yet the browser still decides &lt;em&gt;how far&lt;/em&gt; ahead of the viewport it starts the fetch.&lt;/p&gt;

&lt;p&gt;That nuance matters for agency audits. “We enabled lazy loading” can mean native attributes, a WordPress filter that injects &lt;code&gt;loading="lazy"&lt;/code&gt; on every attachment, a Shopify theme setting, or a JavaScript library that swaps &lt;code&gt;data-src&lt;/code&gt; after scroll. All of those can defer the LCP candidate if the first screen image is included, so the mechanism belongs in the ticket before anyone blames hosting.&lt;/p&gt;

&lt;p&gt;Native lazy loading is progressive enhancement: older browsers ignore unknown attributes and load images normally. That is fine for bandwidth on modern Chrome and Safari, yet it does not excuse shipping a hero with &lt;code&gt;loading="lazy"&lt;/code&gt; on the browsers that dominate your CrUX population. Progressive enhancement is not permission to defer the element field users actually paint as LCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why lazy-loading the LCP image hurts Largest Contentful Paint
&lt;/h2&gt;

&lt;p&gt;LCP marks when the largest above-the-fold content element becomes visible. On marketing and commerce pages that element is often a hero image, product photo, or poster frame. If that resource is marked &lt;code&gt;loading="lazy"&lt;/code&gt;, the browser may delay the request until layout work suggests the image is “near” the viewport, even though it already is. The result shows up as higher &lt;strong&gt;resource load delay&lt;/strong&gt; in Lighthouse and PageSpeed Insights, and as a worse lab LCP, which Google’s &lt;a href="https://web.dev/blog/common-misconceptions-lcp" rel="noopener noreferrer"&gt;common LCP misconceptions&lt;/a&gt; post still flags as a frequent own-goal.&lt;/p&gt;

&lt;p&gt;Search threads for “lazy load LCP” are full of Elementor, WordPress, and theme support tickets for the same pattern: a plugin or theme applied lazy loading sitewide, the logo or banner became LCP, and scores collapsed until someone excluded the first image. Weston Ruter’s comparison demos of lazy-loaded versus eager LCP images make the timing difference visible without arguing theory. Disabling lazy load on the LCP image is a first triage step in those threads, not a last resort after a CDN rewrite.&lt;/p&gt;

&lt;p&gt;The fix is usually boring. Once PageSpeed Insights or Chrome Performance names the LCP element, remove &lt;code&gt;loading="lazy"&lt;/code&gt; from that image (and any identical mobile/desktop sources in &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;). &lt;code&gt;fetchpriority="high"&lt;/code&gt; fits when you know the LCP URL early; a preload fits only when the markup path cannot put that URL in the initial HTML. Preloading and lazy-loading the same URL fights itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When lazy loading images is the right default
&lt;/h2&gt;

&lt;p&gt;Lazy loading images is the right default for content that starts offscreen: article body photos after the fold, related-product grids, footer badges, long category galleries, and comment avatars. Those bytes should not compete with the critical path on first paint. On a twenty-image blog post, native lazy loading can cut early bandwidth sharply on mobile without changing the story the user sees first.&lt;/p&gt;

&lt;p&gt;On retainer sites we treat eager versus lazy as a short policy, not a plugin toggle. Eager (no lazy, or explicit eager) covers the LCP candidate, a logo when it is LCP, the primary above-the-fold product image, and any image inside the first viewport on common breakpoints. Lazy covers everything that requires scroll or a tab change before it matters.&lt;/p&gt;

&lt;p&gt;That policy needs a mobile-width check as well as desktop. An image that looks “below the fold” on a large monitor can sit in the first screen on a phone, and that phone traffic often dominates CrUX. Audits that only run at 1440px tend to lazy-load the wrong assets for the field population.&lt;/p&gt;

&lt;h2&gt;
  
  
  Above-the-fold images, &lt;code&gt;fetchpriority&lt;/code&gt;, and eager loading
&lt;/h2&gt;

&lt;p&gt;“Above the fold” is not a CSS property; it is a judgement about what appears in the initial viewport for your primary breakpoints. When that judgement is wrong, lazy loading above the fold recreates the LCP delay problem even if the CMS labelled the block “content” rather than “hero.” Breakpoints disagree more often than teams expect, especially between a design mockup and a phone-width lab run.&lt;/p&gt;

&lt;p&gt;For the confirmed LCP image, &lt;code&gt;loading="lazy"&lt;/code&gt; comes off (or &lt;code&gt;loading="eager"&lt;/code&gt; overrides a stack that injects lazy by default), accurate &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; or aspect-ratio CSS reserve layout space, and &lt;code&gt;fetchpriority="high"&lt;/code&gt; fits when the image is the clear LCP candidate and other resources are not already marked high. An appropriately sized file matters so eager does not mean downloading a 4000px PNG; the image optimisation post linked above covers formats and &lt;code&gt;srcset&lt;/code&gt;. Theme and page-builder defaults often invert that list: every attachment gets lazy, none get fetch priority, and the hero is still a huge JPEG. Attribute policy belongs ahead of another CDN plan. A smaller eager hero usually beats a huge lazy hero on LCP, even when the waterfall looks “optimised” in a plugin dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iframes, video, and other lazy media caveats
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute also applies to &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, so below-the-fold embeds (maps, secondary YouTube players, chat widgets) are usually sensible lazy candidates. A first-screen video iframe that is also your LCP or a large layout box can delay paint and still risk CLS if dimensions are missing. A facade (poster image + click-to-load) fits heavy third-party players when the embed is not required for the first view. That pattern pairs with &lt;a href="https://apogeewatcher.com/blog/cross-origin-youtube-embeds-and-cls-what-publishers-can-actually-fix" rel="noopener noreferrer"&gt;Cross-Origin YouTube Embeds and CLS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Background images in CSS cannot use &lt;code&gt;loading="lazy"&lt;/code&gt;. If the LCP element is a CSS background, attribute fixes will not help; you need a real &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; in the document, or a different LCP strategy. JavaScript lazy libraries that leave &lt;code&gt;src&lt;/code&gt; empty until hydration can also create late discovery worse than native lazy, especially when the library bundle itself is deferred. Video posters and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements have their own preload behaviour, so “lazy images are on” does not automatically cover posters and iframes. The LCP node type in the trace matters, because a poster frame can win LCP while the checklist only mentions &lt;code&gt;&amp;lt;img loading&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy loading and CLS: reserve space first
&lt;/h2&gt;

&lt;p&gt;Lazy loading does not cause CLS by itself; missing dimensions do. When a lazy image finally loads into a box with no reserved height, the page shifts and CLS rises. That failure mode is easy to miss in a lab run that never scrolls to the image, then appears in field data when users do scroll.&lt;/p&gt;

&lt;p&gt;Lazy loading images still needs intrinsic size hints: &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes, width/height in CMS media metadata, or CSS aspect-ratio on the container. Responsive &lt;code&gt;srcset&lt;/code&gt; still needs a consistent aspect ratio across candidates. If a theme wraps images in a collapsing container until load, the container belongs in the ticket before anyone argues about Core Web Vitals thresholds. Hero images that are eager still need reserved space: eager versus lazy is an LCP timing decision, while dimensioning is a CLS decision, so agencies should treat them as two checklist rows rather than one vague “images” ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lab vs field when lazy loading hides LCP regressions
&lt;/h2&gt;

&lt;p&gt;A single PageSpeed Insights run on the homepage can look fine after you “enable lazy loading,” especially if the lab viewport and your CMS preview disagree about what is on screen. Field LCP in CrUX or the PageSpeed Insights field section can still worsen when real devices, slower networks, and cookie banners change which element wins LCP. Mobile users may also hit a lazy hero that desktop lab never marked as LCP, so one desktop screenshot is not proof.&lt;/p&gt;

&lt;p&gt;Scheduled lab checks on money URLs (home, category, product, key landing pages) before and after attribute changes, on both mobile and desktop strategies, keep the claim honest. LCP element identity matters more than the score alone. If the LCP node switches from a heading to an image after a deploy, that image’s lazy attribute is the next place to look. For portfolio monitoring across many client sites, Apogee Watcher keeps those lab histories in one place so an attribute change does not vanish into a one-off PDF.&lt;/p&gt;

&lt;p&gt;Lab green and field amber can both be honest, because lab may scroll less, block third parties differently, or use a colder cache. When lazy loading is in the diff, read resource load delay for the LCP URL in the lab diagnostics before you close the ticket. If load delay stays high after “optimisation,” suspect the attribute before you rewrite the media query set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agency checklist before you ship “lazy everything”
&lt;/h2&gt;

&lt;p&gt;Before a theme update or “speed plugin” goes to production, a short pass usually pays for itself. The current LCP element and time on mobile and desktop for each money URL set the baseline, then templates and plugin settings get a search for global &lt;code&gt;loading="lazy"&lt;/code&gt; injection. The LCP candidate (and logo if needed) stays off the lazy list, and width/height or aspect-ratio get confirmed on lazy and eager images alike. Lab checks run again until the LCP element and load delay move the right way; field LCP is watched for the 28-day window after release rather than declared fixed on day one; and the exclusion list is written down so the next plugin install does not re-lazy the hero. That pass is cheaper than a month of “we improved PageSpeed” conversations while CrUX stays amber, and it gives the next developer a written exclusion list instead of tribal knowledge about “the hero must stay eager.” The list belongs in the repository or the retainer runbook so plugin reinstalls do not undo it quietly.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Should every image use &lt;code&gt;loading="lazy"&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No: lazy loading images is for offscreen content, while the LCP image and other critical above-the-fold images should load eagerly. Sitewide lazy defaults from CMS plugins are a common source of LCP regressions on retainers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does &lt;code&gt;loading="lazy"&lt;/code&gt; on the LCP image always break field data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not always, because browsers and viewports differ, but it is a high-risk pattern that Lighthouse and many case studies associate with longer LCP. The LCP candidate usually stays eager unless you have measured no harm on mobile and desktop for that template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is native lazy loading better than a JavaScript lazy library?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For ordinary images, native lazy loading is usually enough and avoids waiting on a script. Libraries still appear for older patterns or fancy placeholders; they must not leave the LCP &lt;code&gt;src&lt;/code&gt; undiscovered until late JavaScript runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can lazy loading improve CLS?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Indirectly, only if it reduces contention and you already reserve space. Lazy loading without dimensions often worsens CLS when images pop in during scroll, so sizing belongs ahead of another lazy-loading toggle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about logos?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the logo is the LCP element (common on simple brochure sites), it should stay eager. If a large hero is LCP and the logo is small, the logo can follow normal theme defaults, but still reserve space to avoid header shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ship eager heroes, lazy galleries
&lt;/h2&gt;

&lt;p&gt;Lazy loading images remains one of the strongest bandwidth defaults on long pages, as long as the LCP image stays eager, dimensions protect CLS, and iframes or video facades are handled on purpose. The &lt;code&gt;loading="lazy"&lt;/code&gt; attribute is a scalpel for offscreen media, not a blanket for every attachment ID in the CMS. The exclusion list travels with the theme update so the next speed plugin cannot quietly reverse it.&lt;/p&gt;

&lt;p&gt;For format and sizing work around the same LCP element, continue with &lt;a href="https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores" rel="noopener noreferrer"&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt;. When font files compete with the hero, use &lt;a href="https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp" rel="noopener noreferrer"&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt;. To keep attribute changes honest across a client roster, &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;start a free trial&lt;/a&gt; or &lt;a href="https://apogeewatcher.com/check" rel="noopener noreferrer"&gt;run a check&lt;/a&gt; on a money URL before and after you remove lazy from the hero.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://web.dev/articles/browser-level-image-lazy-loading" rel="noopener noreferrer"&gt;Browser-level image lazy loading for the web&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading" rel="noopener noreferrer"&gt;Lazy loading&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/blog/common-misconceptions-lcp" rel="noopener noreferrer"&gt;Common misconceptions about how to optimize LCP&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading" rel="noopener noreferrer"&gt;HTML attribute: loading&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores" rel="noopener noreferrer"&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp" rel="noopener noreferrer"&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gtmetrix.com/dont-lazy-load-lcp-image.html" rel="noopener noreferrer"&gt;Lighthouse: Don't lazy load Largest Contentful Paint image&lt;/a&gt; (GTmetrix / Lighthouse audit explanation)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/cross-origin-youtube-embeds-and-cls-what-publishers-can-actually-fix" rel="noopener noreferrer"&gt;Cross-Origin YouTube Embeds and CLS: What Publishers Can Actually Fix&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>seo</category>
    </item>
    <item>
      <title>What PageSpeed monitoring stack should an agency run in 2026?</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:55:41 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/what-pagespeed-monitoring-stack-should-an-agency-run-in-2026-1j9i</link>
      <guid>https://dev.to/apogeewatcher/what-pagespeed-monitoring-stack-should-an-agency-run-in-2026-1j9i</guid>
      <description>&lt;p&gt;The roster hits twenty client sites, yet the “monitoring stack” is still a shared folder of PageSpeed Insights screenshots, one engineer’s n8n flow nobody else can edit, and a promise to check Core Web Vitals before the QBR. That is not a PageSpeed monitoring stack for agencies; it is a coping habit with a product roadmap glued on. The gap shows up the first time two account managers need last month’s LCP trend and only one person knows which sheet tab is current.&lt;/p&gt;

&lt;p&gt;What agencies should run in 2026 is usually simpler than the vendor shortlist suggests. A multi-site portfolio monitor works best as the system of record for lab history, budgets, and alert ownership, while DIY PageSpeed Insights scripts and Lighthouse CI stay as layers on sites you deploy. Paid real-user monitoring (RUM) belongs on the one or two flagship properties where field depth pays for itself; everything else is optional seasoning.&lt;/p&gt;

&lt;p&gt;The full recipes and failure modes live on our blog in &lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pagespeed-monitoring-stack-agency-2026" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt;, and the feature checklists sit in &lt;a href="https://apogeewatcher.com/blog/comparing-pagespeed-monitoring-tools-features-agencies-need?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pagespeed-monitoring-stack-agency-2026" rel="noopener noreferrer"&gt;Comparing PageSpeed Monitoring Tools&lt;/a&gt;. What follows here is the opinionated pick: which stack to run first when the account team asks for a decision, not another comparison table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a PageSpeed monitoring stack is (for agencies)
&lt;/h2&gt;

&lt;p&gt;A stack is a small set of jobs with named owners, not a shopping cart of logos. For agency work those jobs are predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scheduled lab coverage on money URLs (PageSpeed Insights or equivalent),&lt;/li&gt;
&lt;li&gt;history an account manager can open without asking engineering,&lt;/li&gt;
&lt;li&gt;budgets and alerts that fire for someone other than the person who wrote the cron,&lt;/li&gt;
&lt;li&gt;optional CI gates on templates you ship,&lt;/li&gt;
&lt;li&gt;optional RUM depth where a snippet and seat cost are justified,&lt;/li&gt;
&lt;li&gt;a clear split between uptime/health tools and Core Web Vitals work (they are not the same purchase).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of those jobs live only in one person’s head, you do not have a stack yet. You have a hero, and heroes do not scale across twenty organisations. Named owners in the tool turn the same checklist into something the account team can run without a private Slack ping.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default stack most agencies should run in 2026
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Default:&lt;/strong&gt; portfolio monitor first for multi-client PageSpeed / Core Web Vitals coverage, DIY and CI as supporting layers, RUM as a selective add-on.&lt;/p&gt;

&lt;p&gt;That default fits when you manage roughly ten or more client sites, sell performance or SEO retainers that mention LCP/INP/CLS, and cannot put a RUM snippet on every brochure domain. The monitor owns schedules, URL inventories, budgets, and shared history; Lighthouse CI stays in the repositories you control; PageSpeed Insights remains the lab dialect clients already recognise in Search Console conversations. Once those three layers are named, the weekly argument stops being “which vendor is best” and becomes “which job is failing.”&lt;/p&gt;

&lt;p&gt;Apogee Watcher is built for that portfolio shape, and peers exist in the same job class. The recommendation is the shape, not a claim that only one vendor can fill it, so layer rather than rip out: keep DebugBear, SpeedCurve, or Calibre where you already pay for flagship RUM, and skip pretending every client needs that seat maths on day one. The unpaid work is deciding which sites never get a snippet, not collecting logos.&lt;/p&gt;

&lt;p&gt;Buying “the best RUM” and rolling it out everywhere sounds tidy until seat cost, privacy reviews, and install friction kill portfolio coverage before the first amber LCP is fixed. Staying on DIY forever sounds frugal until URL lists drift, quotas collide, and reporting hours eat the retainer. The default sits between those failure modes on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DIY PageSpeed Insights + sheets is enough
&lt;/h2&gt;

&lt;p&gt;DIY (PageSpeed Insights API or self-hosted Lighthouse, Lighthouse CI, Sheets or Notion, n8n or cron) is enough when the portfolio is small, one engineer already owns automation, and nobody expects branded client PDFs from the monitoring layer. It also fits when you only need merge gates on sites you deploy, with occasional API checks elsewhere. Outside that band, DIY becomes unpaid platform work dressed up as thrift.&lt;/p&gt;

&lt;p&gt;DIY stops being a sound primary system when any of these show up more than once a month:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;campaign URLs ship and nobody added them to the sheet,&lt;/li&gt;
&lt;li&gt;the digest email dies because the workflow owner is on leave,&lt;/li&gt;
&lt;li&gt;account managers rebuild slides from CSV because clients will not open the spreadsheet,&lt;/li&gt;
&lt;li&gt;“nightly for everyone” became “nightly for whoever we remembered” under API quota.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When those signals repeat, a portfolio monitor becomes the primary system and DIY stays as a layer. That is DIY versus managed PageSpeed without the false choice of deleting your pipelines: managed here means shared schedules and history, not abandoning Lighthouse CI on the templates you still ship. The roster can grow without the monitoring story living in one export again.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to add RUM on flagship sites only
&lt;/h2&gt;

&lt;p&gt;RUM earns its place when a single property funds deep field investigation: high revenue, stubborn INP, or a client who already bought SpeedCurve, DebugBear, or Calibre and needs you to operate it. The portfolio monitor still covers the long tail so brochure sites keep scheduled lab history, because paying for flagship depth while the rest of the roster goes dark is how retainers look busy and still miss regressions. Selective RUM is a budget decision, not a purity test.&lt;/p&gt;

&lt;p&gt;Waiting for perfect RUM coverage before any monitoring starts is the other trap. Multi-site PageSpeed monitoring fails when teams refuse to schedule anything until every domain has a snippet, while lab schedules plus CrUX context from PageSpeed Insights or Search Console (where eligible) already answer most retainer questions. Field depth is a zoom lens, not the only camera.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jobs the stack must cover (without a vendor matrix)
&lt;/h2&gt;

&lt;p&gt;Treat the table below as a go-live checklist: if a row has no owner and no tool, the stack is incomplete, so fill those gaps before another logo appears on the slide.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Default owner in 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled lab on money URLs&lt;/td&gt;
&lt;td&gt;Portfolio monitor (or DIY if still under ~10 priority URLs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge protection on shipped templates&lt;/td&gt;
&lt;td&gt;Lighthouse CI in your repos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared history for account teams&lt;/td&gt;
&lt;td&gt;Portfolio monitor (not a private n8n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Budgets / alerts with named responders&lt;/td&gt;
&lt;td&gt;Portfolio monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep field waterfalls&lt;/td&gt;
&lt;td&gt;RUM on 1–2 flagships only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reachability / SSL / status pages&lt;/td&gt;
&lt;td&gt;Separate uptime suite (layer; do not confuse with CWV)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When someone asks for “the best tools,” the &lt;a href="https://apogeewatcher.com/blog/comparing-pagespeed-monitoring-tools-features-agencies-need?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pagespeed-monitoring-stack-agency-2026" rel="noopener noreferrer"&gt;tools comparison&lt;/a&gt; is the right hand-off. When they ask “what should we run next quarter?,” the default above plus the three recipes on &lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pagespeed-monitoring-stack-agency-2026" rel="noopener noreferrer"&gt;agency PageSpeed stacks&lt;/a&gt; are the operational answer. The first question is research; the second is delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What PageSpeed monitoring stack should an agency run in 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most multi-client agencies, a portfolio PageSpeed / Core Web Vitals monitor is the system of record, DIY scripts and Lighthouse CI stay as layers, and RUM sits only on flagship sites that justify the seat. DIY-only still fits if the roster is tiny and automation is already owned, so write that choice into the retainer scope and sales and delivery argue from the same default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is PageSpeed Insights alone enough?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a diagnostic, yes. As the only continuous system for fifteen retainers, no: you still need schedules, history, budgets, and someone other than the founder to receive the alert.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do we need RUM on every client site?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually not. RUM belongs where revenue or stubborn field issues pay for it, while the long tail stays on scheduled lab monitoring and CrUX where Google publishes it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is this different from a tools roundup?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A roundup lists features; a stack names jobs and a default order of purchase. Use both: pick the shape here, then validate vendors against a feature checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  CTA
&lt;/h2&gt;

&lt;p&gt;If the current “stack” is still screenshots and a private automation, this quarter is a good moment to make a portfolio monitor primary and write DIY exit criteria into the runbook. &lt;a href="https://apogeewatcher.com/sign-up?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pagespeed-monitoring-stack-agency-2026" rel="noopener noreferrer"&gt;A free Apogee Watcher trial&lt;/a&gt; is useful when you want multi-tenant schedules and budgets without rebuilding the sheet again, while RUM and uptime tools stay where they already earn their keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026 (DIY, Portfolio Monitor, RUM + Monitor)&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/comparing-pagespeed-monitoring-tools-features-agencies-need" rel="noopener noreferrer"&gt;Comparing PageSpeed Monitoring Tools: Features Agencies Need&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/speed/docs/insights/v5/get-started" rel="noopener noreferrer"&gt;PageSpeed Insights API&lt;/a&gt; (Google)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/GoogleChrome/lighthouse-ci" rel="noopener noreferrer"&gt;Lighthouse CI&lt;/a&gt; (GoogleChrome)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>agency</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>WordPress Speculation and Prerender Plugins vs Core Web Vitals</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:51:19 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/wordpress-speculation-and-prerender-plugins-vs-core-web-vitals-62d</link>
      <guid>https://dev.to/apogeewatcher/wordpress-speculation-and-prerender-plugins-vs-core-web-vitals-62d</guid>
      <description>&lt;p&gt;WordPress speculative loading started as a Performance Team feature plugin and landed in &lt;a href="https://make.wordpress.org/core/2025/03/06/speculative-loading-in-6-8/" rel="noopener noreferrer"&gt;WordPress 6.8&lt;/a&gt; as Core behaviour for most public front ends. The browser still does the work through the &lt;a href="https://developer.chrome.com/docs/web-platform/prerender-pages" rel="noopener noreferrer"&gt;Speculation Rules API&lt;/a&gt;: JSON rules tell Chromium-class browsers which URLs to prefetch or prerender before the click finishes. Agencies then face a practical choice. Keep Core’s conservative prefetch, install (or leave) the &lt;a href="https://wordpress.org/plugins/speculation-rules/" rel="noopener noreferrer"&gt;Speculative Loading&lt;/a&gt; plugin with stronger prerender defaults, or layer a third-party wordpress prefetch / prerender plugin on top of both.&lt;/p&gt;

&lt;p&gt;That choice is not “faster equals always better.” Speculative loading can make the &lt;em&gt;next&lt;/em&gt; navigation feel instant and can improve Interaction to Next Paint (INP) on the path the user actually takes. It can also pull HTML, scripts, and third-party tags for pages nobody visits, inflate bandwidth on mobile, and confuse first-visit Largest Contentful Paint (LCP) or Cumulative Layout Shift (CLS) when teams measure the wrong navigation. What follows is a WordPress-centric how-to for retainers: when speculation rules help Core Web Vitals, when a wordpress prerender plugin hurts, and how to verify with lab schedules instead of a single homepage paste.&lt;/p&gt;

&lt;p&gt;For broader WordPress monitoring context, see &lt;a href="https://apogeewatcher.com/blog/wordpress-performance-monitoring-complete-guide" rel="noopener noreferrer"&gt;WordPress Performance Monitoring: A Complete Guide&lt;/a&gt;. When the site is still slow after delivery tweaks, keep &lt;a href="https://apogeewatcher.com/blog/wordpress-site-slow-not-always-hosting" rel="noopener noreferrer"&gt;Why Your WordPress Site Is Slow (It Is Not Always Hosting)&lt;/a&gt; in the runbook: speculation will not fix plugin asset storms on the current URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WordPress speculative loading is (prefetch vs prerender)
&lt;/h2&gt;

&lt;p&gt;Speculation rules are progressive enhancement. Unsupported browsers ignore the script. Supported Chromium browsers (Chrome, Edge, Opera at current versions) may act on the rules subject to memory, Data Saver, and other heuristics. Treat every rule as a hint, not a preload contract.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtqays9mfk9zpkbmx00j.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtqays9mfk9zpkbmx00j.webp" alt="Speculation Rules comparison schematic: PREFETCH fetches HTML bytes after a conservative click then navigates and paints; PRERENDER loads a hidden tab with JavaScript on moderate interaction, then activates for a near-instant view. Footer notes progressive enhancement." width="799" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two modes matter on WordPress sites:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What the browser roughly does&lt;/th&gt;
&lt;th&gt;Typical CWV upside&lt;/th&gt;
&lt;th&gt;Main risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prefetch&lt;/td&gt;
&lt;td&gt;Fetches the document (and often related resources) early&lt;/td&gt;
&lt;td&gt;Shorter wait before paint on the next navigation&lt;/td&gt;
&lt;td&gt;Extra bytes if the user never clicks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prerender&lt;/td&gt;
&lt;td&gt;Loads the page in a hidden background state, ready to activate&lt;/td&gt;
&lt;td&gt;Near-instant next navigation; load CLS can finish before activation; INP can look better because work finished early&lt;/td&gt;
&lt;td&gt;Runs client JS earlier; analytics and personalisation bugs; higher CPU/memory; more wasted work on wrong guesses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Chrome’s documentation is explicit: prerender can drive near-zero LCP and reduce CLS for the activated view when load shifts happen before the user sees the page, and it can improve INP because interaction lands on a warmer page. The same docs warn against over-prerendering because of memory and network cost. WordPress Core and the Speculative Loading plugin are different opinions about how aggressive that trade-off should be by default.&lt;/p&gt;

&lt;p&gt;Older wordpress prefetch plugins (Flying Pages-style link hover prefetch, theme “instant page” scripts, some cache-plugin toggles) sit adjacent to this story. Some now emit Speculation Rules; others still use older link-rel or mouseover fetch patterns. For agency audits, treat “prefetch on hover” and “Speculation Rules prerender” as different levers with different failure modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core 6.8 defaults vs the Speculative Loading plugin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://make.wordpress.org/core/2025/03/06/speculative-loading-in-6-8/" rel="noopener noreferrer"&gt;WordPress 6.8&lt;/a&gt; enables speculative loading on the front end by default when the visitor is logged out and the site uses pretty permalinks. The effective Core starting point is &lt;strong&gt;prefetch&lt;/strong&gt; with &lt;strong&gt;conservative&lt;/strong&gt; eagerness: speculation starts around the beginning of a click. That is intentionally close to configurations large CDNs have used at scale. It buys a short head start with a low rate of unused fetches.&lt;/p&gt;

&lt;p&gt;Core disables the feature for logged-in users and when pretty permalinks are off, because query-string “action URLs” (cart adds, favourites, state changes via GET) are common in the plugin ecosystem and must not be guessed into. URLs with query parameters are excluded by default. Filters such as &lt;code&gt;wp_speculation_rules_configuration&lt;/code&gt; and &lt;code&gt;wp_speculation_rules_href_exclude_paths&lt;/code&gt; let engineers raise eagerness, switch to prerender, or exclude path patterns such as &lt;code&gt;/cart/*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://wordpress.org/plugins/speculation-rules/" rel="noopener noreferrer"&gt;Speculative Loading plugin&lt;/a&gt; remains useful after the Core merge. Its defaults are more aggressive: &lt;strong&gt;prerender&lt;/strong&gt; with &lt;strong&gt;moderate&lt;/strong&gt; eagerness (typically on link interaction), plus a Settings → Reading UI for mode and eagerness. The plugin also documents opt-ins for authenticated front-end users when the host can absorb the load (object cache strongly recommended). On WordPress 6.8+, the plugin builds on Core’s API rather than replacing the whole idea; agencies should know which layer owns the live configuration before they “install one more speed plugin.”&lt;/p&gt;

&lt;p&gt;HTTP Archive and CrUX analysis cited in the Core note reported roughly a &lt;strong&gt;1.9%&lt;/strong&gt; median lift in LCP &lt;em&gt;passing rate&lt;/em&gt; for sites that enabled speculative loading via the feature plugin over the study window. That is a population signal, not a promise that every client homepage will drop 200 ms in lab LCP after you flip prerender to moderate.&lt;/p&gt;

&lt;h2&gt;
  
  
  When speculation helps navigation INP and next-page LCP
&lt;/h2&gt;

&lt;p&gt;Speculation pays off when users move through predictable internal links: article → related post, category → product, docs hub → guide. The win shows up on the &lt;em&gt;destination&lt;/em&gt; navigation, not on the cold first entry from search or ads. Agencies selling “instant site” from a single PageSpeed Insights homepage score are measuring the wrong clock.&lt;/p&gt;

&lt;p&gt;Helpful patterns we see in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core &lt;strong&gt;prefetch / conservative&lt;/strong&gt; on content sites with clean pretty permalinks and few GET action URLs.&lt;/li&gt;
&lt;li&gt;Plugin or filter &lt;strong&gt;prerender / moderate&lt;/strong&gt; on a small set of high-confidence destinations (primary nav, top product cards) after cart and account paths are excluded.&lt;/li&gt;
&lt;li&gt;Chromium-heavy audiences (many B2B and ecommerce dashboards) where progressive enhancement still covers Safari/Firefox users without harm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;INP can improve on the activated page because main-thread work and hydration had a head start. Next-page LCP can look excellent when the LCP image and text were already in the prerender. Neither outcome excuses a heavy first HTML response or third-party tags on the URL the user opened first. Speculation multiplies whatever that destination loads; it does not delete unused JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a WordPress prerender plugin hurts first-visit LCP, CLS, or bandwidth
&lt;/h2&gt;

&lt;p&gt;Problems show up when teams install a wordpress prerender plugin (or raise Core to prerender/eager) and then judge success only from a warmed multi-page lab session, or when unused prerenders compete with the current page for CPU and network on mid-range mobiles.&lt;/p&gt;

&lt;p&gt;Common failure modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First visit from search or paid landings stays untouched.&lt;/strong&gt; Speculation does not prerender the entry URL from Google. If mobile LCP is poor on that landing template, fix the LCP resource and server path first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eager or broad prerender on mega-menus.&lt;/strong&gt; Hovering a header with forty links can queue many documents. Bandwidth and main-thread cost rise; field INP on the &lt;em&gt;current&lt;/em&gt; page can worsen while “next page” demos look great in the office.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cart, checkout, account, and nonce URLs.&lt;/strong&gt; Prefetching a GET add-to-cart or wishlist URL can change state without a full navigation. Core excludes many query-string URLs; custom rewrite “action URLs” still need &lt;code&gt;wp_speculation_rules_href_exclude_paths&lt;/code&gt; (or the plugin’s &lt;code&gt;plsr_speculation_rules_href_exclude_paths&lt;/code&gt;) and &lt;code&gt;no-prefetch&lt;/code&gt; / &lt;code&gt;no-prerender&lt;/code&gt; classes on blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics and personalisation.&lt;/strong&gt; Prerender runs page JS early. Providers that do not wait for activation can double-count or set cookies too soon. Chrome documents delaying analytics until activation; many major tags already do this, but custom theme JS often does not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS “improvements” that hide layout debt.&lt;/strong&gt; Load CLS that finishes during prerender may not appear at activation, which is good for users and scores, but it can mask unreserved embeds that still break when prerender is cancelled or unsupported. Keep fixing reserved space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stacked plugins.&lt;/strong&gt; Core + Speculative Loading + Flying Pages + a cache plugin’s “preload links” toggle can emit overlapping hints. Pick one speculation owner per site.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If lab LCP on the entry URL got worse after enabling prerender, check whether the test device is fighting background prerenders while measuring the current document. If field LCP improved only on internal navigations, say so in the client report; do not imply organic landing LCP moved the same way. Separating those clocks is what keeps the retainer honest when a plugin changelog promises “instant LCP.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Safe settings for agency WordPress retainers
&lt;/h2&gt;

&lt;p&gt;Use a staged default rather than a global “enable prerender” checkbox on every brochure site.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site type&lt;/th&gt;
&lt;th&gt;Starting point&lt;/th&gt;
&lt;th&gt;Escalate only when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Marketing / blog, pretty permalinks&lt;/td&gt;
&lt;td&gt;Core prefetch / conservative (6.8 default)&lt;/td&gt;
&lt;td&gt;Internal nav is the KPI and Chromium share is high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WooCommerce / membership&lt;/td&gt;
&lt;td&gt;Core default + exclude &lt;code&gt;/cart/*&lt;/code&gt;, checkout, account, wishlist paths&lt;/td&gt;
&lt;td&gt;Host capacity proven; action URLs audited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-traffic content with clear next clicks&lt;/td&gt;
&lt;td&gt;Speculative Loading plugin or Core filter to prerender / moderate on selected patterns&lt;/td&gt;
&lt;td&gt;Analytics and tag managers verified under prerender&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logged-in app-like front end&lt;/td&gt;
&lt;td&gt;Leave disabled until object cache and exclusions exist&lt;/td&gt;
&lt;td&gt;Product owners accept extra authenticated load&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Agency checklist before go-live:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm WordPress version and whether Core already injects speculation rules (View Source for a &lt;code&gt;speculationrules&lt;/code&gt; script type).&lt;/li&gt;
&lt;li&gt;Inventory other prefetch/prerender plugins and cache-plugin toggles so one owner remains.&lt;/li&gt;
&lt;li&gt;Exclude cart, checkout, logout, nonce, and any GET action paths.&lt;/li&gt;
&lt;li&gt;Decide logged-in behaviour explicitly (usually off).&lt;/li&gt;
&lt;li&gt;Document mode and eagerness in the retainer runbook so the next plugin cleanup does not reset them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Theme and page-builder “instant load” marketing copy is not a configuration record. Write the actual mode (&lt;code&gt;prefetch&lt;/code&gt; vs &lt;code&gt;prerender&lt;/code&gt;) and eagerness (&lt;code&gt;conservative&lt;/code&gt; / &lt;code&gt;moderate&lt;/code&gt; / &lt;code&gt;eager&lt;/code&gt;) into the handoff. The next engineer should not have to reverse-engineer View Source to learn what you enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to verify with lab schedules and field data
&lt;/h2&gt;

&lt;p&gt;Measure two journeys separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entry URL (first visit):&lt;/strong&gt; PageSpeed Insights or scheduled Lighthouse on the money landing template with a cold load. Speculation should not be the primary fix here. Watch LCP resource, TTFB, and third-party blocking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Internal navigation:&lt;/strong&gt; From a listing or article, follow a primary link in Chrome with Speculation Rules debugging enabled (Chrome documents debugging flows for prerender). Compare activation feel and performance panel timings with rules on versus off. For portfolio retainers, keep scheduled lab history on both the entry URL and one representative destination URL so a plugin change cannot hide behind a single score.&lt;/p&gt;

&lt;p&gt;Field data (CrUX via PageSpeed Insights or Search Console) mixes navigations. A rise in origin LCP after enabling prerender may reflect faster subsequent views, a changing Chrome population, or unrelated template work. Annotate the speculation change in your monitoring notes the same week you ship it. &lt;a href="https://apogeewatcher.com/blog/wordpress-performance-monitoring-complete-guide" rel="noopener noreferrer"&gt;WordPress Performance Monitoring: A Complete Guide&lt;/a&gt; covers ongoing schedules; use those schedules so “we turned on prerender” is a dated event next to the charts.&lt;/p&gt;

&lt;p&gt;Apogee Watcher fits the verification loop for agencies: multi-site lab schedules on entry and destination URLs, budgets when LCP regresses after a plugin change, and history account managers can open without re-running a laptop test. Speculation remains a WordPress and browser feature; monitoring tells you whether the retainer got faster for the journeys you sell. Without that history, every prerender debate restarts from a single screenshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What are WordPress speculation rules?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They are Speculation Rules API instructions WordPress prints so compatible browsers can prefetch or prerender likely next URLs. WordPress 6.8 includes a conservative prefetch default for logged-out users on pretty-permalink sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the Speculative Loading plugin still needed on WordPress 6.8?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Often yes if you want prerender, moderate eagerness, or a wp-admin UI. Core’s default is safer and milder. The plugin (or Core filters) is the escalation path, not a required install on every site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will a wordpress prerender plugin fix homepage LCP from Google?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually not by itself. Speculation targets subsequent navigations. Fix the landing template’s LCP resource, CSS, and server response for entry traffic first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can speculative loading break WooCommerce?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It can if add-to-cart or other GET action URLs are guessed. Cart, checkout, and account paths belong on the exclude list, and Core’s conservative defaults are the safer starting point until those exclusions are proven. POST-based cart flows remain the healthier pattern regardless of speculation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does wordpress prefetch help Safari and Firefox?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those browsers ignore Speculation Rules today. Users still get a normal navigation; they simply miss the head start. Do not promise cross-browser instant navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we know it helped Core Web Vitals?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compare scheduled lab tests on entry versus destination URLs before and after the change, and annotate field dashboards with the ship date. Destination LCP or INP gains matter only when entry-URL scores and bandwidth stay within the budgets you already sold.&lt;/p&gt;




&lt;p&gt;If a client’s WordPress stack already ships Core 6.8, start by documenting the live speculation configuration before installing another prerender plugin. Keep lab schedules on the URLs you sell in the retainer, and treat speculation as a navigation optimisation with explicit exclusions. &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;Start a free Apogee Watcher trial&lt;/a&gt; when you want those WordPress URLs monitored across clients without pasting PageSpeed Insights by hand after every plugin toggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://make.wordpress.org/core/2025/03/06/speculative-loading-in-6-8/" rel="noopener noreferrer"&gt;Speculative Loading in 6.8&lt;/a&gt; (Make WordPress Core)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wordpress.org/plugins/speculation-rules/" rel="noopener noreferrer"&gt;Speculative Loading (WordPress plugin)&lt;/a&gt; (WordPress Performance Team)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/web-platform/prerender-pages" rel="noopener noreferrer"&gt;Prerender pages in Chrome for instant page navigations&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/web-platform/implementing-speculation-rules" rel="noopener noreferrer"&gt;Implementing speculation rules&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API" rel="noopener noreferrer"&gt;Speculation Rules API&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/wordpress-performance-monitoring-complete-guide" rel="noopener noreferrer"&gt;WordPress Performance Monitoring: A Complete Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/wordpress-site-slow-not-always-hosting" rel="noopener noreferrer"&gt;Why Your WordPress Site Is Slow (It Is Not Always Hosting)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>seo</category>
    </item>
    <item>
      <title>TTFB Is Not Only the Server: The Unattributed Slice Agencies Should Name in Reports</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Wed, 07 Oct 2026 06:58:57 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/ttfb-is-not-only-the-server-the-unattributed-slice-agencies-should-name-in-reports-4fnh</link>
      <guid>https://dev.to/apogeewatcher/ttfb-is-not-only-the-server-the-unattributed-slice-agencies-should-name-in-reports-4fnh</guid>
      <description>&lt;p&gt;Time to First Byte is often treated as a synonym for back-end time. In the browser it is wider: everything from the start of the navigation until the first byte of the final response arrives. Redirects, DNS, connection setup, TLS inside that connection, network latency, CDN and origin work, and browser overhead can all sit inside the same number. When agencies paste a high Waiting (TTFB) bar into a client slide and write “server response,” they may be describing only the part the waterfall labels clearly.&lt;/p&gt;

&lt;p&gt;Unattributed Navigation Overhead (UNO) is the residual after you subtract the phases Navigation Timing can name. Harry Roberts documented the metric and the agency reporting problem in &lt;a href="https://csswizardry.com/2026/08/uno-is-underrated/" rel="noopener noreferrer"&gt;UNO Is Underrated&lt;/a&gt;, building on Tim Vereecke’s framing: measure the whole journey to the first byte, subtract every attributed phase, and keep whatever is left. The leftover may be hard to pin on one owner. It is still time users paid for. Naming it stops missing milliseconds from being assigned to origin PHP by default.&lt;/p&gt;

&lt;p&gt;What follows is a how-to for agencies who already walk delivery-layer TTFB in &lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;. When the attributed server phase is the real bottleneck after the residual is accounted for, hand off to &lt;a href="https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme" rel="noopener noreferrer"&gt;TTFB Won't Go Down? Server-Side Culprits Beyond the Theme&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What unattributed navigation overhead (UNO) is
&lt;/h2&gt;

&lt;p&gt;UNO is not a browser-provided metric. It is a calculated remainder:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UNO = TTFB − redirect − DNS − connection − (request → responseStart)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Navigation Timing terms, TTFB for this purpose is &lt;code&gt;responseStart − startTime&lt;/code&gt; (or the nearest equivalent your RUM tool exposes). Subtract the visible redirect span, DNS lookup, full connection span (TCP plus TLS when the API folds them together), and the span from &lt;code&gt;requestStart&lt;/code&gt; to &lt;code&gt;responseStart&lt;/code&gt;. What remains, floored at zero, is UNO.&lt;/p&gt;

&lt;p&gt;That residual can include browser initialisation, delays while unloading the previous page, disk or cache access, resource contention, and timings hidden by cross-origin restrictions. It is &lt;strong&gt;not&lt;/strong&gt; another name for redirect time. Hidden cross-origin redirects are a common source of UNO, but treating every unexplained millisecond as “a tracking redirect” repeats the same attribution mistake with a different label.&lt;/p&gt;

&lt;p&gt;CrUX can tell you field TTFB is poor. It cannot decompose that time into phases, so it also cannot compute UNO. Without a Navigation Timing breakdown from real navigations (or a careful local reproduction), all of TTFB is effectively unattributed in the Google field dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation Timing TTFB breakdown: redirect, DNS, connection, request
&lt;/h2&gt;

&lt;p&gt;A useful client-facing breakdown starts with the named hops, then shows the residual. Keep the language plain enough for a non-engineer stakeholder, and precise enough that engineers can map it back to DevTools. If the slide only shows total Waiting, every remedy conversation defaults to hosting.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;What it usually covers&lt;/th&gt;
&lt;th&gt;Where teams over-blame&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Redirect&lt;/td&gt;
&lt;td&gt;Visible same-origin (or opted-in) redirects before the final response&lt;/td&gt;
&lt;td&gt;Ignoring hidden cross-origin hops that never appear in &lt;code&gt;redirectCount&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS&lt;/td&gt;
&lt;td&gt;Domain lookup for the final host&lt;/td&gt;
&lt;td&gt;Blaming “DNS” when connection or residual dominates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection&lt;/td&gt;
&lt;td&gt;TCP + TLS setup for the final host&lt;/td&gt;
&lt;td&gt;Calling all Waiting “TLS” when connect is short&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request → first byte&lt;/td&gt;
&lt;td&gt;Time from sending the request until &lt;code&gt;responseStart&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Calling this alone “the server” when UNO is large&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UNO&lt;/td&gt;
&lt;td&gt;Everything in TTFB not in the rows above&lt;/td&gt;
&lt;td&gt;Leaving it unnamed so it inherits the server label&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Lighthouse and PageSpeed Insights still surface high first-byte time under diagnostics such as Reduce initial server response time. That audit name is historically server-shaped. It does not prove that PHP, WordPress cron, or database load owns the whole bar. Pair the lab label with a Navigation Timing breakdown before you write the remediation paragraph. &lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough" rel="noopener noreferrer"&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt; explains why a single paste also misses hour-of-day and campaign-mix effects that change which phases dominate.&lt;/p&gt;

&lt;p&gt;For DNS, TLS, HTTP version, and CDN cache rules that actually move the attributed network phases, stay inside the &lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;network performance guide&lt;/a&gt;. The focus here is the slice those guides do not name: the unattributed remainder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why redirect, DNS, and connection phases still leave a gap
&lt;/h2&gt;

&lt;p&gt;Navigation Timing often fails to add back up to TTFB. Gaps exist between timestamps. Some timings are deliberately hidden. The browser still includes that time in TTFB; it simply will not (or cannot) attribute it in the redirect, DNS, or connection fields.&lt;/p&gt;

&lt;p&gt;Cross-origin redirects are the clearest example. When a navigation includes a cross-origin hop, Navigation Timing has traditionally reported &lt;code&gt;redirectStart&lt;/code&gt;, &lt;code&gt;redirectEnd&lt;/code&gt;, and &lt;code&gt;redirectCount&lt;/code&gt; as zero. Overall TTFB still includes the hop. The redirect vanishes from the breakdown and lands in UNO. Common journeys include affiliate or ad tracking wrappers, URL shorteners, social outbound wrappers, and even &lt;code&gt;http://&lt;/code&gt; to &lt;code&gt;https://&lt;/code&gt; on the same hostname. A change of scheme is a change of origin. What looks like a harmless first-party canonicalisation can still hide redirect timing.&lt;/p&gt;

&lt;p&gt;Synthetic tests that open the final landing URL never walk that chain. CrUX folds the cost into TTFB. Agencies comparing a clean lab homepage to a paid-search landing path then argue past each other: one chart shows a short Waiting bar, the other shows field TTFB that “must be the server.” Segment by landing page, campaign, and referrer when UNO rises. Reproduce representative journeys in DevTools instead of assuming origin compute.&lt;/p&gt;

&lt;p&gt;Chrome has started improving opt-in visibility for some cross-origin redirect timing via &lt;code&gt;Timing-Allow-Origin&lt;/code&gt; on redirecting servers. Adoption across shorteners and campaign platforms will be uneven for a long time. Even with better visibility, UNO still matters: not every residual is a redirect, and not every redirect will opt in.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to calculate UNO from Navigation Timing
&lt;/h2&gt;

&lt;p&gt;On a page you control, open DevTools Console after a hard navigation and read the navigation entry. The shape matches Harry’s public snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntriesByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uno&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseStart&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
  &lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
  &lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domainLookupEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domainLookupStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
  &lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
  &lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not treat a single Console value as portfolio truth. Cache warmth, device, connection, and previous-page unload all move the residual. For client work, collect UNO as both a duration and an occurrence count in RUM (or in a small beacon you control), then segment. Chart it beside redirect, DNS, connection, attributed server waiting, total TTFB, and Largest Contentful Paint. When LCP is TTFB-sensitive, unexplained first-byte time is not academic; it delays paint. &lt;a href="https://apogeewatcher.com/blog/quick-way-to-fix-lcp" rel="noopener noreferrer"&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt; still applies after you know whether the early wait is attributed server time or UNO.&lt;/p&gt;

&lt;p&gt;For a quick sanity check of hidden redirects, open a shortened URL that lands on a known host, then compare &lt;code&gt;redirectCount&lt;/code&gt; (often zero) with a non-zero UNO. Contrast that with a same-origin trailing-slash redirect that &lt;em&gt;does&lt;/em&gt; enumerate. The point is not the demo URL; it is that visible redirect count alone is a poor map of real campaign traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What agencies should name in client reports when TTFB looks “server-only”
&lt;/h2&gt;

&lt;p&gt;Client reports need a labelled residual. A practical slide or appendix row looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Total TTFB&lt;/strong&gt; (lab on the money URL, plus field TTFB when CrUX exists).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributed phases&lt;/strong&gt; you can defend: redirect (visible), DNS, connection, request→first byte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNO&lt;/strong&gt; as “unexplained navigation time inside TTFB,” with a one-line definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next action by owner:&lt;/strong&gt; campaign/redirect chain, delivery (DNS/TLS/CDN), or origin application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Write the sentence that prevents the wrong ticket. Prefer: “Field TTFB is elevated; Navigation Timing leaves X ms unattributed after redirect, DNS, connection, and request timing. We will reproduce campaign landings before we open a hosting upsizing ticket.” Avoid: “Server response is slow” when the only evidence is a total TTFB bar.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://apogeewatcher.com/blog/performance-budget-thresholds-template" rel="noopener noreferrer"&gt;Performance Budget Thresholds Template&lt;/a&gt; so money URLs have explicit first-byte budgets, then annotate whether breaches are attributed server time or UNO-heavy. Schedule lab coverage on priority URLs with &lt;a href="https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio" rel="noopener noreferrer"&gt;PageSpeed monitoring test frequency and priority across a portfolio&lt;/a&gt; so you are not inventing the breakdown from a single Friday afternoon paste. Watcher’s multi-tenant schedules keep those lab baselines comparable week to week; they do not replace RUM for UNO segmentation, and you should say that plainly when the residual only appears on campaign landings.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the attributed server phase is the real bottleneck
&lt;/h2&gt;

&lt;p&gt;Name UNO first. Then look at the request→responseStart span (and any RUM “server” or Waiting attribution your tool exposes after known network phases). If that attributed slice dominates, and DNS/connect/UNO are small, origin work is the honest story.&lt;/p&gt;

&lt;p&gt;That is when &lt;a href="https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme" rel="noopener noreferrer"&gt;TTFB Won't Go Down? Server-Side Culprits Beyond the Theme&lt;/a&gt; becomes the runbook: WP-Cron storms, cold PHP workers, missing object cache, database load, backup plugins at peak. Do not start there when UNO or hidden redirect chains explain most of the bar. Do not skip there when the residual is already named and still tiny beside a long attributed wait.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Likely owner&lt;/th&gt;
&lt;th&gt;First move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High UNO on campaign/referrer segments; lab direct URL fine&lt;/td&gt;
&lt;td&gt;Redirect / landing path&lt;/td&gt;
&lt;td&gt;Reproduce chain; talk to tracking/shortener owners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High DNS or connect; UNO modest&lt;/td&gt;
&lt;td&gt;Delivery / network&lt;/td&gt;
&lt;td&gt;[Network performance checklist](&lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High request→first byte; UNO and connect small&lt;/td&gt;
&lt;td&gt;Origin application&lt;/td&gt;
&lt;td&gt;[Server-side TTFB checklist](&lt;a href="https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme" rel="noopener noreferrer"&gt;https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything elevated after a browser-major mix shift&lt;/td&gt;
&lt;td&gt;Population / measurement&lt;/td&gt;
&lt;td&gt;Annotate releases; do not only ship origin tickets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TTFB is not a Core Web Vital, but it still gates LCP because HTML must arrive before the largest content can paint. Keep that link explicit in reports so stakeholders do not treat first-byte work as vanity once LCP is the slide title. Naming UNO does not replace LCP fixes; it stops you spending the LCP budget on the wrong first-byte owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CrUX and one-off lab runs miss the unattributed slice
&lt;/h2&gt;

&lt;p&gt;CrUX reports field TTFB without the Navigation Timing phases needed for UNO. Useful as a population signal; useless as a phase budget. One-off PageSpeed Insights or Lighthouse runs on the final URL skip affiliate and shortener chains, warm different caches, and label the wait with server-shaped language. Neither artefact is wrong for what it measures. Both are incomplete if your clients’ money arrives through wrapped links.&lt;/p&gt;

&lt;p&gt;Proper RUM (commercial, open-source, or homegrown) that retains navigation timestamps, page-view context, and dimensions is how UNO becomes actionable. You need duration and occurrence count, not only a p75. You need breakdowns by landing page, campaign, referrer, browser, device, and connection. Synthetic schedules still matter for regression detection on known URLs; they answer a different question. &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to use synthetic versus real user monitoring&lt;/a&gt; is the pairing guide when a stakeholder asks which chart to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is unattributed navigation overhead?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is the part of Time to First Byte left after subtracting the redirect, DNS, connection, and request-to-response phases exposed by Navigation Timing. It is a residual metric, not a single browser-reported timer. You calculate it so unexplained time has a label instead of inheriting the server narrative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is UNO the same as redirect time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Hidden cross-origin redirects often inflate UNO, but browser work, cache access, unload delays, and other gaps can sit there too. Do not rewrite “unattributed” as “redirects we have not counted yet” without evidence from reproduction and referrer or campaign data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why are some redirects missing from Navigation Timing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For privacy and origin-boundary reasons, cross-origin navigation redirects have traditionally reported zero redirect timing and count even when TTFB includes them. Scheme changes such as HTTP to HTTPS count as cross-origin even on the same hostname. The hop still costs users; only the breakdown loses it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can CrUX report UNO?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. CrUX exposes field TTFB without the phase timestamps required to calculate the residual. Use RUM or a Navigation Timing beacon on your own traffic if you need the split.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should we talk about this in a client report?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Show total TTFB, the named phases, and a labelled UNO row. State the next owner (campaign path, delivery, or origin) instead of defaulting every elevated first-byte chart to “upgrade hosting.” One honest residual row prevents a week of origin tickets that never touch the real journey.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When do we optimise the server instead?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the attributed request→first-byte (or tool-equivalent server) phase dominates after UNO and network phases are small. Use the &lt;a href="https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme" rel="noopener noreferrer"&gt;server-side TTFB checklist&lt;/a&gt;. That hand-off is intentional: UNO naming first, origin work second.&lt;/p&gt;




&lt;p&gt;If your retainers still describe every Waiting bar as server time, add UNO to the next report cycle on two or three campaign-heavy URLs and compare it with a direct lab navigation. Keep scheduled lab baselines on those URLs while you wire RUM (or a small beacon) for the Navigation Timing breakdown clients never see in CrUX alone. &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;Start a free Apogee Watcher trial&lt;/a&gt; when you want those lab checks on a multi-tenant schedule without pasting PageSpeed Insights by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://csswizardry.com/2026/08/uno-is-underrated/" rel="noopener noreferrer"&gt;Unattributed Navigation Overhead (UNO) Is Underrated&lt;/a&gt; (Harry Roberts / CSS Wizardry; metric coined by Tim Vereecke)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://csswizardry.com/2026/08/web-perf-wednesday-006-faster-browser-releases-change-your-rum-population/" rel="noopener noreferrer"&gt;Web-Perf Wednesday 006 – Faster Browser Releases Change Your RUM Population&lt;/a&gt; (CSS Wizardry)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/TR/navigation-timing-2/" rel="noopener noreferrer"&gt;Navigation Timing Level 2&lt;/a&gt; (W3C)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.dev/articles/ttfb" rel="noopener noreferrer"&gt;Time to First Byte (TTFB)&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/ttfb-wont-go-down-server-side-culprits-beyond-theme" rel="noopener noreferrer"&gt;TTFB Won't Go Down? Server-Side Culprits Beyond the Theme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/quick-way-to-fix-lcp" rel="noopener noreferrer"&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough" rel="noopener noreferrer"&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/performance-budget-thresholds-template" rel="noopener noreferrer"&gt;Performance Budget Thresholds Template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio" rel="noopener noreferrer"&gt;PageSpeed monitoring: schedule test frequency and priority across a portfolio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to use synthetic versus real user monitoring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>seo</category>
    </item>
    <item>
      <title>Oh Dear alternative? Uptime green is not Core Web Vitals portfolio monitoring</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Tue, 06 Oct 2026 06:58:22 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/oh-dear-alternative-uptime-green-is-not-core-web-vitals-portfolio-monitoring-5gge</link>
      <guid>https://dev.to/apogeewatcher/oh-dear-alternative-uptime-green-is-not-core-web-vitals-portfolio-monitoring-5gge</guid>
      <description>&lt;p&gt;The uptime dashboard is green, SSL is fine, and the status page is quiet, yet a client still forwards a PageSpeed Insights screenshot where mobile Largest Contentful Paint sits in Needs improvement. Nobody can explain how both truths coexist. Searching for an Oh Dear alternative feels like the next step, but that query usually returns more uptime and white-label status products, not a Core Web Vitals portfolio monitor.&lt;/p&gt;

&lt;p&gt;The gap is not that Oh Dear is weak at its job; it is treating reachability as proof that shoppers experience a fast page. Green uptime and healthy Core Web Vitals are different clocks, so conflating them is how retainers buy the wrong primary tool. The search phrase “Oh Dear alternative” then steers buyers back onto the uptime shelf when the screenshot was about experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What “Oh Dear alternative” usually means in search
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ohdear.app/" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt; sits in a crowded agency niche: uptime checks, SSL and DNS health, broken-link crawls, status pages, and often a scheduled Lighthouse or response-time layer under one login. When agencies outgrow a free ping tool, “Oh Dear alternative” is a natural buying phrase. The search box does not know whether you meant “better status pages” or “finally watch LCP.”&lt;/p&gt;

&lt;p&gt;Open that SERP today and you mostly see other agency uptime suites: white-label status pages, client PDF uptime reports, multi-region pings, SSL and domain expiry. Those products compete on the uptime axis, and they are sensible shortlists when the failure mode is “the site returned an error” or “the certificate expired on Friday night.” That shelf is crowded for a reason: downtime still burns retainers.&lt;/p&gt;

&lt;p&gt;They are a weak answer when the failure mode is “HTTP 200, but LCP and Interaction to Next Paint are amber across the money path.” That job needs scheduled lab history, CrUX field context where Google publishes it, URL inventories that keep up with CMS churn, and budgets written in Core Web Vitals units. Uptime clones do not become that stack because the brochure says “performance,” so the buying phrase and the failure mode have to match before you shortlist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uptime green is not a Core Web Vitals signal
&lt;/h2&gt;

&lt;p&gt;Uptime answers whether this origin responded successfully from the checker’s vantage point, while Core Web Vitals answer how real Chrome users (field) or a throttled lab browser (Lighthouse / PageSpeed Insights) experienced load and interactivity on specific URLs. Both can be “true” on the same Tuesday and still describe different risks. That mismatch is what the green dashboard hides.&lt;/p&gt;

&lt;p&gt;A site can stay up while:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the LCP image ships late on mobile category templates,&lt;/li&gt;
&lt;li&gt;a new extension blocks the main thread on add-to-cart (INP),&lt;/li&gt;
&lt;li&gt;a promo bar shifts layout without reserved space (CLS),&lt;/li&gt;
&lt;li&gt;third-party tags grow for a campaign week that never shows as downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those failures flip a classic uptime monitor red, but they do show up in PageSpeed Insights lab runs, in CrUX when the URL is eligible, and in client SEO conversations that already use Google’s Good / Needs improvement / Poor bands. Calling the origin “healthy” because the ping is green trains account teams to ignore the metric set the retainer actually sells. The screenshot arrives anyway; the dashboard just never warned anyone.&lt;/p&gt;

&lt;p&gt;For the wider lab-versus-field map, see &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=oh-dear-alternative-uptime-green-not-cwv-portfolio" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt;. Synthetic uptime and synthetic Lighthouse are both lab-shaped, but they measure different artefacts, so keep the labels honest in the pack. Readers who skip that distinction spend the next quarter arguing about which green is “real.”&lt;/p&gt;

&lt;h2&gt;
  
  
  What Oh Dear-class suites cover (and what they leave out)
&lt;/h2&gt;

&lt;p&gt;Oh Dear-class products are genuinely strong when you need one place for “is it up?”, certificate risk, and a client-facing status story. Many also run HTTP timing on the same fetch path, or a daily Lighthouse score on selected URLs, and those extras matter. They still sit beside uptime economics: pricing and product roadmaps usually scale with sites and check frequency, not with multi-URL Core Web Vitals portfolios and discovery.&lt;/p&gt;

&lt;p&gt;What they typically leave as a separate purchase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;continuous PageSpeed Insights history across many client organisations,&lt;/li&gt;
&lt;li&gt;CrUX field bands stored next to lab runs for the same URL set,&lt;/li&gt;
&lt;li&gt;automated discovery when a CMS adds templates you never pasted into the monitor list,&lt;/li&gt;
&lt;li&gt;budgets and alerts written primarily against LCP, INP, and CLS rather than millisecond TTFB on the uptime probe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Daily Lighthouse is closer to “pagespeed” than a ping, but it is still not the same as a portfolio programme built around Google’s PageSpeed Insights API and field context. Mixing “we have Lighthouse in the uptime tool” with “we monitor Core Web Vitals for SEO” without labelling the difference is how false confidence survives a QBR. One score on one URL is a check; a retainer needs a series.&lt;/p&gt;

&lt;p&gt;A fair pairwise feature split (Oh Dear versus a CWV-first portfolio tool) lives in &lt;a href="https://apogeewatcher.com/blog/oh-dear-vs-apogee-watcher-uptime-vs-cwv-portfolio?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=oh-dear-alternative-uptime-green-not-cwv-portfolio" rel="noopener noreferrer"&gt;Oh Dear vs Apogee Watcher: Uptime Suite vs Core Web Vitals Portfolio Monitoring&lt;/a&gt;. Use that matrix when you are already comparing vendors; what follows here is the job split before you open the spreadsheet. The spreadsheet is useless if you still think both columns measure the same risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to keep the uptime suite and add a CWV layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Keep (or replace within) the uptime axis when&lt;/strong&gt; the pager must fire because HTTPS is down, certificates expire, or clients need a branded status page. An Oh Dear alternative that stays on that axis is a valid purchase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a Core Web Vitals portfolio layer when&lt;/strong&gt; you sell performance retainers, report LCP/INP/CLS in client decks, or manage many origins where the expensive failure is slow-but-up. Layer rather than rip out. Agencies that already run Oh Dear (or Pingdom, Better Stack, UptimeRobot, and similar) usually need a second product for CWV depth, not a single suite that pretends both jobs are free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replace Oh Dear only when&lt;/strong&gt; you never needed the uptime bundle and the trial proved you were paying uptime economics for a CWV-only brief. That is a narrower case than the search phrase suggests.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical split for retainers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Prefer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reachability, SSL, status pages&lt;/td&gt;
&lt;td&gt;Oh Dear or another uptime / health suite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold-load lab + opportunity text&lt;/td&gt;
&lt;td&gt;PageSpeed Insights lab or scheduled PSI-style monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO-facing field categories&lt;/td&gt;
&lt;td&gt;CrUX via Search Console / PageSpeed Insights field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Many client sites, CWV budgets, discovery&lt;/td&gt;
&lt;td&gt;Multi-tenant PageSpeed / CWV portfolio monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Write both truths in the pack with labels: “Uptime (reachability)” versus “Lab PageSpeed / CrUX (experience).” Green on the first column does not clear the second, and clients notice when the PDF pretends otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is searching for an Oh Dear alternative the right move for Core Web Vitals?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only if you also need a better uptime suite. If the pain is amber LCP on money pages while pings stay green, shortlist a CWV portfolio monitor instead of another status-page vendor. The search phrase and the failure mode have to match.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Oh Dear’s Lighthouse check cover Core Web Vitals monitoring?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It covers a scheduled lab score on the URLs you configure, but it does not automatically equal a multi-client PageSpeed Insights programme with field context and discovery. Treat it as a useful signal on the uptime product, not as the whole CWV retainer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should we rip out Oh Dear and switch to a PageSpeed tool?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually no. Keep uptime where downtime is the risk, and add CWV monitoring where experience is the risk. Rip-and-replace only when the uptime bundle was never the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do uptime tools say “performance” then?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because HTTP timing and Lighthouse scores are performance-adjacent. The word still collapses three jobs (reachability timing, lab audits, field Core Web Vitals) into one brochure line. Ask which artefact the alert fires on before you trust the label.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;A useful starting pass is to list every production origin on the retainer, mark which ones already have uptime coverage you trust, and note last lab LCP/INP/CLS (plus whether CrUX exists) for each money-path URL. If uptime is green and lab or field is amber, you do not need another status page first. You need a scheduled CWV layer and a report that names both clocks.&lt;/p&gt;

&lt;p&gt;For the pairwise Oh Dear versus portfolio decision, use &lt;a href="https://apogeewatcher.com/blog/oh-dear-vs-apogee-watcher-uptime-vs-cwv-portfolio?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=oh-dear-alternative-uptime-green-not-cwv-portfolio" rel="noopener noreferrer"&gt;Oh Dear vs Apogee Watcher&lt;/a&gt;. For how synthetic lab fits beside real-user field data, keep &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=oh-dear-alternative-uptime-green-not-cwv-portfolio" rel="noopener noreferrer"&gt;Synthetic vs Real User Monitoring&lt;/a&gt; in the same pack. Two links, two jobs, one retainer language.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ohdear.app/" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt; (product)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/oh-dear-vs-apogee-watcher-uptime-vs-cwv-portfolio" rel="noopener noreferrer"&gt;Oh Dear vs Apogee Watcher: Uptime Suite vs Core Web Vitals Portfolio Monitoring&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/docs/appearance/core-web-vitals" rel="noopener noreferrer"&gt;Understanding Core Web Vitals and Google search results&lt;/a&gt; (Google Search Central)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>agency</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Is Vercel Speed Insights enough for Core Web Vitals monitoring?</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Sun, 04 Oct 2026 06:54:50 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/is-vercel-speed-insights-enough-for-core-web-vitals-monitoring-3k9d</link>
      <guid>https://dev.to/apogeewatcher/is-vercel-speed-insights-enough-for-core-web-vitals-monitoring-3k9d</guid>
      <description>&lt;p&gt;Agencies often turn on Vercel Speed Insights for a Next.js client, see route-level Core Web Vitals, and assume monitoring is “done.” For that Vercel project, the product is genuinely useful. For a book of WordPress, Shopify, Magento, and mixed hosts, it is not enough. Core Web Vitals monitoring means knowing when Largest Contentful Paint, Interaction to Next Paint, or Cumulative Layout Shift moves on the URLs you promised to watch. Host RUM answers that for instrumented Vercel deployments. It does not schedule lab checks across thirty other origins or give you one organisation view for account leads.&lt;/p&gt;

&lt;p&gt;What follows draws a clean line: when Speed Insights is enough, when you still need PageSpeed Insights field (Chrome UX Report) and scheduled lab coverage, and how agencies usually split the stack. For the synthetic-versus-field vocabulary, see &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt;. For how agencies assemble DIY, portfolio, and RUM-plus-monitor recipes, see &lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Vercel Speed Insights actually measures
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vercel.com/docs/speed-insights" rel="noopener noreferrer"&gt;Vercel’s Speed Insights&lt;/a&gt; is first-party real-user monitoring for projects on Vercel. It collects Core Web Vitals and related timings from visitors on your deployed previews and production. The dashboard supports filters by route, device, time range, and (on paid Speed Insights tiers) richer breakdowns such as element-level views and geography. Vercel also stresses shorter windows than Google’s typical 28-day Chrome UX Report aggregation, which helps engineering see the effect of a deploy sooner.&lt;/p&gt;

&lt;p&gt;That is RUM scoped to the Vercel runtime and their collector. It is not Lighthouse. It is not a cold lab load from Google’s PageSpeed Insights workers. It is not a multi-tenant agency console for sites that never deploy to Vercel.&lt;/p&gt;

&lt;p&gt;Free and Plus packaging change how much detail you see (Vercel documents Real Experience Score on every plan, with fuller Core Web Vitals breakdowns on Plus). Pricing and feature gates move; treat the docs as source of truth for what your client’s plan includes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Speed Insights beats PageSpeed Insights for engineering
&lt;/h2&gt;

&lt;p&gt;PageSpeed Insights field data is Chrome UX Report: Chrome users, eligibility thresholds, origin or URL when sample size allows, rolling roughly 28-day window. That dataset matters for SEO conversations because it aligns with what Google publishes for page experience. It is a poor day-to-day triage tool when you need “which route broke after yesterday’s merge?”&lt;/p&gt;

&lt;p&gt;Speed Insights wins for Vercel engineering when you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Route-level RUM&lt;/strong&gt; on your own traffic, including browsers CrUX undersamples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster iteration windows&lt;/strong&gt; after a deploy or branch, instead of waiting on a long CrUX lag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribution&lt;/strong&gt; that names routes (and, on higher tiers, elements) instead of a single origin badge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vercel’s own Core Web Vitals guides make the same split: use CrUX / PageSpeed Insights field for the SEO-facing view; use Speed Insights (or another RUM path) for engineering triage on the Vercel app. Treat those as complementary field sources, not substitutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it is not enough for agency portfolios
&lt;/h2&gt;

&lt;p&gt;Agencies fail when they generalise from one Vercel client to the whole book.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosts that are not on Vercel.&lt;/strong&gt; Most retained sites still run on WordPress hosts, Shopify, Magento, static elsewhere, or custom VPS stacks. Speed Insights does not cover those origins. You still need scheduled lab tests (PageSpeed Insights API / Lighthouse-class runs), CrUX where published, and a place to store history per client organisation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No shared multi-tenant workflow.&lt;/strong&gt; Account leads need one login, roles, budgets, alerts, and client-ready reports across many domains. A Vercel project dashboard per deployment is the wrong primitive for that job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lab diagnosis still matters.&lt;/strong&gt; RUM tells you users felt a regression. Lab (and PageSpeed Insights opportunities) still help engineers reproduce LCP and CLS causes on a cold load. Speed Insights does not replace that diagnostic loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CrUX remains the SEO reference.&lt;/strong&gt; When a sponsor asks “what does Google show?”, answer with Search Console or PageSpeed Insights field / CrUX, not only your first-party RUM chart. The two can disagree (browser mix, window length, URL versus origin). Label both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enough when:&lt;/strong&gt; the engagement is one Vercel-hosted product, engineering owns the Vercel dashboard, and you only promise route-level RUM plus occasional CrUX checks for SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not enough when:&lt;/strong&gt; you sell portfolio monitoring across many client hosts, need discovery and schedules without a snippet on every domain, or need white-label reporting for non-Vercel properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical stack split
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Prefer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Route RUM on a Vercel Next.js app&lt;/td&gt;
&lt;td&gt;Vercel Speed Insights (or equivalent first-party RUM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO-facing field categories&lt;/td&gt;
&lt;td&gt;CrUX via Search Console / PageSpeed Insights field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold-load lab + opportunity text&lt;/td&gt;
&lt;td&gt;PageSpeed Insights lab or scheduled PSI-style monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Many client sites, one org, budgets/alerts&lt;/td&gt;
&lt;td&gt;Multi-tenant portfolio monitor (see the agency stack recipes linked above)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A common agency pattern: keep Speed Insights on the Vercel flagship; put scheduled lab-plus-CrUX monitoring on the rest of the portfolio; use CrUX as the shared SEO language in retainer packs. That matches the “RUM + monitor” stack idea without pretending one product covers every host.&lt;/p&gt;

&lt;p&gt;Do not disable Speed Insights to “avoid duplicate tools.” Duplicate tools are fine when they answer different questions. Duplicate &lt;em&gt;unlabelled&lt;/em&gt; numbers in a client PDF are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does Speed Insights replace PageSpeed Insights?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Use Speed Insights for Vercel RUM triage. Use PageSpeed Insights (or Search Console) when you need CrUX-aligned field categories and lab diagnostics on a public URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I rely on Speed Insights alone for SEO?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Risky. Google’s published field story is CrUX. First-party RUM helps you ship fixes faster; it is not the same dataset Search Console shows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if only one of twenty clients is on Vercel?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instrument that one with Speed Insights. Monitor the other nineteen with a host-agnostic schedule. Do not wait for every client to migrate to Vercel before you watch regressions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is free Speed Insights “enough”?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enough for a basic Real Experience Score on a Vercel project may be. Enough for element-level and geographic triage depends on the paid tier your client enables. Check Vercel’s current plan matrix before you promise those views in a retainer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;List every production origin on the retainer. Mark which ones deploy on Vercel. Turn on Speed Insights (and the right paid tier) only where the runtime supports it. For every other origin, pick a scheduled lab-plus-CrUX path and write budgets in the same units you already use in client reviews. Put both field sources in the pack with labels: “Vercel RUM (this app)” versus “CrUX / PageSpeed Insights field (SEO window).”&lt;/p&gt;

&lt;p&gt;If you are choosing the portfolio half of the stack, start from the three recipes in &lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt; and the lab-versus-RUM framing in &lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/docs/speed-insights" rel="noopener noreferrer"&gt;Speed Insights Overview&lt;/a&gt; (Vercel docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/kb/guide/how-to-improve-core-web-vitals" rel="noopener noreferrer"&gt;How to improve Core Web Vitals&lt;/a&gt; (Vercel)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/blog/how-core-web-vitals-affect-seo" rel="noopener noreferrer"&gt;How Core Web Vitals affect SEO&lt;/a&gt; (Vercel)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026" rel="noopener noreferrer"&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance" rel="noopener noreferrer"&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>vercel</category>
      <category>agency</category>
    </item>
    <item>
      <title>Brotli and Gzip Compression: Shrink Text Assets Without Breaking PageSpeed Scores</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Sat, 03 Oct 2026 06:54:43 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/brotli-and-gzip-compression-shrink-text-assets-without-breaking-pagespeed-scores-6e3</link>
      <guid>https://dev.to/apogeewatcher/brotli-and-gzip-compression-shrink-text-assets-without-breaking-pagespeed-scores-6e3</guid>
      <description>&lt;p&gt;The CDN dashboard shows compression enabled. A host panel lists Brotli as on. A lab run on the priority URL still flags Enable text compression, or the Performance score barely moves while Time to First Byte gets worse after someone raised the Brotli level on dynamic HTML. In our experience the gap is rarely “nobody turned compression on.” It is a mismatch between which responses are compressed, which layer applies &lt;code&gt;Content-Encoding&lt;/code&gt;, and what Lighthouse actually measures on that URL.&lt;/p&gt;

&lt;p&gt;What follows is a delivery guide for teams who already walk DNS, TLS, HTTP, and cache rules in &lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;. That piece explains where edge and origin sit on the path to first byte. Here the focus is Brotli compression and gzip for text assets: how teams enable Brotli with a safe fallback, and how to keep PageSpeed Insights and Lighthouse honest after the change. Pair it with &lt;a href="https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks" rel="noopener noreferrer"&gt;Cache-Control Headers for Web Performance&lt;/a&gt;. Caching decides whether bytes are reused; compression decides how small those bytes are on the first download.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Brotli and gzip change on the response path
&lt;/h2&gt;

&lt;p&gt;HTTP compression shrinks the body of a response before it travels over the network. The client advertises what it accepts in &lt;code&gt;Accept-Encoding&lt;/code&gt; (commonly &lt;code&gt;br&lt;/code&gt;, &lt;code&gt;gzip&lt;/code&gt;, and &lt;code&gt;deflate&lt;/code&gt;). The server or CDN chooses an encoding and returns &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;Content-Encoding: gzip&lt;/code&gt; when it compresses. The browser decompresses before parsing HTML, CSS, or JavaScript. Transfer size drops; the uncompressed size the parser needs does not.&lt;/p&gt;

&lt;p&gt;That distinction matters for Core Web Vitals work. Smaller transfer size can shorten download time for render-blocking CSS and for JavaScript that sits on the critical path. It does not rewrite a slow origin query, a third-party script, or an oversized Largest Contentful Paint image. Compression is a bandwidth and decode trade-off on text responses. It sits beside Time to First Byte and LCP resource priority; it is not a substitute for the fixes in &lt;a href="https://apogeewatcher.com/blog/quick-way-to-fix-lcp" rel="noopener noreferrer"&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lighthouse and PageSpeed Insights surface missing compression under audits such as &lt;a href="https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression" rel="noopener noreferrer"&gt;Enable text compression&lt;/a&gt; (&lt;code&gt;uses-text-compression&lt;/code&gt;). Google’s older &lt;a href="https://developers.google.com/speed/docs/insights/EnableCompression" rel="noopener noreferrer"&gt;Enable Compression&lt;/a&gt; guidance still frames the same idea for agencies reading mixed reports: text resources that benefit from gzip or Brotli should arrive compressed when the client supports it. Gzip compression on the web is still the safety net when Brotli is unavailable on a hop; both belong in the same verification pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brotli vs gzip for web delivery (and when gzip still wins)
&lt;/h2&gt;

&lt;p&gt;Brotli versus gzip is not a purity contest. Brotli usually produces smaller text payloads than gzip at comparable quality settings, especially for HTML, CSS, and JavaScript. Gzip is older, universally supported for compressed HTTP responses, and cheap to encode at moderate levels. Most modern browsers prefer Brotli when the server offers &lt;code&gt;br&lt;/code&gt; and the negotiation succeeds.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Brotli (&lt;code&gt;br&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Gzip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Typical text ratio&lt;/td&gt;
&lt;td&gt;Often smaller than gzip at similar effort&lt;/td&gt;
&lt;td&gt;Good baseline; larger than Brotli for many CSS/JS bundles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encode CPU&lt;/td&gt;
&lt;td&gt;Higher at high quality levels on dynamic content&lt;/td&gt;
&lt;td&gt;Lower at common levels (for example gzip 4–6)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support for HTTP&lt;/td&gt;
&lt;td&gt;Broad for current Chrome, Firefox, Safari, Edge&lt;/td&gt;
&lt;td&gt;Universal for compression-capable clients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best use&lt;/td&gt;
&lt;td&gt;Precompressed static assets; edge or origin for text&lt;/td&gt;
&lt;td&gt;Fallback when &lt;code&gt;br&lt;/code&gt; is unavailable; always-on safety net&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk if mis-set&lt;/td&gt;
&lt;td&gt;High dynamic Brotli quality can inflate TTFB&lt;/td&gt;
&lt;td&gt;Double-gzip or gzip on already-compressed binary wastes CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For static fingerprinted files, precompressing at build time (&lt;code&gt;.br&lt;/code&gt; and &lt;code&gt;.gz&lt;/code&gt; siblings) and serving the matching encoding avoids burning origin CPU on every request. For HTML that changes per request, compression at the CDN or reverse proxy with a moderate quality setting usually works better, with gzip kept as the fallback for clients or intermediaries that do not take Brotli. That split (offline high effort for static, moderate online effort for HTML) is what keeps transfer size down without quietly raising Time to First Byte.&lt;/p&gt;

&lt;p&gt;Zstandard (&lt;code&gt;zstd&lt;/code&gt;) appears in some CDN and origin stacks as another encoding. It is useful optional coverage where the edge already supports it. Brotli and gzip remain the baseline pair until client and intermediary support for your traffic mix is proven. Delivery checklists we use with client sites still verify gzip, Brotli, and zstd where the stack claims them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which responses to compress (and which to leave alone)
&lt;/h2&gt;

&lt;p&gt;The responses that benefit are those whose payload is mostly text and is not already in a compressed container. A practical allow-list looks like this, and it is what we expect to match Lighthouse’s text-compression audit when the page is otherwise healthy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text/html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text/javascript&lt;/code&gt; / &lt;code&gt;application/javascript&lt;/code&gt; / &lt;code&gt;application/x-javascript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;application/json&lt;/code&gt; / &lt;code&gt;application/ld+json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;image/svg+xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text/xml&lt;/code&gt; / &lt;code&gt;application/xml&lt;/code&gt; (where XML is not already packaged)&lt;/li&gt;
&lt;li&gt;Often &lt;code&gt;font/woff&lt;/code&gt; is already compressed; woff2 is compressed by design, so wrapping it again rarely helps&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;application/wasm&lt;/code&gt; may benefit in some stacks once size and CPU are checked on a representative URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Brotli or gzip as a blanket over JPEG, PNG, WebP, AVIF, MP4, or other already-compressed media rarely shrinks transfer size and can add latency and CPU. Agencies still hit this when a “compress everything” host preset includes &lt;code&gt;image/*&lt;/code&gt; or when a plugin gzip-filters the whole response stack. The win is smaller text on the wire, not a second envelope around media that is already compressed.&lt;/p&gt;

&lt;p&gt;Partial compression is another common miss. HTML compressed at the edge while CSS and JavaScript miss &lt;code&gt;Content-Encoding&lt;/code&gt; still fails Lighthouse’s text-compression audit for those URLs. The audit looks at individual text resources above a size threshold, not at a single dashboard toggle labelled “Brotli.”&lt;/p&gt;

&lt;h2&gt;
  
  
  How to enable Brotli with a gzip fallback at origin and CDN
&lt;/h2&gt;

&lt;p&gt;Enabling Brotli only helps when negotiation survives to the browser. Clients send &lt;code&gt;Accept-Encoding&lt;/code&gt; with &lt;code&gt;br&lt;/code&gt; and &lt;code&gt;gzip&lt;/code&gt;. Stacks that prefer Brotli when available, and fall back to gzip without serving identity encoding for large text bodies, clear audits more reliably than a lone dashboard switch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Origin and reverse proxy patterns
&lt;/h3&gt;

&lt;p&gt;Common patterns we see work in delivery:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;NGINX with Brotli module.&lt;/strong&gt; Configuration that turns &lt;code&gt;brotli on;&lt;/code&gt; for the MIME types above, sets a moderate &lt;code&gt;brotli_comp_level&lt;/code&gt; for dynamic responses, and keeps &lt;code&gt;gzip on;&lt;/code&gt; with overlapping types so clients without &lt;code&gt;br&lt;/code&gt; still compress. Google’s &lt;a href="https://github.com/google/ngx_brotli" rel="noopener noreferrer"&gt;ngx_brotli&lt;/a&gt; and &lt;a href="https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/" rel="noopener noreferrer"&gt;NGINX Brotli docs&lt;/a&gt; cover module loading; production still needs a check that the module is loaded, not only present in a staging snippet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache.&lt;/strong&gt; &lt;code&gt;mod_brotli&lt;/code&gt; / &lt;code&gt;mod_deflate&lt;/code&gt; with explicit &lt;code&gt;AddOutputFilterByType&lt;/code&gt; (or equivalent) for the text MIME list works when filter chains do not compress twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application middleware.&lt;/strong&gt; Express &lt;code&gt;compression&lt;/code&gt;, Laravel or Rails middleware, and similar helpers often default to gzip. Brotli belongs here only when the library and deployment target support it; otherwise compression at the proxy in front of the app is the cleaner path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precompressed static assets.&lt;/strong&gt; Emitting &lt;code&gt;.br&lt;/code&gt; / &lt;code&gt;.gz&lt;/code&gt; at build, mapping &lt;code&gt;Accept-Encoding&lt;/code&gt; to those files, and setting &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; keeps shared caches from mixing encodings.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  CDN and edge
&lt;/h3&gt;

&lt;p&gt;Many CDNs offer automatic Brotli and gzip for cacheable text. Three facts in the live response matter more than the marketing checkbox, because PageSpeed Insights tests the hostname you give it, not the checkbox label in a vendor UI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The origin response for HTML, CSS, and JavaScript either arrives compressed or is compressible at the edge without being marked uncacheable for the wrong reason.&lt;/li&gt;
&lt;li&gt;The edge returns &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; on a cold and warm fetch from a client that sends both encodings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; (or CDN-equivalent vary behaviour) is present so caches store separate variants.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cloudflare and similar platforms document serving Brotli from origin and compression rules. Reading the vendor guide is not enough if an origin &lt;code&gt;Cache-Control: private&lt;/code&gt; or a page rule disables optimisation on the hostname you test in PageSpeed Insights. Compression and caching interact; the Cache-Control post covers HTML versus fingerprinted assets in more depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix Lighthouse “Enable text compression” without breaking PageSpeed scores
&lt;/h2&gt;

&lt;p&gt;The Lighthouse audit &lt;a href="https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression" rel="noopener noreferrer"&gt;Enable text compression&lt;/a&gt; fails when text resources are large enough to benefit from compression and arrive without a recognised &lt;code&gt;Content-Encoding&lt;/code&gt;. Clearing the audit means those URLs gain compression on the lab client’s path. It does not mean raising Brotli quality to the maximum on every HTML response.&lt;/p&gt;

&lt;p&gt;A workflow that keeps scores honest usually looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pull the audit URLs from the Lighthouse JSON or PageSpeed Insights diagnostics list (HTML document, CSS, and JavaScript files named in the audit).&lt;/li&gt;
&lt;li&gt;Request each URL with &lt;code&gt;Accept-Encoding: br, gzip&lt;/code&gt; and inspect &lt;code&gt;Content-Encoding&lt;/code&gt;, &lt;code&gt;Content-Type&lt;/code&gt;, and transfer size in DevTools or &lt;code&gt;curl -H "Accept-Encoding: br, gzip" -I&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Turn compression on for the MIME types that failed, while leaving images and already-compressed fonts alone.&lt;/li&gt;
&lt;li&gt;Re-run the same lab profile (same device and throttling) after deploy, watching Performance score and Time to First Byte / LCP, not only the green tick on the audit.&lt;/li&gt;
&lt;li&gt;If Time to First Byte rises while transfer size falls, lower dynamic compression quality or move compression to precompressed static files and edge caching so origin CPU is not on the critical path for every HTML hit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PageSpeed scores break when teams chase the audit alone: double compression, compressing PDFs or images, or saturating the origin so first byte suffers. The audit is a checklist item. The score reflects the full lab experience. Both belong in the same verification loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compression mistakes that hurt TTFB, LCP, or lab scores
&lt;/h2&gt;

&lt;p&gt;These failure modes show up repeatedly on agency portfolios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double compression.&lt;/strong&gt; Origin gzip plus CDN Brotli on an already-encoded body, or a plugin that gzip-filters output already compressed by the proxy. Symptoms include unexpected &lt;code&gt;Content-Encoding&lt;/code&gt; chains, larger transfer sizes, or decode errors. One compression layer per response class, with a clear owner (origin or edge), avoids that class of failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong MIME allow-list.&lt;/strong&gt; Compressing &lt;code&gt;image/jpeg&lt;/code&gt; or skipping &lt;code&gt;text/css&lt;/code&gt; because a preset used outdated type strings. Allow-lists that match what Lighthouse actually requests on the page clear the audit faster than generic host presets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High Brotli quality on uncached HTML.&lt;/strong&gt; Quality 11 on every HTML response can cost more CPU milliseconds than the download saves on a fast connection. Moderate levels suit dynamic HTML; high effort fits offline precompression of static assets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt;.&lt;/strong&gt; Shared caches serve a gzip body to a Brotli-capable client (or the reverse), which produces confusing lab versus browser results and intermittent audit failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming the CDN checkbox covers third-party hosts.&lt;/strong&gt; Lighthouse flags text files on your origin and on hosts you control in the waterfall. A script or stylesheet on a tag manager domain you do not configure will keep failing until that host compresses or the file leaves the critical path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expecting compression alone to fix LCP.&lt;/strong&gt; If the LCP element is a hero image, Brotli on HTML and CSS helps the document and styles, but the image path still dominates. Compression works alongside the LCP levers in the quick-fix guide, not instead of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify Content-Encoding on live URLs after every deploy
&lt;/h2&gt;

&lt;p&gt;Compression belongs in the same habit as Cache-Control: prove it on the live hostname after release, then watch it on a schedule so a platform default does not silently revert.&lt;/p&gt;

&lt;p&gt;A useful checklist per priority URL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The HTML document and two to three render-blocking CSS/JavaScript URLs from the lab waterfall.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Content-Encoding&lt;/code&gt; of &lt;code&gt;br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; from a client that sends both in &lt;code&gt;Accept-Encoding&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Transfer size materially smaller than content size for those text files.&lt;/li&gt;
&lt;li&gt;LCP images left alone by the compression layer (no accidental re-encoding).&lt;/li&gt;
&lt;li&gt;A PageSpeed Insights or Lighthouse run before and after so the Enable text compression audit and the Performance score share the same baseline.&lt;/li&gt;
&lt;li&gt;A re-check after CDN rule changes, host panel toggles, and major theme or plugin releases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Apogee Watcher fits as the scheduled lab layer across client sites. After Brotli and gzip are configured correctly, scheduled re-tests on priority URLs catch a host migration or “optimisation” plugin that drops &lt;code&gt;Content-Encoding&lt;/code&gt; without a ticket. Monitoring layers onto the stack you already run; a single red audit is not a reason to rip out an existing CDN.&lt;/p&gt;

&lt;p&gt;For a starting point on one URL before you standardise a portfolio, &lt;a href="https://apogeewatcher.com/check" rel="noopener noreferrer"&gt;apogeewatcher.com/check&lt;/a&gt; is enough. For ongoing multi-site schedules and budgets after compression and cache work, &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;start a trial&lt;/a&gt;. Either path keeps the same question in view: does &lt;code&gt;Content-Encoding&lt;/code&gt; still match what you configured last week?&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Brotli compression on the web?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Brotli is a compression format (content coding &lt;code&gt;br&lt;/code&gt;) commonly used for HTTP responses. For web performance it mainly shrinks text assets such as HTML, CSS, and JavaScript when the client advertises support in &lt;code&gt;Accept-Encoding&lt;/code&gt;. MDN’s glossary entry is a short reference; production work still needs header checks on live URLs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I enable Brotli or gzip?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Both. Brotli when negotiation succeeds, gzip when the client or path cannot use &lt;code&gt;br&lt;/code&gt;. Disabling gzip solely because Brotli exists leaves older clients and some intermediary hops on identity encoding for large text bodies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does Lighthouse still say Enable text compression?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A dashboard toggle is not enough. Individual text resources above the audit threshold must arrive with &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; on the lab request path. Headers and MIME type on each failing URL usually explain the miss faster than another host-panel screenshot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Brotli improve Core Web Vitals?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It can reduce download time for text on the critical path, which may help LCP and related lab metrics when those files were the bottleneck. It will not fix a slow origin alone or an uncompressed LCP image. Before-and-after runs on the same lab profile show whether the change mattered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can compression make PageSpeed scores worse?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. Excessive dynamic compression CPU, double compression, or compressing the wrong asset types can raise Time to First Byte or add work without shrinking useful bytes. Lab tests after every change, with precompression preferred for static files, catch those regressions early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need zstd as well?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Only when your CDN and clients benefit from it in production. Brotli and gzip remain the baseline pair for agency portfolios until zstd support is verified for your traffic.&lt;/p&gt;

&lt;p&gt;Compression belongs in the same delivery contract as caching and CDN rules. Naming the layer that owns encoding, limiting it to text that benefits, and verifying &lt;code&gt;Content-Encoding&lt;/code&gt; on live URLs after every deploy keeps the setup honest. When Brotli and gzip are configured that way, Lighthouse’s Enable text compression audit tends to clear without trading away Time to First Byte or inventing a false PageSpeed win.&lt;/p&gt;

&lt;p&gt;Ready to keep compression and Core Web Vitals honest across a client portfolio? &lt;a href="https://apogeewatcher.com/sign-up" rel="noopener noreferrer"&gt;Start a free trial of Apogee Watcher&lt;/a&gt; or &lt;a href="https://apogeewatcher.com/check" rel="noopener noreferrer"&gt;run a single URL check&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression" rel="noopener noreferrer"&gt;Enable text compression (Lighthouse)&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/speed/docs/insights/EnableCompression" rel="noopener noreferrer"&gt;Enable Compression&lt;/a&gt; (PageSpeed Insights / Google)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Brotli_compression" rel="noopener noreferrer"&gt;Brotli compression (MDN Glossary)&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/gzip_compression" rel="noopener noreferrer"&gt;gzip compression (MDN Glossary)&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/" rel="noopener noreferrer"&gt;NGINX Brotli module&lt;/a&gt; (NGINX Docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/google/ngx_brotli" rel="noopener noreferrer"&gt;google/ngx_brotli&lt;/a&gt; (GitHub)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/google/brotli" rel="noopener noreferrer"&gt;google/brotli&lt;/a&gt; (GitHub)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules" rel="noopener noreferrer"&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks" rel="noopener noreferrer"&gt;Cache-Control Headers for Web Performance: CDN and Browser Caching That Sticks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apogeewatcher.com/blog/quick-way-to-fix-lcp" rel="noopener noreferrer"&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>seo</category>
    </item>
    <item>
      <title>Why is PageSpeed Insights worse than my local Lighthouse score?</title>
      <dc:creator>Apogee Watcher</dc:creator>
      <pubDate>Fri, 02 Oct 2026 07:53:43 +0000</pubDate>
      <link>https://dev.to/apogeewatcher/why-is-pagespeed-insights-worse-than-my-local-lighthouse-score-5dpj</link>
      <guid>https://dev.to/apogeewatcher/why-is-pagespeed-insights-worse-than-my-local-lighthouse-score-5dpj</guid>
      <description>&lt;p&gt;You run Lighthouse in Chrome DevTools on a client URL and see Performance 94. You paste the same URL into PageSpeed Insights and the lab Performance score drops to the sixties. The audits look related. The numbers do not. Neither result is “lying.” They ran the same Lighthouse family of audits on different machines, with different throttling behaviour, and often with different cache and extension state.&lt;/p&gt;

&lt;p&gt;That gap shows up constantly in agency Slack threads and client calls. People then optimise against the friendlier number, or treat PageSpeed Insights as broken. What follows explains why PageSpeed Insights lab data is often worse than a local Lighthouse run, how to compare fairly, and which result to trust for client work. For how Lighthouse turns metrics into a score, see &lt;a href="https://apogeewatcher.com/blog/how-lighthouse-performance-scores-recorded-calculated?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=why-pagespeed-insights-worse-than-local-lighthouse" rel="noopener noreferrer"&gt;How Lighthouse Performance Scores Are Recorded and Calculated&lt;/a&gt;. For when one-off PageSpeed Insights checks stop being enough, see &lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=why-pagespeed-insights-worse-than-local-lighthouse" rel="noopener noreferrer"&gt;PageSpeed Insights vs Automated Monitoring&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Same Lighthouse engine, different machines
&lt;/h2&gt;

&lt;p&gt;PageSpeed Insights lab results are Lighthouse runs on Google’s shared infrastructure. Chrome DevTools Lighthouse and the Lighthouse CLI run on your laptop. The audit set is related. The CPU is not.&lt;/p&gt;

&lt;p&gt;Lighthouse records a &lt;strong&gt;benchmarkIndex&lt;/strong&gt; (device score) that describes how fast the host can run JavaScript before the audited page load. A powerful developer machine often scores much higher than the PageSpeed Insights workers. Mobile runs also apply a CPU slowdown (commonly described as about 4×) so the lab approximates mid-tier phones. Four times a fast laptop is still faster than four times a slower shared worker. Long tasks, Total Blocking Time, and Interaction to Next Paint proxies move first when the host is slower. Largest Contentful Paint and other paint timings can move too when layout and script work stretch.&lt;/p&gt;

&lt;p&gt;Network path and test location add another layer. PageSpeed Insights picks from a small set of regions. Your laptop sits on your office fibre next to a nearby CDN edge. Cold loads on a distant worker see different latency even before CPU differences matter.&lt;/p&gt;

&lt;p&gt;So a lower PageSpeed Insights lab score does not prove the site “got worse overnight.” It often proves you compared two hosts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Total Blocking Time jumps on PageSpeed Insights
&lt;/h2&gt;

&lt;p&gt;Total Blocking Time is especially sensitive to host speed. It sums the portions of long tasks that exceed 50 milliseconds during page load. On a fast local CPU, many tasks finish just under that line and never enter Total Blocking Time. On a slower PageSpeed Insights worker, the same work crosses 50 milliseconds and the metric spikes. Performance score then falls even when First Contentful Paint only moved a little.&lt;/p&gt;

&lt;p&gt;That pattern is well documented in developer threads and Lighthouse discussions: throttling and slower hosts push borderline tasks over the threshold. Simulated throttling (PageSpeed Insights lab default) is also not the same as packet-level throttling used by some other lab tools. Treat PageSpeed Insights lab numbers as one environment, not as a perfect replay of your MacBook.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local pollution: extensions, cache, and warm state
&lt;/h2&gt;

&lt;p&gt;Local Lighthouse can look better for reasons that have nothing to do with the production HTML.&lt;/p&gt;

&lt;p&gt;Chrome extensions inject scripts and change network behaviour. A warm disk cache and service worker can skip work that a cold PageSpeed Insights load always pays. Cookie banners and consent layers may already be dismissed on your profile. Antivirus, VPN, and other processes on the machine add noise. DevTools may warn when it detects conditions that skew the audit; PageSpeed Insights starts from a cleaner cold profile on Google’s side.&lt;/p&gt;

&lt;p&gt;Use an Incognito window with extensions disabled, or the Lighthouse CLI against a clean profile, when you need a local baseline. Even then, expect residual host-speed differences versus PageSpeed Insights. A clean local profile removes extension noise; it does not turn your laptop into Google’s lab workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not mix PageSpeed Insights field data with local lab
&lt;/h2&gt;

&lt;p&gt;PageSpeed Insights shows two stories on one page. The top block is Chrome UX Report field data when enough real Chrome users visited the origin or URL. The lower block is a fresh Lighthouse lab run.&lt;/p&gt;

&lt;p&gt;Your local Lighthouse score is lab only. Comparing a local Performance score to the field Core Web Vitals categories is a category error. Field windows cover days of real devices and networks. Lab is one controlled load. Lab-versus-field reconciliation is a separate topic; here the focus is local lab versus PageSpeed Insights lab.&lt;/p&gt;

&lt;p&gt;If field looks healthier than PageSpeed Insights lab, users may be on faster devices, revisit with cache, or you may be reading origin-level field against a URL-level lab run. Calibrate, do not average the two into one fake “truth.”&lt;/p&gt;

&lt;h2&gt;
  
  
  How to compare fairly (and what to trust for client work)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;What it measures&lt;/th&gt;
&lt;th&gt;Best use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chrome DevTools / local CLI&lt;/td&gt;
&lt;td&gt;Lab on your machine&lt;/td&gt;
&lt;td&gt;Before/after while debugging the same URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PageSpeed Insights lab&lt;/td&gt;
&lt;td&gt;Lab on Google’s workers&lt;/td&gt;
&lt;td&gt;Shareable cold-load baseline close to what clients paste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PageSpeed Insights field (CrUX)&lt;/td&gt;
&lt;td&gt;Real-user Core Web Vitals&lt;/td&gt;
&lt;td&gt;Trend and eligibility, not a Lighthouse score twin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rules that keep agencies from mixing incompatible scores:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compare before and after on the same tool.&lt;/strong&gt; Local 94 → local 88 after a change is useful. Local 94 versus PageSpeed Insights 61 is not a regression proof.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match strategy.&lt;/strong&gt; Mobile versus mobile. Desktop versus desktop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer cold loads&lt;/strong&gt; when you claim a public score. Clear cache or use a clean profile locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the device score / environment notes&lt;/strong&gt; in the Lighthouse JSON when you need to explain a gap to a technical lead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For client reporting, prefer a stable lab path.&lt;/strong&gt; Scheduled PageSpeed Insights-style runs from a monitoring product reduce “my laptop versus your laptop” arguments. Spot checks still help debugging; they are a weak single source of truth for retainers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;DebugBear’s comparison of PageSpeed Insights and Lighthouse, and Google’s own Lighthouse variability notes, make the same point: synthetic scores depend on CPU, location, Chrome version, and throttling method. Absolute equality across tools is the wrong goal. Directional agreement on the same tool is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is PageSpeed Insights “more accurate” than local Lighthouse?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For cold-load lab diagnostics that clients can reopen in a browser, PageSpeed Insights is often the better shared reference. For day-to-day engineering, local Lighthouse before/after on the same machine is faster and still valid. Neither replaces field Core Web Vitals when you need real-user truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my local Lighthouse match PageSpeed Insights sometimes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When host speeds are closer, the URL is light on main-thread work, or the runs simply land nearer each other, gaps shrink. Heavy JavaScript and layout work widen them. Treat occasional agreement as luck on a light page, not proof that the two environments are interchangeable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I raise local CPU slowdown until scores match PageSpeed Insights?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can experiment with CLI throttling for research. Do not treat a personalised slowdown as a contract with the client unless everyone agrees that environment is the baseline. Document the tool and settings you will use in the retainer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a better local score mean Search Console will improve?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not by itself. Search Console and Chrome UX Report track field data. Lab wins help you find fixes; field windows confirm whether real users felt them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;Pick one money URL. Run Lighthouse twice locally in a clean profile and note the spread. Run PageSpeed Insights lab on the same URL and strategy. Write down host differences instead of merging the scores. Put the PageSpeed Insights lab number (or a scheduled monitoring run) in the client pack when you need a shareable baseline, and keep local Lighthouse for the fix loop.&lt;/p&gt;

&lt;p&gt;If you manage many client origins, automate the PageSpeed Insights-shaped lab path so every site uses the same cold-load recipe. That is the operational answer to “whose Lighthouse do we believe?”: agree the environment once, then track change inside it. Spot laptop runs stay useful for debugging; they should not be the only number in the monthly pack.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.debugbear.com/blog/why-is-my-lighthouse-score-different-from-pagespeed-insights" rel="noopener noreferrer"&gt;PageSpeed Insights vs. Lighthouse: What's the Difference?&lt;/a&gt; (DebugBear)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/GoogleChrome/lighthouse/blob/main/docs/variability.md" rel="noopener noreferrer"&gt;Lighthouse variability / scoring environment&lt;/a&gt; (Chrome Lighthouse docs)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/75326384/why-is-lighthouse-data-reported-via-the-pagespeed-insights-api-consistently-diff" rel="noopener noreferrer"&gt;Why Lighthouse via PageSpeed Insights API differs from CLI&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/78156164/why-is-tbt-on-psi-so-different-from-my-local-machine" rel="noopener noreferrer"&gt;Why TBT on PageSpeed Insights differs from a local machine&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/how-lighthouse-performance-scores-recorded-calculated" rel="noopener noreferrer"&gt;How Lighthouse Performance Scores Are Recorded and Calculated&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough" rel="noopener noreferrer"&gt;PageSpeed Insights vs Automated Monitoring: When Manual Checks Aren't Enough&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webperf</category>
      <category>corewebvitals</category>
      <category>lighthouse</category>
      <category>pagespeed</category>
    </item>
  </channel>
</rss>
