<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Planet Performance</title>
<link>http://perfplanet.com/</link>
<description>News and views from the web performance blogosphere</description>
<language>en-us</language>
<pubDate>Sat, 13 Jun 2026 05:20:24 -0700</pubDate>
<lastBuildDate>Sat, 13 Jun 2026 05:20:24 -0700</lastBuildDate>
<atom:link href="http://perfplanet.com/rss.xml" rel="self" type="application/rss+xml" />
<item>
<title>Front-End’s Missing Metric: The TBT Window</title>
<link>https://csswizardry.com/2026/06/front-ends-missing-metric-the-tbt-window/</link>
<guid isPermaLink="true">https://csswizardry.com/2026/06/front-ends-missing-metric-the-tbt-window/</guid>
<description>The TBT Window is the FCP-to-TTI interval used to calculate Total Blocking Time. If FCP or TTI moves, TBT can change even when long tasks do not.</description>
<pubDate>1 June 2026, 4:30 am</pubDate>
<content:encoded><![CDATA[The TBT Window is the FCP-to-TTI interval used to calculate Total Blocking Time. If FCP or TTI moves, TBT can change even when long tasks do not.]]></content:encoded>
</item>

<item>
<title>How To Set Up Performance Alerts On Your Website</title>
<link>https://www.debugbear.com/blog/web-performance-monitoring-alerts</link>
<guid isPermaLink="true">https://www.debugbear.com/blog/web-performance-monitoring-alerts</guid>
<description>Learn how to set up performance budgets to monitor Core Web Vitals and other key metrics such as Time To First Byte and First Contentful Paint.</description>
<pubDate>27 May 2026, 5:00 pm</pubDate>
<content:encoded><![CDATA[<p>Web performance is important if you want to deliver a good user experience. But it's easy for websites to regress over time.</p>
<p>In this article, we'll explain how you can detect performance regressions, make the right people in your team aware of them, and get the data you need to identify what caused a regression.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Why is web performance monitoring important?<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#why-is-web-performance-monitoring-important" class="hash-link" aria-label="Direct link to Why is web performance monitoring important?" title="Direct link to Why is web performance monitoring important?">​</a></h2>
<p>Performance issues often come up once a website is released, as features are gradually updated or third-party scripts are added. Monitoring your website is essential to maintaining good performance over time.</p>
<p>Slowdowns can reduce conversions, hurt SEO (search engine optimization) rankings, increase bounce rates, and negatively impact customer trust and revenue. The longer regressions go undetected, the more challenging it is to detect what changed and when.</p>
<p>Checking dashboards daily works, but isn't a sustainable or time-efficient solution. Automated monitoring and alerting solve this problem by continuously watching your metrics and notifying you the moment problems begin to arise.</p>
<p>When you get notified of a regression, you need the ability to compare test results over time and trace metric changes back to specific technical causes. For example:</p>
<ul>
<li>Was a heavier image added?</li>
<li>Did a script start blocking the main thread?</li>
</ul>
<div class="theme-admonition theme-admonition-tip admonition_LMjb alert alert--success"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pGk6"><p>The real value of performance monitoring comes from comparing test results after a change.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_FNw8">How to set up monitoring for your website<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#how-to-set-up-monitoring-for-your-website" class="hash-link" aria-label="Direct link to How to set up monitoring for your website" title="Direct link to How to set up monitoring for your website">​</a></h2>
<p><a href="https://www.debugbear.com/" target="_blank" rel="noopener noreferrer">DebugBear</a> lets you keep track of your web performance using scheduled synthetic tests, real user analytics, and <a href="https://www.debugbear.com/blog/chrome-user-experience-report">Google CrUX data</a>.</p>
<p>To run synthetic tests, all you need to do is add the URLs you want to monitor. To collect real user monitoring data you need to <a href="https://www.debugbear.com/docs/rum/setup">install a small JavaScript snippet on your website</a>.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/fe8b756dd8e01367bc17fb4c442d9c01.png" alt="DebugBear monitoring dashboard" data-abc="true" class="img_CujE"></p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">How to set up alerts<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#how-to-set-up-alerts" class="hash-link" aria-label="Direct link to How to set up alerts" title="Direct link to How to set up alerts">​</a></h2>
<p>Once you've set up monitoring, you can configure budgets and notification channels to get alerted when performance changes.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">What is a performance budget?<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#what-is-a-performance-budget" class="hash-link" aria-label="Direct link to What is a performance budget?" title="Direct link to What is a performance budget?">​</a></h3>
<p>A <a href="https://www.debugbear.com/docs/performance-budgets">performance budget</a> allows you to set metric thresholds based on your needs. Once the threshold is breached, you and your team will receive an alert. This allows you to define which performance changes matter to your team and get notified immediately when thresholds are exceeded.</p>
<div class="theme-admonition theme-admonition-info admonition_LMjb alert alert--info"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_pGk6"><p>Budgets can also be enforced in <a href="https://www.debugbear.com/docs/performance-budgets#impact-on-ci-builds" target="_blank" rel="noopener noreferrer">CI/CD pipelines</a>, catching issues before they reach production.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Why use performance budgets?<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#why-use-performance-budgets" class="hash-link" aria-label="Direct link to Why use performance budgets?" title="Direct link to Why use performance budgets?">​</a></h3>
<p>DebugBear automatically detects major changes on your website. But that doesn't necessarily match the metrics that matter to your team, or the frequency of alerts you need.</p>
<p>Performance budgets set clear boundaries for what constitutes a breach. If a metric crosses a threshold set up by your team, then investigation and a fix are needed. Without performance budgets, it becomes difficult to distinguish between normal metric fluctuations and meaningful regressions that require investigation.</p>
<p>Performance budgets add a layer of insurance to your monitoring:</p>
<ul>
<li><strong>Custom thresholds tailored to your site</strong>: You can define thresholds that best suit your website rather than relying on the standard ones.</li>
<li><strong>Dashboard visibility</strong>: See which pages are meeting targets and which are failing.</li>
<li><strong>Proactive monitoring</strong>: Instead of receiving feedback from visitors that your website is slow, resolve the issue without damaging conversions and bounce rates.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Goals for a solid alerting setup<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#goals-for-a-solid-alerting-setup" class="hash-link" aria-label="Direct link to Goals for a solid alerting setup" title="Direct link to Goals for a solid alerting setup">​</a></h3>
<p>When setting up your first performance budgets, it's a good idea to think about what purpose they serve and how often your team is alerted.</p>
<p>Overall, the goal is to catch regressions in real time, before they impact users or business metrics. Before creating your first performance budget, consider the following questions:</p>
<ul>
<li><strong>What does our previous data look like?</strong> Setting up thresholds starts by looking at recent data. You want budgets that reflect a true trend change.</li>
<li><strong>What channels should notifications be sent to?</strong> Alerts can be delivered by email or to an integration such as Slack or Teams. Deciding which team members receive these alerts, and where they're sent, is vital so changes can be resolved together as they happen.</li>
<li><strong>Will these alerts lead to action?</strong> If goals are unrealistic, then many alerts could be ignored. Setting appropriate budgets will avoid notification fatigue.</li>
</ul>
<p>You also need to make sure your alerts stay up to date, since they can become outdated as pages improve. Taking stock every few months allows budgets to be adjusted and remain meaningful.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Understanding performance thresholds<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#understanding-performance-thresholds" class="hash-link" aria-label="Direct link to Understanding performance thresholds" title="Direct link to Understanding performance thresholds">​</a></h2>
<p>A great way to understand performance budgets is by looking at the <a href="https://www.debugbear.com/docs/metrics/largest-contentful-paint" target="_blank" rel="noopener noreferrer">Largest Contentful Paint (LCP)</a> thresholds. There are three ranges: Good, Needs Improvement, and Poor.</p>
<ul>
<li><strong>Good</strong> — 2.5 seconds and under</li>
<li><strong>Needs Improvement</strong> — 2.5 to 4 seconds</li>
<li><strong>Poor</strong> — Over 4 seconds</li>
</ul>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/9266eaf3b657dfe98a43070a4c6e4b13.png" alt="Largest Contentful Paint thresholds" data-abc="true" class="img_CujE"></p>
<p>These thresholds provide a starting point, but your budgets should reflect your site's current situation. In this example from <code>searchengineland.com</code> in our <a href="https://www.debugbear.com/project/25972" target="_blank" rel="noopener noreferrer">demo project</a>, the LCP score is currently 2.23 seconds, with a recent history of heavy regressions.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/00b3401d1523410dce798b4e676c1764.png" alt="LCP example" data-abc="true" class="img_CujE"></p>
<p>Setting a budget at 2500 ms ensures you're notified before visitors endure a slow experience.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Setting up your first performance budget<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#setting-up-your-first-performance-budget" class="hash-link" aria-label="Direct link to Setting up your first performance budget" title="Direct link to Setting up your first performance budget">​</a></h2>
<p>You can configure performance budgets in your page settings. Open a monitoring result, select <strong>Page Settings</strong> in the sidebar, click <strong>Show Advanced</strong>, then <strong>Add Performance Budget</strong>.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/36c04cda73e104555dd1bb384a59606e.png" alt="Advanced settings" data-abc="true" class="img_CujE"></p>
<p>Click <strong>Create Performance Budget</strong> to define a new budget. Name your budget and select the metric you want to be alerted on. In this case, we want Largest Contentful Paint.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/71a4a3dabd591c385cce305f5552e88f.png" alt="Metric selection" data-abc="true" class="img_CujE"></p>
<p>Next, we need to create the alert condition. Since we are dealing with the LCP good threshold, we can select 'goes above' and add 2500 ms as our threshold. Then click <strong>Create</strong> and save the page settings.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/85d76c6bce72440145f1b6e9ff0fd6d8.png" alt="LCP budget conditions" data-abc="true" class="img_CujE"></p>
<div class="theme-admonition theme-admonition-tip admonition_LMjb alert alert--success"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pGk6"><p>For detailed step-by-step instructions, see the <a href="https://www.debugbear.com/docs/performance-budgets" target="_blank" rel="noopener noreferrer">performance budgets documentation</a>.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Which metrics should you set alerts for?<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#which-metrics-should-you-set-alerts-for" class="hash-link" aria-label="Direct link to Which metrics should you set alerts for?" title="Direct link to Which metrics should you set alerts for?">​</a></h2>
<p>If you're new to performance budgets, the fewer metrics you set alerts for, the better. This helps avoid alert fatigue: if a lot of alerts are consistently coming in from many different metrics, they may ultimately get ignored.</p>
<p>Critical metrics, such as the <a href="https://www.debugbear.com/docs/core-web-vitals-metrics" target="_blank" rel="noopener noreferrer">Core Web Vitals</a> are a great place to start. You can then fine-tuner alert thresholds for your website. Let's take a look at some key metrics and the reasons for monitoring them.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Largest Contentful Paint<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#largest-contentful-paint" class="hash-link" aria-label="Direct link to Largest Contentful Paint" title="Direct link to Largest Contentful Paint">​</a></h3>
<p>LCP measures when the main content becomes visible. Set a "goes above" alert at the good threshold (2500ms) or slightly below your current baseline to catch regressions early.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Cumulative Layout Shift<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#cumulative-layout-shift" class="hash-link" aria-label="Direct link to Cumulative Layout Shift" title="Direct link to Cumulative Layout Shift">​</a></h3>
<p><a href="https://www.debugbear.com/docs/metrics/cumulative-layout-shift" target="_blank" rel="noopener noreferrer">Cumulative Layout Shift (CLS)</a> measures visual stability by tracking how much page content unexpectedly shifts during loading. Layout shifts frustrate users and often indicate missing image dimensions, font swaps, or injected ad content. A good CLS score is under 0.1, so set your budget there.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Interaction to Next Paint<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#interaction-to-next-paint" class="hash-link" aria-label="Direct link to Interaction to Next Paint" title="Direct link to Interaction to Next Paint">​</a></h3>
<p><a href="https://www.debugbear.com/docs/metrics/interaction-to-next-paint" target="_blank" rel="noopener noreferrer">Interaction to Next Paint (INP)</a> measures responsiveness by tracking the time from user interaction to the next paint. High INP indicates that the main thread is blocked, often due to heavy JavaScript execution. A good INP score is under 200ms, but consider an "increases by" alert of 20% to catch significant regressions relative to your baseline.</p>
<p>Real-time INP can only be measured well with real user data. You can check CrUX INP scores, but those will take a few weeks to update since Google aggregates data over a 28-day rolling window.</p>
<p>You can use <a href="https://www.debugbear.com/docs/metrics/total-blocking-time" target="_blank" rel="noopener noreferrer">Total Blocking Time (TBT)</a> as a very rough proxy for interaction delays on your page. Or you can script specific interactions in your synthetic checks and measure INP scores for them.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Time To First Byte<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#time-to-first-byte" class="hash-link" aria-label="Direct link to Time To First Byte" title="Direct link to Time To First Byte">​</a></h3>
<p><a href="https://www.debugbear.com/docs/metrics/time-to-first-byte" target="_blank" rel="noopener noreferrer">Time To First Byte (TTFB)</a> measures server response time. Poor TTFB delays every other loading milestone. The good range is under 800ms, but an "increases by" alert of 10% can catch server-side regressions before they cascade into user-facing problems.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">First Contentful Paint<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#first-contentful-paint" class="hash-link" aria-label="Direct link to First Contentful Paint" title="Direct link to First Contentful Paint">​</a></h3>
<p><a href="https://www.debugbear.com/docs/metrics/first-contentful-paint" target="_blank" rel="noopener noreferrer">First Contentful Paint (FCP)</a> measures how quickly users see the first piece of visible content. FCP and LCP often share bottlenecks, so an FCP regression may signal an LCP issue as well. The good threshold is 1.8 seconds.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Lighthouse Performance Score<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#lighthouse-performance-score" class="hash-link" aria-label="Direct link to Lighthouse Performance Score" title="Direct link to Lighthouse Performance Score">​</a></h3>
<p>The <a href="https://www.debugbear.com/blog/lighthouse-performance-audits" target="_blank" rel="noopener noreferrer">Lighthouse Performance</a> score provides an overall assessment on a scale of 0 to 100. A score below 90, or a significant percentage drop, can indicate broad regressions that individual metrics might not surface clearly.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Page Weight<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#page-weight" class="hash-link" aria-label="Direct link to Page Weight" title="Direct link to Page Weight">​</a></h3>
<p><a href="https://www.debugbear.com/blog/page-weight-website-speed">Page weight</a> (the total size of all resources) doesn't always correlate with poor performance, but monitoring it can explain LCP or FCP regressions. An "increases by" alert of 5% helps you catch when new assets are added that might impact loading.</p>
<div class="theme-admonition theme-admonition-tip admonition_LMjb alert alert--success"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pGk6"><p>Unlike page load milestone metrics, page weight is often more stable and does not depend on random variation in server response timings.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_FNw8">The budgets dashboard<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#the-budgets-dashboard" class="hash-link" aria-label="Direct link to The budgets dashboard" title="Direct link to The budgets dashboard">​</a></h2>
<p>Once you've set up performance budgets, the budgets dashboard provides a centralized view of all pages and their budget status. Any team member can quickly see which pages have budgets applied and whether they're currently passing or failing. New budgets can be created by clicking the plus icon in the top right corner.</p>
<p>Viewing the budgets dashboard here, we can see that there has been a major LCP regression.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/590f458d9618b723a374f698964be5cd.png" alt="Budgets dashboard" data-abc="true" class="img_CujE"></p>
<p>Clicking on the page will show the latest test result with the change. You can use the compare pages toggle to identify what caused the regression.</p>
<p>In this case, we can see the LCP image has changed, with the new image now being dependent on an additional LCP initiator request.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/7e7829d04bff62df62d904f5c0107b91.png" alt="LCP request chain" data-abc="true" class="img_CujE"></p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Setting up alerts for your team<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#setting-up-alerts-for-your-team" class="hash-link" aria-label="Direct link to Setting up alerts for your team" title="Direct link to Setting up alerts for your team">​</a></h2>
<p>Email alerts work, but they have limitations as they can easily be missed. When a performance regression happens, you want the alert to land where your team is already working. Pairing email notifications with team chat integrations means faster action to fix issues.</p>
<p>Integrating alerts with tools like <a href="https://www.debugbear.com/docs/slack-integration">Slack</a> makes performance monitoring more collaborative and efficient. Alerts are delivered to a dedicated channel where the whole team can see them immediately. This keeps conversations in context, allowing team members to discuss regressions directly where the alert appeared, share findings, and coordinate fixes faster without the need to forward emails.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Configure alert notification channels<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#configure-alert-notification-channels" class="hash-link" aria-label="Direct link to Configure alert notification channels" title="Direct link to Configure alert notification channels">​</a></h3>
<p>To set up email notifications, mark the subscribe checkbox. Click the gear icon to configure notification settings.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/e8ff93a6167df46e0ee698b80b7584b4.png" alt="Subscribe for alerts" data-abc="true" class="img_CujE"></p>
<p>The <strong>Re-alert on consistent breaches</strong> option continues sending notifications while a budget remains breached. This setting ensures that further emails are sent if the breach continues.</p>
<p>You can also select which automatic alerts you want to receive, or mute notifications to reduce noise and keep alerts relevant.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/146742e25204c03998ebdd9be6fadb8d.png" alt="Lab alerts settings" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Slack integration<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#slack-integration" class="hash-link" aria-label="Direct link to Slack integration" title="Direct link to Slack integration">​</a></h3>
<p>To integrate with Slack, click <strong>Configure Channels</strong> on the budget dashboard to reach the integrations page, then <strong>Add to Slack</strong>. After authorizing access, select your channel and choose which alert types to send.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/c4a41660545ff4de1441b11a541cfcd0.png" alt="Notification channels" data-abc="true" class="img_CujE"></p>
<p>In this example, we created a new Slack channel called <code>#website-alerts</code>. Now all lab alerts will be automatically sent to this channel for your team to receive. For complete setup instructions, see the <a href="https://www.debugbear.com/docs/slack-integration" target="_blank" rel="noopener noreferrer">Slack integration guide</a>.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/95fb230dbd2be07239a576d3ba0c5bb1.png" alt="Slack channel added" data-abc="true" class="img_CujE"></p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">What happens after an alert?<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#what-happens-after-an-alert" class="hash-link" aria-label="Direct link to What happens after an alert?" title="Direct link to What happens after an alert?">​</a></h2>
<p>Once a budget is breached and an alert is received, you can quickly act to resolve the issue. Using the compare toggle on a test result is a great way to view test data side by side, making it easier to spot regressions and investigate their cause.</p>
<p>By comparing results over time, you can identify which changes introduced the issue, make a fix, and quickly confirm that performance is back to normal. This cycle of alerting, investigating, fixing, and verifying problems is what makes monitoring an important part of maintaining performance.</p>
<p>For example, when a synthetic alert is triggered, the comparison page lets you see what metrics changed. From there you can dive into specific technical changes: were new resources added to the page? Did the priority of a request change? Are there new long CPU tasks?</p>
<p>You can also visually compare test results and view a side-by-side video recording of the page load. That makes it easy to show team members the end-user impact of a regression.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/6c5bd70dc4a0f1586fb73a823672b05f.png" alt="Synthetic alert debugging" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Real User Monitoring alerts<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#real-user-monitoring-alerts" class="hash-link" aria-label="Direct link to Real User Monitoring alerts" title="Direct link to Real User Monitoring alerts">​</a></h3>
<p>You can also set up <a href="https://www.debugbear.com/docs/rum/real-user-monitoring" target="_blank" rel="noopener noreferrer">Real User Monitoring (RUM)</a> alerts to surface issues affecting visitors.</p>
<p>Within RUM settings, go to the <strong>Alerts &amp; Budgets</strong> tab and subscribe to email alerts. Click the gear icon to configure alert frequency and metric thresholds.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/d24871481aa7a95d98cb357386a59a0c.png" alt="RUM settings" data-abc="true" class="img_CujE"></p>
<p>For custom budgets, click <strong>Create Budget</strong> and configure the following conditions:</p>
<ul>
<li><strong>Check Every</strong>: How often to evaluate the budget (hourly to every 72 hours)</li>
<li><strong>Alert After</strong>: When to notify (immediately, once after breach, or twice after breach)</li>
<li><strong>Baseline Duration</strong>: The reference period for detecting changes</li>
</ul>
<p>In this example, we have set up a custom budget to monitor the LCP score for the homepage. This is checked every 4 hours. If there is an increase of 10% compared to the last 4 hours, an alert will be sent.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/d6a69dc31466883c23e37cfaaa0f8558.png" alt="RUM budget conditions" data-abc="true" class="img_CujE"></p>
<p>When a RUM alert is breached, an email will be sent notifying you of the change.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/346ef38f49822671bce7739518accc40.png" alt="Email RUM alert" data-abc="true" class="img_CujE"></p>
<p>If you have Slack integration set up, these alerts can be configured to be sent to a dedicated Slack channel.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/055b3763c59ef42fa25df63d9512c834.png" alt="Slack RUM alert" data-abc="true" class="img_CujE"></p>
<p>When clicking on the details for either an email or Slack alert, you'll be brought to the RUM alert landing page, where you can view more details on the change, as well as the alert history graph. In this case, we can see the LCP score has been regressing over the last 24 hours.</p>
<p>After a slight improvement in the previous 4-hour period, the regression exceeded 10% and the notification was sent. This timeline gives us context that the LCP score has been creeping up.</p>
<p>From this page, we can inspect further to see what has caused the change, looking at potential causes such as a TTFB increase or inspecting the <a href="https://www.debugbear.com/docs/metrics/largest-contentful-paint#measuring-lcp-sub-parts" target="_blank" rel="noopener noreferrer">LCP sub-parts</a> data.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/3b96f9c726f93281bef2852d7824e471.png" alt="RUM alert landing page" data-abc="true" class="img_CujE"></p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Monitoring best practices<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#monitoring-best-practices" class="hash-link" aria-label="Direct link to Monitoring best practices" title="Direct link to Monitoring best practices">​</a></h2>
<p>If it is your first time setting up alerts, these principles will help you get the most from performance alerting:</p>
<ul>
<li><strong>Start small.</strong> Don't overwhelm yourself and your team with budgets. Begin with Core Web Vitals on your high-traffic pages. Then continue with more metrics and pages.</li>
<li><strong>Set realistic thresholds.</strong> Base budgets on your current performance plus a reasonable buffer. Alerts should indicate genuine regressions.</li>
<li><strong>Combine lab and field data.</strong> Using alerts on both lab and RUM data helps catch regressions sooner, minimizing impact on user experience, SEO rankings, and conversions.</li>
<li><strong>Make alerts actionable.</strong> Once an alert has been sent, compare against previous data to see what changed.</li>
<li><strong>Integrate with your team.</strong> Inviting team members to view the budget dashboard, receive email alerts, and join a Slack channel means everyone is on the same page.</li>
<li><strong>Review and adjust.</strong> Audit your budgets over time to reflect your website's current performance and future targets.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Get started with performance monitoring<a href="https://www.debugbear.com/blog/web-performance-monitoring-alerts#get-started-with-performance-monitoring" class="hash-link" aria-label="Direct link to Get started with performance monitoring" title="Direct link to Get started with performance monitoring">​</a></h2>
<p>Performance budgets turn passive observation into proactive protection. Instead of discovering regressions days or weeks later through user complaints or ranking drops, you'll know immediately when metrics drift outside acceptable ranges.</p>
<p>Ready to set up monitoring for your site? <a href="https://www.debugbear.com/" target="_blank" rel="noopener noreferrer">Start a free DebugBear trial</a> and configure your first performance budgets in minutes.</p>
<!-- -->
<div class="cta_Vy7l"><div class="ctaContainer_dzq8"><div class="ctaImage_MZ5b"><img src="https://www.debugbear.com/dimg/57001785e35454b95f43aa4f3bf6f857.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="https://www.debugbear.com/dimg/b2c0ae7a8dfbc4b18ba827a334c5c1af.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><div class="ctaContent_VgWi"><h2>Monitor Page Speed &amp; Core Web Vitals</h2><div class="ctaBenefits_OYw7"><h3>DebugBear monitoring includes:</h3><ul><li>In-depth Page Speed Reports</li><li>Automated Recommendations</li><li>Real User Analytics Data</li></ul></div><div><a href="https://www.debugbear.com/signup" class="ctaButton_Uos9 hidden-when-logged-in"><span>Start Free Trial</span></a><a href="https://www.debugbear.com/app" class="ctaButton_Uos9 visible-when-logged-in"><span>Go To App</span></a></div></div></div></div>]]></content:encoded>
</item>

<item>
<title>Smarter Website Caching With No-Vary-Search</title>
<link>https://www.debugbear.com/blog/no-vary-search</link>
<guid isPermaLink="true">https://www.debugbear.com/blog/no-vary-search</guid>
<description>Learn how No-Vary-Search improves caching for URLs with query parameters. This article explains how the header works, when it increases cache efficiency, and when to avoid it.</description>
<pubDate>25 May 2026, 5:00 pm</pubDate>
<content:encoded><![CDATA[<p>Modern websites rely heavily on query parameters that are used for tracking (<code>utm_source</code>), filtering (<code>?size=small</code>), pagination (<code>?page=3</code>), sorting (<code>?sort=quantity</code>), feature flags, search state, and countless other use cases.</p>
<p>However, this means websites can miss out on the performance benefits of <a href="https://www.debugbear.com/docs/http-cache-control-header">HTTP caching</a>. Even if two URLs return identical content, caches generally store them as separate entries simply because the query string differs. That leads to fragmented caches, lower cache hit rates, and unnecessary origin requests from <a href="https://www.debugbear.com/blog/cdn-cache">Content Delivery Network (CDN) caches</a>.</p>
<p>The new <code>No-Vary-Search</code> HTTP response header aims to solve this problem by giving browsers and CDNs more control over how query parameters affect cache keys.</p>
<p>In this article, we'll look at:</p>
<ul>
<li>why query parameters are problematic for caching,</li>
<li>how <code>No-Vary-Search</code> works,</li>
<li>what problems it solves,</li>
<li>advanced edge cases,</li>
<li>and when you should avoid using it.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_FNw8">The Problem with Query Parameter Caching<a href="https://www.debugbear.com/blog/no-vary-search#the-problem-with-query-parameter-caching" class="hash-link" aria-label="Direct link to The Problem with Query Parameter Caching" title="Direct link to The Problem with Query Parameter Caching">​</a></h2>
<p>Traditionally, caches treat the full URL as the cache key, which means these URLs are considered completely different resources:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-text codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">/products</span><br></span><span class="token-line"><span class="token plain">/products?utm_source=twitter</span><br></span><span class="token-line"><span class="token plain">/products?ref=homepage</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>Even if the response body is identical, most caches will create separate cache entries for every variation, and this creates several problems:</p>
<ol>
<li><strong>Lower Cache Hit Rates</strong>: A CDN may already have <code>/products</code> cached, but a request for <code>/products?utm_campaign=spring-sale</code> can still result in a cache miss. At scale, this significantly reduces cache efficiency.</li>
<li><strong>Increased Origin Traffic</strong>: More cache misses mean more requests hitting the origin server. For high-traffic applications, especially content-heavy sites, this increases infrastructure costs and backend load.</li>
<li><strong>Browser Cache Inefficiency</strong>: The same issue exists in browsers. A browser may already have a page cached, but a slightly different query parameter combination prevents cache reuse.</li>
<li><strong>Overly Complex Cache Rules</strong>: Many teams try to work around this problem manually by rewriting URLs, maintaining allowlists, stripping tracking parameters at the CDN layer, or configuring custom cache key normalization logic. These solutions are often vendor-specific and difficult to maintain consistently across platforms.</li>
</ol>
<p>This is where the new <code>No-Vary-Search</code> HTTP header comes into play.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">What Is No-Vary-Search?<a href="https://www.debugbear.com/blog/no-vary-search#what-is-no-vary-search" class="hash-link" aria-label="Direct link to What Is No-Vary-Search?" title="Direct link to What Is No-Vary-Search?">​</a></h2>
<p><code>No-Vary-Search</code> is a new HTTP response header that tells caches which query parameters should, or should not, affect cache matching. Instead of treating every query parameter as significant, servers can explicitly define which parameters matter, for example:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-http codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-http codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">No-Vary-Search: params=("utm_source" "utm_campaign")</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>This indicates that the <code>utm_source</code> and <code>utm_campaign</code> parameters should be ignored when matching cache entries.</p>
<div class="theme-admonition theme-admonition-info admonition_LMjb alert alert--info"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_pGk6"><p>Keep in mind that the syntax is strings separated by a space, not a comma.</p></div></div>
<p>As a result, all of these URLs can reuse the same cached response:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-text codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">/products</span><br></span><span class="token-line"><span class="token plain">/products?utm_source=twitter</span><br></span><span class="token-line"><span class="token plain">/products?utm_campaign=winter</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>The content is treated as equivalent for caching purposes. The header is part of ongoing work to improve cache efficiency and reduce unnecessary cache fragmentation on the modern web.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">More Complex Use Cases<a href="https://www.debugbear.com/blog/no-vary-search#more-complex-use-cases" class="hash-link" aria-label="Direct link to More Complex Use Cases" title="Direct link to More Complex Use Cases">​</a></h2>
<p>Real-world query parameter behavior is rarely simple: the position of query parameters may or may not matter, and different parameters may need different rules. <code>No-Vary-Search</code> supports more advanced patterns for handling these cases.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Ignoring Everything<a href="https://www.debugbear.com/blog/no-vary-search#ignoring-everything" class="hash-link" aria-label="Direct link to Ignoring Everything" title="Direct link to Ignoring Everything">​</a></h3>
<p>When a page does not vary by query string, we could set the header value to the following:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-http codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-http codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">No-Vary-Search: params</span><br></span><span class="token-line"><span class="token plain">// or</span><br></span><span class="token-line"><span class="token plain">No-Vary-Search: params=()</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>Keep in mind that this feature is still experimental. That is why there are two versions, <code>params</code> and <code>params=()</code>. Check <a href="https://github.com/httpwg/http-extensions/pull/3374" target="_blank" rel="noopener noreferrer">this http-extensions pull request</a> and <a href="https://issues.chromium.org/issues/492218542" target="_blank" rel="noopener noreferrer">this Chromium issue</a> as pinpointed by <a href="https://bsky.app/profile/tunetheweb.com" target="_blank" rel="noopener noreferrer">Barry Pollard</a> and <a href="https://twitter.com/csswizardry" target="_blank" rel="noopener noreferrer">Harry Roberts</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Ignore parameter order<a href="https://www.debugbear.com/blog/no-vary-search#ignore-parameter-order" class="hash-link" aria-label="Direct link to Ignore parameter order" title="Direct link to Ignore parameter order">​</a></h3>
<p>If a page returns the same content regardless of parameter order, we still want to serve it from one cache entry instead of caching each ordering as a different URL.</p>
<p>For example, the following URL:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-text codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">/shoes?size=small&amp;sort=price</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>Should be cached as the same page as:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-text codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">/shoes?sort=price&amp;size=small</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>To achieve that, we can set the header to:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-http codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-http codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">No-Vary-Search: key-order</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>And it will return the same page from cache for these two seemingly identical URLs.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Ignore everything except X, Y<a href="https://www.debugbear.com/blog/no-vary-search#ignore-everything-except-x-y" class="hash-link" aria-label="Direct link to Ignore everything except X, Y" title="Direct link to Ignore everything except X, Y">​</a></h3>
<p>Sometimes it is better to set the rule to ignore everything but have an exception for just a few query parameters and it can be done like the following:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-http codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-http codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">No-Vary-Search: params, except=("variant" "price")</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<div class="theme-admonition theme-admonition-tip admonition_LMjb alert alert--success"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pGk6"><p>Remember the syntax: rules are listed after a comma, while parameters are in quotation marks and separated by spaces.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Combining multiple rules<a href="https://www.debugbear.com/blog/no-vary-search#combining-multiple-rules" class="hash-link" aria-label="Direct link to Combining multiple rules" title="Direct link to Combining multiple rules">​</a></h3>
<p>We may have a scenario where we need to use multiple rules at the same time and it can be done like this:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-http codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-http codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">No-Vary-Search: params, key-order, except=("variant" "price")</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>This rule will instruct the cache that all parameters may be ignored, the order of query parameters does not matter, and to not ignore the <code>variant</code> and <code>price</code> parameters.</p>
<p>This way, all the following URLs will be cached under the same entry:</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-text codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token plain">/products/shoes?variant=compact&amp;size=small</span><br></span><span class="token-line"><span class="token plain">/products/shoes?size=small&amp;variant=compact</span><br></span><span class="token-line"><span class="token plain">/products/shoes?utm_source=google&amp;variant=compact</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<p>Combining the rules like this gives you fine-grained control over exactly which URLs share a single cache entry.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">When should you not use No-Vary-Search?<a href="https://www.debugbear.com/blog/no-vary-search#when-should-you-not-use-no-vary-search" class="hash-link" aria-label="Direct link to When should you not use No-Vary-Search?" title="Direct link to When should you not use No-Vary-Search?">​</a></h2>
<p><code>No-Vary-Search</code> is powerful, but using it incorrectly can cause serious caching bugs.</p>
<p>The rule is simple: never ignore query parameters that change the response content.</p>
<p>But to be more precise, you should not use it in the following examples:</p>
<ul>
<li><strong>Personalized Content</strong>: Avoid using it for parameters related to authentication, session state, localization, experiments, or personalization. For example <code>/dashboard?user=peter</code> must never share cache entries across users.</li>
<li><strong>Search Queries</strong>: Page <code>/search?q=laptop</code> is different from <code>/search?q=monitor</code> and that is why we shouldn't be ignoring the <code>q</code> query param as it would break the application.</li>
<li><strong>Pagination</strong>: Pagination parameters are also content-defining. Page <code>?page=1</code> is different from <code>?page=2</code>. These must remain distinct cache entries.</li>
<li><strong>Unclear Cache Behavior</strong>: If you're unsure whether a parameter affects content, it's safer not to ignore it. Incorrect cache reuse can lead to users seeing stale content, broken personalization, or even security issues.</li>
</ul>
<p>Keeping in mind these scenarios will help you avoid common caching problems.</p>
<div class="theme-admonition theme-admonition-tip admonition_LMjb alert alert--success"><div class="admonitionHeading_GGQ4"><span class="admonitionIcon_ifdW"><svg viewbox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pGk6"><p>This only matters if the query parameters are used by the backend server to render the HTML. If your client-side code is responsible for handling a <code>q</code> search parameter for example then it's fine to use <code>No-Vary-Search</code> for that parameter.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_FNw8">No-Vary-Search and speculation rules<a href="https://www.debugbear.com/blog/no-vary-search#no-vary-search-and-speculation-rules" class="hash-link" aria-label="Direct link to No-Vary-Search and speculation rules" title="Direct link to No-Vary-Search and speculation rules">​</a></h2>
<p><a href="https://www.debugbear.com/blog/speculation-rules">Speculation Rules</a> let web developers ask the browser to speculatively pre-render future pages a visitor is likely to visit. When the user actually navigates to the next page, this navigation can be practically instant.</p>
<p>However, you might have links to <code>/login</code>, <code>/login?source=sidebar</code> and <code>/login?source=footer</code>. If just the plain <code>/login</code> is pre-rendered the other two links won't result in an instant navigation. Using <code>No-Vary-Search</code> for the <code>source</code> parameter fixes this issue.</p>
<p>But what if you're pre-rendering the <code>/login</code> page but then click on <code>/login?source=sidebar</code> before the request is complete? The browser won't know about <code>No-Vary-Search</code> until the response is received.</p>
<p>To work around this problem, speculation rules offer the <code>expects_no_vary_search</code> option. The browser can then wait for the existing pre-render request instead of starting a new navigation.</p>
<pre tabindex="0" class="codeBlockStandalone_Nhx8 thin-scrollbar codeBlockContainer_aalF theme-code-block"><code class="codeBlockLines_RjmQ"><div class="language-html codeBlockContainer_aalF theme-code-block"><div class="codeBlockContent_MHx8"><pre tabindex="0" class="prism-code language-html codeBlock_zHgq thin-scrollbar"><code class="codeBlockLines_RjmQ"><span class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">script</span><span class="token tag"> </span><span class="token tag attr-name">type</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">speculationrules</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation">{</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"prerender"</span><span class="token script language-javascript operator">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation">[</span><span class="token script language-javascript punctuation">{</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"source"</span><span class="token script language-javascript operator">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string">"list"</span><span class="token script language-javascript punctuation">,</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"urls"</span><span class="token script language-javascript operator">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation">[</span><span class="token script language-javascript string">"/login"</span><span class="token script language-javascript punctuation">]</span><span class="token script language-javascript punctuation">,</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"expects_no_vary_search"</span><span class="token script language-javascript operator">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string">"params=(\"source\")"</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation">}</span><span class="token script language-javascript punctuation">]</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation">}</span><span class="token script language-javascript"></span><br></span><span class="token-line"><span class="token script language-javascript"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">script</span><span class="token tag punctuation">&gt;</span><br></span></code></pre><div class="buttonGroup_Sd8_"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_LnQD" aria-hidden="true"><svg viewbox="0 0 24 24" class="copyButtonIcon_t3l1"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewbox="0 0 24 24" class="copyButtonSuccessIcon_IiZV"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></code></pre>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Browser compatibility<a href="https://www.debugbear.com/blog/no-vary-search#browser-compatibility" class="hash-link" aria-label="Direct link to Browser compatibility" title="Direct link to Browser compatibility">​</a></h2>
<p>The feature is currently marked as Experimental which can change in the future. Below is a small browser compatibility matrix that shows where this feature is currently supported.</p>
<table><thead><tr><th>Feature</th><th>Chrome</th><th>Firefox</th><th>Opera</th><th>Safari</th><th>Edge</th></tr></thead><tbody><tr><td><code>No-Vary-Search</code> (Experimental)</td><td>Yes</td><td>No</td><td>Yes</td><td>No</td><td>Yes</td></tr></tbody></table>
<p>For full browser compatibility, check out the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/No-Vary-Search#browser_compatibility" target="_blank" rel="noopener noreferrer">MDN No-Vary-Search reference</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Summary<a href="https://www.debugbear.com/blog/no-vary-search#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>Query parameters have always been one of the messiest parts of HTTP caching. Most sites depend on them heavily, but traditional cache behavior treats every variation as a separate resource, even when the response is identical.</p>
<p><code>No-Vary-Search</code> introduces a cleaner and more standardized way to handle this problem. By explicitly defining which query parameters matter for cache matching, websites can:</p>
<ul>
<li>improve cache hit rates,</li>
<li>reduce origin traffic,</li>
<li>simplify cache configuration,</li>
<li>and improve browser cache reuse.</li>
</ul>
<p>For content-heavy websites with lots of tracking parameters, the performance impact can be significant. At the same time, the header must be used carefully. Ignoring the wrong parameters can easily introduce broken or unsafe cache behavior.</p>
<p>Like many caching optimizations, the mechanism itself is the easy part. The real work is correctly understanding which parts of a URL define the response.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Measure the impact of your performance work<a href="https://www.debugbear.com/blog/no-vary-search#measure-the-impact-of-your-performance-work" class="hash-link" aria-label="Direct link to Measure the impact of your performance work" title="Direct link to Measure the impact of your performance work">​</a></h2>
<p><a href="https://www.debugbear.com/" target="_blank" rel="noopener noreferrer">DebugBear</a> lets you monitor the performance of your website and identify high-impact optimizations. Get alerted to performance regressions and see how better performance leads to better business outcomes.</p>
<p><a href="https://www.debugbear.com/signup" target="_blank" rel="noopener noreferrer">Sign up for a free trial</a> and start monitoring your website today! Run scheduled synthetic tests, benchmark Google CrUX data, and measure real user experience all in one place.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/8eb3971f52cb1e6a7a664b85c5519a8f.png" alt="Website monitoring dashboard" data-abc="true" class="img_CujE"></p>
<!-- -->
<div class="cta_Vy7l"><div class="ctaContainer_dzq8"><div class="ctaImage_MZ5b"><img src="https://www.debugbear.com/dimg/57001785e35454b95f43aa4f3bf6f857.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="https://www.debugbear.com/dimg/b2c0ae7a8dfbc4b18ba827a334c5c1af.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><div class="ctaContent_VgWi"><h2>Monitor Page Speed &amp; Core Web Vitals</h2><div class="ctaBenefits_OYw7"><h3>DebugBear monitoring includes:</h3><ul><li>In-depth Page Speed Reports</li><li>Automated Recommendations</li><li>Real User Analytics Data</li></ul></div><div><a href="https://www.debugbear.com/signup" class="ctaButton_Uos9 hidden-when-logged-in"><span>Start Free Trial</span></a><a href="https://www.debugbear.com/app" class="ctaButton_Uos9 visible-when-logged-in"><span>Go To App</span></a></div></div></div></div>]]></content:encoded>
</item>

<item>
<title>10 Causes of Slow Websites (and How to Fix Them)</title>
<link>https://calibreapp.com/blog/causes-of-slow-websites</link>
<guid isPermaLink="true">https://calibreapp.com/blog/causes-of-slow-websites</guid>
<description>Slow websites cost rankings, conversions, and trust. Here are the ten most common causes of slow page loads, and how to fix each one.</description>
<pubDate>21 May 2026, 5:00 pm</pubDate>
<content:encoded><![CDATA[Slow websites cost rankings, conversions, and trust. Here are the ten most common causes of slow page loads, and how to fix each one.]]></content:encoded>
</item>

<item>
<title>Further Reading on AI Fatigue</title>
<link>https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/</link>
<guid isPermaLink="true">https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/</guid>
<description>&lt;p&gt;Last February, I wrote about &lt;a href=&quot;https://boris.schapira.dev/notes/2026-02-productivity-quality/&quot;&gt;productivity and quality&lt;/a&gt;: poorly thought-out delegation, the cognitive load on validators, the silent erosion of collective skills. A text built from an organizational perspective, drawing on my conversations with colleagues who ultimately hold roles peripheral to the code itself.&lt;/p&gt;
&lt;h2&gt;What I had missed&lt;/h2&gt;
&lt;p&gt;One of them shared with me an article by Siddhant Khare, who lived that same reality up close. He builds AI agent infrastructure, meaning the tools other engineers use to run AI in production. And he still ended up hitting a wall. Not a performance wall. A human one.&lt;/p&gt;
&lt;p&gt;His article, “&lt;a href=&quot;https://siddhantkhare.com/writing/ai-fatigue-is-real&quot;&gt;AI fatigue is real and nobody talks about it&lt;/a&gt;”, haunts me, as it significantly completes what I had written.&lt;/p&gt;
 &lt;div class=&quot;inline-note&quot;&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; There is no need to come tell me that AI is an ecological and economic waste; I am aware. What interests me is the fact that these tools are, today, a reality, and that this reality has human and organizational consequences.&lt;/p&gt;
&lt;p&gt;We can talk about how difficult it is to do without this technology in a competitive landscape where it is used massively, while also knowing it is not profitable in the long run. But that is not the subject of this specific post.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;The clash of probabilistic systems&lt;/h3&gt;
&lt;p&gt;My article talked about &lt;strong&gt;cognitive overload from validation&lt;/strong&gt;. What I had not named is a very specific source of that overload: the fact of collaborating with a fundamentally unpredictable system, while our brains are wired for determinism.&lt;/p&gt;
&lt;p&gt;Siddhant puts it with a precision I had not achieved:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;you are collaborating with a probabilistic system, and your brain is wired for deterministic ones. That mismatch is a constant, low-grade source of stress.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fact that the model decided to go a different direction today, that the same prompt produces different results from one day to the next, with no accessible explanation, no readable log, is terrible. For someone whose work depends on the ability to reason about deterministic systems, this is a source of quiet but constant anxiety.&lt;/p&gt;
&lt;p&gt;I know, of course, that this is not inevitable. There are ways to reduce LLM variability, to make them more predictable. But it is a long-haul effort, and it is easy to underestimate just how much this unpredictability is a source of stress for teams.&lt;/p&gt;
&lt;h3&gt;The treadmill of new tools&lt;/h3&gt;
&lt;p&gt;All the more so because the pressure is constant to stay “up to date” in a team dynamic that reinvents itself every week, every day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I fell into this trap hard. I was spending weekends evaluating new tools. Reading every changelog. Watching every demo. Trying to stay at the frontier because I was terrified of falling behind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Entire weeks spent configuring a new tool, only to see it obsolete the following week. Carefully built workflows, outdated within three months after a model update. Siddhant calls this &lt;strong&gt;Knowledge Decay&lt;/strong&gt;, the depreciation of accumulated knowledge. I had missed that one, but it is real.&lt;/p&gt;
&lt;p&gt;This is not simply fatigue. It is a &lt;strong&gt;regular destruction of our cognitive investment&lt;/strong&gt;, with no guarantee of return. And this destruction is systemic, not individual.&lt;/p&gt;
&lt;h3&gt;The “come on, let me try one more thing” trap&lt;/h3&gt;
&lt;p&gt;My article focused on organizational dysfunctions. Siddhant zooms in to the level of the individual daily work gesture.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You started with a clear goal. Thirty minutes later you’re debugging your prompt instead of debugging your code. You’re optimizing your instructions to a language model instead of solving the actual problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He calls this the &lt;strong&gt;Prompt Spiral&lt;/strong&gt;, and I would be dishonest if I said I had never felt it. You start with a clear objective. The first response is 70% right. From there, you refine the prompt. The second iteration is 75% right, but it broke something the first one had gotten correct.&lt;/p&gt;
&lt;p&gt;And so on. Forty-five minutes later, you have lost sight of the initial goal, you are in a vicious cycle, and you have not moved an inch.&lt;/p&gt;
&lt;p&gt;What I find remarkable in his text is that Siddhant does not stop at the diagnosis. He proposes concrete rules, drawn from his own experience: three attempts maximum, then write it yourself; sessions capped at thirty minutes. The first hour of the morning without AI, to “warm up” his own thinking before delegating anything at all.&lt;/p&gt;
&lt;p&gt;There is something sadly fascinating in seeing just how necessary these rules have become for good mental hygiene, and how difficult they are to stick to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My article was addressed to managers and organizations. His is addressed to practitioners, directly.&lt;/strong&gt; They are not at the same altitude. Both are necessary. Both are unsettling.&lt;/p&gt;
&lt;p&gt;In short, I invite you to read “&lt;a href=&quot;https://siddhantkhare.com/writing/ai-fatigue-is-real&quot;&gt;AI fatigue is real and nobody talks about it&lt;/a&gt;” because it completes everything I had left aside: the anxiety of the determinist facing the probabilistic, the exhaustion of permanent monitoring, the micro-decisions that accumulate until burnout.&lt;/p&gt;
&lt;p&gt;And if you have lived what he describes, know that you are not alone. And that it is not a question of competence or discipline. What we are living through, what the market is imposing today, is hard, and will have significant consequences on our mental health, our ability to do good work, and our enjoyment of this profession. And this will hold true even if the bubble bursts.&lt;/p&gt;
&lt;h2&gt;Blame It on the Boogie 🎶&lt;/h2&gt;
&lt;p&gt;Between two articles questioning the &lt;strong&gt;how&lt;/strong&gt; (how to better use these tools, how to reorganize processes, how to preserve one’s mental health), I also recently read another text that poses a different question: the question of &lt;strong&gt;why&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;My article and Siddhant’s analyze &lt;strong&gt;effects&lt;/strong&gt;: overload, erosion of skills, individual and collective fatigue. We describe what is happening on the deck of the ship. “&lt;a href=&quot;https://www.stvn.sh/writing/programming-still-sucks-fqffhyp&quot; hreflang=&quot;en&quot;&gt;Programming Still Sucks&lt;/a&gt;”, by Steven Langbroek, describes how the ship was built, who decided to throw the manual overboard, and who signed the list of eliminated positions while convincing themselves that “the juniors will adapt” (spoiler: no).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI didn’t take our jobs. Greed did. Same greed that moved factories to Bangladesh and keeps slaves in cobalt mines in the Congo, wearing a new mask.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The text is more literary, more political, deliberately angrier (I love it all the more for it). It is an excellent illustration of how short-term productivity obsession destroys things without seeing it, without even knowing what it is destroying. Where my article asks “how to delegate better?” and Siddhant’s asks “how to survive this pace?”, this third text asks: &lt;strong&gt;who decided this was acceptable, and why?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The picture is fairly complete, and unfortunately fairly dark.&lt;/p&gt;
&lt;h2&gt;And unfortunately, we are right&lt;/h2&gt;
&lt;p&gt;To drive the nail in further, one last piece of reading: the INSEE&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; economic outlook note for March 2026, titled “&lt;a href=&quot;https://www.insee.fr/fr/statistiques/8907419?sommaire=8907467&quot;&gt;Éclairage – Avec l’essor de l’intelligence artificielle générative, l’investissement numérique tire davantage la croissance aux États-Unis qu’en France, tandis que l’emploi recule dans les activités informatiques des deux côtés de l’Atlantique&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;One can read in particular:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In particular, sector-level indicators suggest an employment reversal over the past two years in the most exposed segments, notably in computer programming activities, and for which value added is trending upward, in both the United States and France. Furthermore, in both countries, employment adjustment in this sector would be concentrated among young entrants.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“Employment reversal”, in case you are not sure what that means, is an elegant way of saying that jobs are being destroyed. This is made explicit further on in a chart caption:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Employment in the information technology and information services sector fell by 3.0% between Q4 2023 and Q4 2025. The contribution of 15-29 year-olds (excluding apprentices) was -3.8 percentage points, compared to +1.4 points for 30-54 year-olds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Because in this difficult context, older workers, who are able to draw on their experience to achieve the necessary emotional distance we are all talking about, are better positioned to cope with the situation (or at least, to cope with it the least badly). Young people are more vulnerable. They have not yet had time to build a career, develop transferable skills, or forge the experience that would make them more resilient in the face of this kind of shock.&lt;/p&gt;
&lt;p&gt;In short, the numbers are there, and they are not good. We are right to be worried. We are right to feel tired. We are right to wonder how we are going to continue doing good work under these conditions.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;INSEE (&lt;span lang=&quot;fr&quot;&gt;Institut national de la statistique et des études économiques&lt;/span&gt;) is France’s official national statistics agency, responsible for producing and publishing economic, social, and demographic data. Its economic outlook notes are considered authoritative references in French public policy debates. When INSEE says employment is falling, it is not an op-ed; it is the scoreboard. &lt;a href=&quot;https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          &lt;hr&gt;
          &lt;div&gt;
              &lt;p&gt;
                  You subscribed to my posts :
              &lt;/p&gt;
              &lt;ul&gt;
                  &lt;li&gt;from the category Web&lt;/li&gt;
                  &lt;li&gt;written in English.&lt;/li&gt;
              &lt;/ul&gt;
              
          &lt;/div&gt;</description>
<pubDate>18 May 2026, 3:00 pm</pubDate>
<content:encoded><![CDATA[<p>Last February, I wrote about <a href="https://boris.schapira.dev/notes/2026-02-productivity-quality/">productivity and quality</a>: poorly thought-out delegation, the cognitive load on validators, the silent erosion of collective skills. A text built from an organizational perspective, drawing on my conversations with colleagues who ultimately hold roles peripheral to the code itself.</p>
<h2>What I had missed</h2>
<p>One of them shared with me an article by Siddhant Khare, who lived that same reality up close. He builds AI agent infrastructure, meaning the tools other engineers use to run AI in production. And he still ended up hitting a wall. Not a performance wall. A human one.</p>
<p>His article, “<a href="https://siddhantkhare.com/writing/ai-fatigue-is-real">AI fatigue is real and nobody talks about it</a>”, haunts me, as it significantly completes what I had written.</p>
 <div class="inline-note"><p><strong>NOTE</strong> There is no need to come tell me that AI is an ecological and economic waste; I am aware. What interests me is the fact that these tools are, today, a reality, and that this reality has human and organizational consequences.</p>
<p>We can talk about how difficult it is to do without this technology in a competitive landscape where it is used massively, while also knowing it is not profitable in the long run. But that is not the subject of this specific post.</p>
</div>
<h3>The clash of probabilistic systems</h3>
<p>My article talked about <strong>cognitive overload from validation</strong>. What I had not named is a very specific source of that overload: the fact of collaborating with a fundamentally unpredictable system, while our brains are wired for determinism.</p>
<p>Siddhant puts it with a precision I had not achieved:</p>
<blockquote>
<p>you are collaborating with a probabilistic system, and your brain is wired for deterministic ones. That mismatch is a constant, low-grade source of stress.</p>
</blockquote>
<p>The fact that the model decided to go a different direction today, that the same prompt produces different results from one day to the next, with no accessible explanation, no readable log, is terrible. For someone whose work depends on the ability to reason about deterministic systems, this is a source of quiet but constant anxiety.</p>
<p>I know, of course, that this is not inevitable. There are ways to reduce LLM variability, to make them more predictable. But it is a long-haul effort, and it is easy to underestimate just how much this unpredictability is a source of stress for teams.</p>
<h3>The treadmill of new tools</h3>
<p>All the more so because the pressure is constant to stay “up to date” in a team dynamic that reinvents itself every week, every day.</p>
<blockquote>
<p>I fell into this trap hard. I was spending weekends evaluating new tools. Reading every changelog. Watching every demo. Trying to stay at the frontier because I was terrified of falling behind.</p>
</blockquote>
<p>Entire weeks spent configuring a new tool, only to see it obsolete the following week. Carefully built workflows, outdated within three months after a model update. Siddhant calls this <strong>Knowledge Decay</strong>, the depreciation of accumulated knowledge. I had missed that one, but it is real.</p>
<p>This is not simply fatigue. It is a <strong>regular destruction of our cognitive investment</strong>, with no guarantee of return. And this destruction is systemic, not individual.</p>
<h3>The “come on, let me try one more thing” trap</h3>
<p>My article focused on organizational dysfunctions. Siddhant zooms in to the level of the individual daily work gesture.</p>
<blockquote>
<p>You started with a clear goal. Thirty minutes later you’re debugging your prompt instead of debugging your code. You’re optimizing your instructions to a language model instead of solving the actual problem.</p>
</blockquote>
<p>He calls this the <strong>Prompt Spiral</strong>, and I would be dishonest if I said I had never felt it. You start with a clear objective. The first response is 70% right. From there, you refine the prompt. The second iteration is 75% right, but it broke something the first one had gotten correct.</p>
<p>And so on. Forty-five minutes later, you have lost sight of the initial goal, you are in a vicious cycle, and you have not moved an inch.</p>
<p>What I find remarkable in his text is that Siddhant does not stop at the diagnosis. He proposes concrete rules, drawn from his own experience: three attempts maximum, then write it yourself; sessions capped at thirty minutes. The first hour of the morning without AI, to “warm up” his own thinking before delegating anything at all.</p>
<p>There is something sadly fascinating in seeing just how necessary these rules have become for good mental hygiene, and how difficult they are to stick to.</p>
<p><strong>My article was addressed to managers and organizations. His is addressed to practitioners, directly.</strong> They are not at the same altitude. Both are necessary. Both are unsettling.</p>
<p>In short, I invite you to read “<a href="https://siddhantkhare.com/writing/ai-fatigue-is-real">AI fatigue is real and nobody talks about it</a>” because it completes everything I had left aside: the anxiety of the determinist facing the probabilistic, the exhaustion of permanent monitoring, the micro-decisions that accumulate until burnout.</p>
<p>And if you have lived what he describes, know that you are not alone. And that it is not a question of competence or discipline. What we are living through, what the market is imposing today, is hard, and will have significant consequences on our mental health, our ability to do good work, and our enjoyment of this profession. And this will hold true even if the bubble bursts.</p>
<h2>Blame It on the Boogie 🎶</h2>
<p>Between two articles questioning the <strong>how</strong> (how to better use these tools, how to reorganize processes, how to preserve one’s mental health), I also recently read another text that poses a different question: the question of <strong>why</strong>.</p>
<p>My article and Siddhant’s analyze <strong>effects</strong>: overload, erosion of skills, individual and collective fatigue. We describe what is happening on the deck of the ship. “<a href="https://www.stvn.sh/writing/programming-still-sucks-fqffhyp" hreflang="en">Programming Still Sucks</a>”, by Steven Langbroek, describes how the ship was built, who decided to throw the manual overboard, and who signed the list of eliminated positions while convincing themselves that “the juniors will adapt” (spoiler: no).</p>
<blockquote>
<p>AI didn’t take our jobs. Greed did. Same greed that moved factories to Bangladesh and keeps slaves in cobalt mines in the Congo, wearing a new mask.</p>
</blockquote>
<p>The text is more literary, more political, deliberately angrier (I love it all the more for it). It is an excellent illustration of how short-term productivity obsession destroys things without seeing it, without even knowing what it is destroying. Where my article asks “how to delegate better?” and Siddhant’s asks “how to survive this pace?”, this third text asks: <strong>who decided this was acceptable, and why?</strong></p>
<p>The picture is fairly complete, and unfortunately fairly dark.</p>
<h2>And unfortunately, we are right</h2>
<p>To drive the nail in further, one last piece of reading: the INSEE<sup class="footnote-ref"><a href="https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/#fn1">1</a></sup> economic outlook note for March 2026, titled “<a href="https://www.insee.fr/fr/statistiques/8907419?sommaire=8907467">Éclairage – Avec l’essor de l’intelligence artificielle générative, l’investissement numérique tire davantage la croissance aux États-Unis qu’en France, tandis que l’emploi recule dans les activités informatiques des deux côtés de l’Atlantique</a>”.</p>
<p>One can read in particular:</p>
<blockquote>
<p>In particular, sector-level indicators suggest an employment reversal over the past two years in the most exposed segments, notably in computer programming activities, and for which value added is trending upward, in both the United States and France. Furthermore, in both countries, employment adjustment in this sector would be concentrated among young entrants.</p>
</blockquote>
<p>“Employment reversal”, in case you are not sure what that means, is an elegant way of saying that jobs are being destroyed. This is made explicit further on in a chart caption:</p>
<blockquote>
<p>Employment in the information technology and information services sector fell by 3.0% between Q4 2023 and Q4 2025. The contribution of 15-29 year-olds (excluding apprentices) was -3.8 percentage points, compared to +1.4 points for 30-54 year-olds.</p>
</blockquote>
<p>Because in this difficult context, older workers, who are able to draw on their experience to achieve the necessary emotional distance we are all talking about, are better positioned to cope with the situation (or at least, to cope with it the least badly). Young people are more vulnerable. They have not yet had time to build a career, develop transferable skills, or forge the experience that would make them more resilient in the face of this kind of shock.</p>
<p>In short, the numbers are there, and they are not good. We are right to be worried. We are right to feel tired. We are right to wonder how we are going to continue doing good work under these conditions.</p>
<section class="footnotes">
<ol>
<li>
<p>INSEE (<span lang="fr">Institut national de la statistique et des études économiques</span>) is France’s official national statistics agency, responsible for producing and publishing economic, social, and demographic data. Its economic outlook notes are considered authoritative references in French public policy debates. When INSEE says employment is falling, it is not an op-ed; it is the scoreboard. <a href="https://boris.schapira.dev/notes/2026-05-readings-ai-fatigue/#fnref1" class="footnote-backref">↩</a></p>
</li>
</ol>
</section>

          <hr>
          <div>
              <p>
                  You subscribed to my posts :
              </p>
              <ul>
                  <li>from the category Web</li>
                  <li>written in English.</li>
              </ul>
              
          </div>]]></content:encoded>
</item>

<item>
<title>Losing Focus</title>
<link>https://timkadlec.com/remembers/2026/05/losing-focus/</link>
<guid isPermaLink="true">https://timkadlec.com/remembers/2026/05/losing-focus/</guid>
<description></description>
<pubDate>18 May 2026, 1:39 pm</pubDate>
<content:encoded><![CDATA[]]></content:encoded>
</item>

<item>
<title>2ality blog: temporarily offline</title>
<link>https://timkadlec.com/saved/2026/05/2ality-blog-temporarily-offline/</link>
<guid isPermaLink="true">https://timkadlec.com/saved/2026/05/2ality-blog-temporarily-offline/</guid>
<description></description>
<pubDate>16 May 2026, 5:55 pm</pubDate>
<content:encoded><![CDATA[]]></content:encoded>
</item>

<item>
<title>Meet Your Users Where They Are with Obs.js</title>
<link>https://csswizardry.com/2026/05/meet-your-users-where-they-are-with-obs-js/</link>
<guid isPermaLink="true">https://csswizardry.com/2026/05/meet-your-users-where-they-are-with-obs-js/</guid>
<description>Obs.js is a tiny inline script that helps you adapt your site to real-world network, battery, CPU, and memory conditions.</description>
<pubDate>12 May 2026, 9:53 am</pubDate>
<content:encoded><![CDATA[Obs.js is a tiny inline script that helps you adapt your site to real-world network, battery, CPU, and memory conditions.]]></content:encoded>
</item>

<item>
<title>An update on the recent JavaScript error tracking outage</title>
<link>https://www.speedcurve.com/blog/may-13-postmortem</link>
<guid isPermaLink="true">https://www.speedcurve.com/blog/may-13-postmortem</guid>
<description>&lt;p&gt;During a deployment at 08:00 pm on 7 May 2026 (UTC), SpeedCurve RUM JavaScript error tracking had an outage that lasted for 5 days, until 08:00 pm on 12 May. The outage caused the complete loss of JavaScript error details recorded by SpeedCurve&apos;s RUM script, lux.js. Total error count was recorded correctly, but the details of those errors were lost.&lt;/p&gt;&lt;p&gt;Unfortunately our automated monitoring did not alert us to this outage. We were only alerted after reports of missing data from SpeedCurve customers. Once the initial report was received, we were able to identify and fix the issue within a few minutes. We then performed an investigation to discover the root cause, and put together a timeline of events.&lt;/p&gt;
&lt;h2&gt;The impact on your data&lt;/h2&gt;
&lt;p&gt;JavaScript error tracking is done in two parts: counting the number of errors on a page, and sending the full details of a small sample of those errors (up to 5 per page). The first part of this tracking was not affected, so the total number of errors shown in your dashboards remains correct*. The second part is what was affected: error message, filename, line, and column were all lost during the outage.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*One exception is when filtering to a specific error message.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;blog-img&quot; src=&quot;https://blog-img.speedcurve.com/img/567/total-error-count.png?auto=format,compress&amp;amp;fit=max&amp;amp;w=2000&quot; alt=&quot;Screenshot of a chart showing JavaScript error count over time, with no change in count during the outage&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This chart shows JavaScript error count during the outage period, with the total count unaffected by the outage.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;The timeline&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;On 4 May we deployed and tested an update to the staging environment of our JS error tracking pipeline. This update included a new endpoint for receiving JS error beacons, and a new version of our RUM script (lux.js v4.5) that sends JS error beacons to the new endpoint.&lt;/li&gt;
&lt;li&gt;On 7 May at around 08:00 pm (UTC) we deployed lux.js v4.5 to our production environment, but did not deploy the new endpoint. This meant that any JS error details generated by lux.js v4.5 were sent to an endpoint that did not exist, resulting in a 404 response code and the error details being lost.&lt;/li&gt;
&lt;li&gt;On 7 May at 10:00 pm the majority of RUM traffic was using the new version of lux.js. Around this time, our monitoring alerted us that the number of JS errors in our ingest pipeline had dropped to zero. We spot-checked this alert against SpeedCurve&apos;s internal &quot;dogfooding&quot; account and determined it to be a monitoring issue.&lt;/li&gt;
&lt;li&gt;The monitoring system was patched and the number of JS errors returned to a non-zero value. This value was significantly lower than before however this was falsely attributed to a monitoring system quirk.&lt;/li&gt;
&lt;li&gt;On 11 May at 10:00 am, SpeedCurve received a report that JS error details were missing. This report was not forwarded to the engineering team until 07:00 pm on 12 May, at which point is was triaged as a P0 (urgent priority) incident.&lt;/li&gt;
&lt;li&gt;On 12 May at 07:00 pm engineering identified the root cause as the endpoint not being deployed, causing JS error details to be dropped. The endpoint was deployed within several minutes.&lt;/li&gt;
&lt;li&gt;At 7:20 pm the issue was confirmed as fixed.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;What went wrong&lt;/h2&gt;
&lt;p&gt;Ultimately the root cause of this outage was human error, however there were gaps in our processes and monitoring systems that allowed it to go unnoticed for so long. The release process for the affected systems is nontrivial and entirely manual. In the past we have been able to rely on our monitoring to alert us of issues post-release. In this case our monitoring coverage was not sufficient.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;blog-img&quot; src=&quot;https://blog-img.speedcurve.com/img/567/ingestion-error-monitoring.png?auto=format,compress&amp;amp;fit=max&amp;amp;w=2000&quot; alt=&quot;Screenshot of SpeedCurve&apos;s error monitoring chart showing no increase in errors&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This chart shows the number of errors from our RUM beacon endpoints. This metric did not increase during the outage, preventing any alerts from being issued.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The relevant part of our monitoring is a metric that tracks the number of errors in our RUM beacon endpoints. This metric is pushed to our monitoring service by Fastly, and for reasons unclear, this metric did not increase during the outage. This is shown in the chart above, which exhibited normal error rates during the entirety of the outage.&lt;/p&gt;
&lt;p&gt;The alert that was triggered in event (3) of the timeline above was a strong signal that something was wrong. However because we used our internal dogfooding account for spot-checking, we were led to the half-baked conclusion that this was a monitoring issue and not a genuine data issue. While there &lt;em&gt;was&lt;/em&gt; a monitoring issue, we mistakenly believed the issue was solved once we saw our internal data flow into the monitoring system. In reality, this data was coming from our staging environment only. This obscured the fact that no production data was flowing into the system.&lt;/p&gt;
&lt;p&gt;And finally, there was a 35 hour delay between the issue first being reported and the report making its way to our engineering team. This delay did not directly contribute to the issue but did unnecessarily extend the outage.&lt;/p&gt;
&lt;h2&gt;Going forward&lt;/h2&gt;
&lt;p&gt;We&apos;re making some changes to avoid issues like this in the future: we&apos;ll expand our monitoring to cover many more types of potential issues, we&apos;ll improve our spot-checking so that both staging and production data is validated, and we&apos;ll onboard more engineers to support these systems.&lt;/p&gt;
&lt;p&gt;We&apos;d like to thank the users who reported this issue to &lt;strong&gt;support@speedcurve.com&lt;/strong&gt;, and we&apos;re grateful for all of your feedback and patience.&lt;/p&gt;</description>
<pubDate>11 May 2026, 5:00 am</pubDate>
<content:encoded><![CDATA[<p>During a deployment at 08:00 pm on 7 May 2026 (UTC), SpeedCurve RUM JavaScript error tracking had an outage that lasted for 5 days, until 08:00 pm on 12 May. The outage caused the complete loss of JavaScript error details recorded by SpeedCurve's RUM script, lux.js. Total error count was recorded correctly, but the details of those errors were lost.</p><p>Unfortunately our automated monitoring did not alert us to this outage. We were only alerted after reports of missing data from SpeedCurve customers. Once the initial report was received, we were able to identify and fix the issue within a few minutes. We then performed an investigation to discover the root cause, and put together a timeline of events.</p>
<h2>The impact on your data</h2>
<p>JavaScript error tracking is done in two parts: counting the number of errors on a page, and sending the full details of a small sample of those errors (up to 5 per page). The first part of this tracking was not affected, so the total number of errors shown in your dashboards remains correct*. The second part is what was affected: error message, filename, line, and column were all lost during the outage.</p>
<p><em>*One exception is when filtering to a specific error message.</em></p>
<p><img class="blog-img" src="https://blog-img.speedcurve.com/img/567/total-error-count.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Screenshot of a chart showing JavaScript error count over time, with no change in count during the outage"></p>
<p><em>This chart shows JavaScript error count during the outage period, with the total count unaffected by the outage.</em></p>
<h2>The timeline</h2>
<ol>
<li>On 4 May we deployed and tested an update to the staging environment of our JS error tracking pipeline. This update included a new endpoint for receiving JS error beacons, and a new version of our RUM script (lux.js v4.5) that sends JS error beacons to the new endpoint.</li>
<li>On 7 May at around 08:00 pm (UTC) we deployed lux.js v4.5 to our production environment, but did not deploy the new endpoint. This meant that any JS error details generated by lux.js v4.5 were sent to an endpoint that did not exist, resulting in a 404 response code and the error details being lost.</li>
<li>On 7 May at 10:00 pm the majority of RUM traffic was using the new version of lux.js. Around this time, our monitoring alerted us that the number of JS errors in our ingest pipeline had dropped to zero. We spot-checked this alert against SpeedCurve's internal "dogfooding" account and determined it to be a monitoring issue.</li>
<li>The monitoring system was patched and the number of JS errors returned to a non-zero value. This value was significantly lower than before however this was falsely attributed to a monitoring system quirk.</li>
<li>On 11 May at 10:00 am, SpeedCurve received a report that JS error details were missing. This report was not forwarded to the engineering team until 07:00 pm on 12 May, at which point is was triaged as a P0 (urgent priority) incident.</li>
<li>On 12 May at 07:00 pm engineering identified the root cause as the endpoint not being deployed, causing JS error details to be dropped. The endpoint was deployed within several minutes.</li>
<li>At 7:20 pm the issue was confirmed as fixed.</li>
</ol>
<h2>What went wrong</h2>
<p>Ultimately the root cause of this outage was human error, however there were gaps in our processes and monitoring systems that allowed it to go unnoticed for so long. The release process for the affected systems is nontrivial and entirely manual. In the past we have been able to rely on our monitoring to alert us of issues post-release. In this case our monitoring coverage was not sufficient.</p>
<p><img class="blog-img" src="https://blog-img.speedcurve.com/img/567/ingestion-error-monitoring.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Screenshot of SpeedCurve's error monitoring chart showing no increase in errors"></p>
<p><em>This chart shows the number of errors from our RUM beacon endpoints. This metric did not increase during the outage, preventing any alerts from being issued.</em></p>
<p>The relevant part of our monitoring is a metric that tracks the number of errors in our RUM beacon endpoints. This metric is pushed to our monitoring service by Fastly, and for reasons unclear, this metric did not increase during the outage. This is shown in the chart above, which exhibited normal error rates during the entirety of the outage.</p>
<p>The alert that was triggered in event (3) of the timeline above was a strong signal that something was wrong. However because we used our internal dogfooding account for spot-checking, we were led to the half-baked conclusion that this was a monitoring issue and not a genuine data issue. While there <em>was</em> a monitoring issue, we mistakenly believed the issue was solved once we saw our internal data flow into the monitoring system. In reality, this data was coming from our staging environment only. This obscured the fact that no production data was flowing into the system.</p>
<p>And finally, there was a 35 hour delay between the issue first being reported and the report making its way to our engineering team. This delay did not directly contribute to the issue but did unnecessarily extend the outage.</p>
<h2>Going forward</h2>
<p>We're making some changes to avoid issues like this in the future: we'll expand our monitoring to cover many more types of potential issues, we'll improve our spot-checking so that both staging and production data is validated, and we'll onboard more engineers to support these systems.</p>
<p>We'd like to thank the users who reported this issue to <strong>support@speedcurve.com</strong>, and we're grateful for all of your feedback and patience.</p>]]></content:encoded>
</item>

<item>
<title>Google Lighthouse Has A New Agentic Browsing Category</title>
<link>https://www.debugbear.com/blog/lighthouse-agentic-browsing</link>
<guid isPermaLink="true">https://www.debugbear.com/blog/lighthouse-agentic-browsing</guid>
<description>Lighthouse 13.3 introduces a new Agentic Browsing category that audits how well your website works with AI agents.</description>
<pubDate>9 May 2026, 5:00 pm</pubDate>
<content:encoded><![CDATA[<p>Lighthouse 13.3 came out this week, and includes a new category called "Agentic Browsing". Let's take a look at the new audits included in this category.</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">What is the agentic browsing category?<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#what-is-the-agentic-browsing-category" class="hash-link" aria-label="Direct link to What is the agentic browsing category?" title="Direct link to What is the agentic browsing category?">​</a></h2>
<p>While <a href="https://www.debugbear.com/blog/lighthouse-page-speed">Lighthouse</a> has always primarily been a performance testing tool, it also includes other website quality checks looking at website accessibility, SEO, and other best practices.</p>
<p>The new category runs several checks to see how AI agents can interact with your website.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/30bdf63e19cabd2bc859e545b6dadab8.png" alt="Lighthouse scores with new Agentic Browsing category" data-abc="true" class="img_CujE"></p>
<p>The agentic browsing category in the Lighthouse report runs several audits checking:</p>
<ul>
<li>That the website accessibility tree is well-formed</li>
<li>Whether content shifts after rendering</li>
<li>Correct WebMCP implementation</li>
<li>llms.txt guidelines</li>
</ul>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/c40abf48327e999c91a081bcb392d154.png" alt="Agentic browsing report category" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Two important caveats<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#two-important-caveats" class="hash-link" aria-label="Direct link to Two important caveats" title="Direct link to Two important caveats">​</a></h3>
<p>The agentic browsing category is currently still marked as "under development". There's still a lot of uncertainty about what websites need to focus on in order for AI agents to use them effectively.</p>
<p>Also, you won't fail this category just because you haven't integrated new AI features. <code>example.com</code> gets a green 2/2 score!</p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">How to check your agentic browsing score<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#how-to-check-your-agentic-browsing-score" class="hash-link" aria-label="Direct link to How to check your agentic browsing score" title="Direct link to How to check your agentic browsing score">​</a></h2>
<p>You can either test your website using an online tool or run Lighthouse on your own device.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Online testing tools<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#online-testing-tools" class="hash-link" aria-label="Direct link to Online testing tools" title="Direct link to Online testing tools">​</a></h3>
<p>To check your own website you can use the free <a href="https://www.debugbear.com/test/website-grader" target="_blank" rel="noopener noreferrer">DebugBear website quality checker</a>:</p>
<ol>
<li>Enter your website URL and run a test</li>
<li>Open the <strong>Lighthouse</strong> tab in the sidebar</li>
</ol>
<p>PageSpeed Insights and Chrome DevTools still use an older version of Lighthouse, but this should change in the coming months.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/6a40d6287877ab9f8d80d85101aef6d2.png" alt="Finding the agentic browsing score in the DebugBear Lighthouse tab" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Locally on your own computer<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#locally-on-your-own-computer" class="hash-link" aria-label="Direct link to Locally on your own computer" title="Direct link to Locally on your own computer">​</a></h3>
<p>To test your website locally from your own computer you can use the Lighthouse command line tool:</p>
<ol>
<li>Install the latest version of Lighthouse: <code>npm install -g lighthouse@latest</code></li>
<li>Run a test, e.g. <code>lighthouse --view https://web.dev/</code></li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Building agent-friendly websites<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#building-agent-friendly-websites" class="hash-link" aria-label="Direct link to Building agent-friendly websites" title="Direct link to Building agent-friendly websites">​</a></h2>
<p>Google recently published a guide on how to <a href="https://web.dev/articles/ai-agent-site-ux" target="_blank" rel="noopener noreferrer">build agent-friendly websites</a> and there is some overlap between the new Lighthouse checks and the recommendations in the article.</p>
<p>One key take-away from the guide is that AI agents interact with website content in different formats:</p>
<ol>
<li>Screenshots</li>
<li>HTML code</li>
<li>The accessibility tree</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_FNw8">What checks does the agentic browsing category actually run?<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#what-checks-does-the-agentic-browsing-category-actually-run" class="hash-link" aria-label="Direct link to What checks does the agentic browsing category actually run?" title="Direct link to What checks does the agentic browsing category actually run?">​</a></h2>
<p>What AI agent issues can Lighthouse actually detect? The new category combines existing report data with several new audits.</p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Accessibility tree is not well-formed<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#accessibility-tree-is-not-well-formed" class="hash-link" aria-label="Direct link to Accessibility tree is not well-formed" title="Direct link to Accessibility tree is not well-formed">​</a></h3>
<p>The accessibility tree is a simplified representation of the page structure that is used by accessibility tools and AI agents. <a href="https://www.debugbear.com/docs/agentic-browsing/accessibility-tree-is-not-well-formed">This audit</a> data is based on the existing accessibility checks run by Lighthouse.</p>
<p>AI agents can process the accessibility tree more efficiently compared to the full HTML code or a website screenshot.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/af4052b43534e38c85497a448ca5f882.png" alt="Invalid accessibility tree" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">WebMCP validation<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#webmcp-validation" class="hash-link" aria-label="Direct link to WebMCP validation" title="Direct link to WebMCP validation">​</a></h3>
<p><a href="https://developer.chrome.com/blog/webmcp-epp" target="_blank" rel="noopener noreferrer">WebMCP</a> is an API that lets websites provide specific commands that agents can use to interact with them. Unlike general MCP servers, WebMCP
is built for front-end interactions in the context of the visitor's browser session.</p>
<p>There's a declarative version of the API based on annotating HTML forms on the page. The WebMCP audit checks whether forms are annotated and if the annotations match the expected schema.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/2f229e29192a893b9e0977d934dbc208.png" alt="WebMCP form annotation validation result" data-abc="true" class="img_CujE"></p>
<p>Lighthouse also surfaces all WebMCP tools that have been registered on the page, whether they were added through the declarative API or programmatically with <code>navigator.modelContext.registerTool</code>.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/ed6bcf33241d4602d7afc6931683ef8b.png" alt="WebMCP tools in the WebMCP maze demo game" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">llms.txt does not follow recommendations<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#llmstxt-does-not-follow-recommendations" class="hash-link" aria-label="Direct link to llms.txt does not follow recommendations" title="Direct link to llms.txt does not follow recommendations">​</a></h3>
<p><a href="https://www.debugbear.com/docs/agentic-browsing/llms-txt-does-not-follow-recommendations">llms.txt files</a> are a proposed way for websites to provide information to AI agents and crawlers. However, it is <a href="https://ahrefs.com/blog/what-is-llms-txt/" target="_blank" rel="noopener noreferrer">not widely used by AI tools currently</a>.</p>
<p>The new Lighthouse audit checks if the website provides an llms.txt file. If it does, it checks if the file is missing an H1 header, is too short, or doesn't contain any links.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/803a030070e772ce50da1f129cf5d787.png" alt="llms.txt validation result in Lighthouse" data-abc="true" class="img_CujE"></p>
<h3 class="anchor anchorWithStickyNavbar_FNw8">Detecting layout shifts<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#detecting-layout-shifts" class="hash-link" aria-label="Direct link to Detecting layout shifts" title="Direct link to Detecting layout shifts">​</a></h3>
<p>It's hard to use a website if content shifts around unexpectedly. In 2020, Google introduced the <a href="https://www.debugbear.com/docs/metrics/cumulative-layout-shift">Cumulative Layout Shift (CLS) metric</a> to measure and report these shifts.</p>
<p>Why does this matter to AI agents? Google's guide <a href="https://web.dev/articles/ai-agent-site-ux#build_agent-friendly_websites_2" target="_blank" rel="noopener noreferrer">explains</a>:</p>
<blockquote>
<p>Ensure stable layout. Agents that take screenshots will likely be confused if your website layout is constantly shifting</p>
</blockquote>
<p>Ultimately this audit just provides existing CLS score reporting in a different category. An AI agent may interact with your website more quickly than a human visitor, so shifts that occur as content is loading may be more disruptive to an agent.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/cdb8b18bd4660e70d69d1da35763fc22.png" alt="CLS score report" data-abc="true" class="img_CujE"></p>
<h2 class="anchor anchorWithStickyNavbar_FNw8">Test your website and keep it optimized<a href="https://www.debugbear.com/blog/lighthouse-agentic-browsing#test-your-website-and-keep-it-optimized" class="hash-link" aria-label="Direct link to Test your website and keep it optimized" title="Direct link to Test your website and keep it optimized">​</a></h2>
<p>Whether you're optimizing your website for performance, SEO, or AI agents, DebugBear provides in-depth reporting on website quality and visitor experience. Identify key issues and get alerted when there's a regression.</p>
<p><a href="https://www.debugbear.com/signup" target="_blank" rel="noopener noreferrer">Start your free trial today</a>.</p>
<p><img loading="lazy" src="https://www.debugbear.com/dimg/edead1a8a60274c7ebe9527aa99878d1.png" alt="DebugBear audits dashboard" data-abc="true" class="img_CujE"></p>
<!-- -->
<div class="cta_Vy7l"><div class="ctaContainer_dzq8"><div class="ctaImage_MZ5b"><img src="https://www.debugbear.com/dimg/57001785e35454b95f43aa4f3bf6f857.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="https://www.debugbear.com/dimg/b2c0ae7a8dfbc4b18ba827a334c5c1af.png" alt="Illustration of website monitoring" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><div class="ctaContent_VgWi"><h2>Monitor Page Speed &amp; Core Web Vitals</h2><div class="ctaBenefits_OYw7"><h3>DebugBear monitoring includes:</h3><ul><li>In-depth Page Speed Reports</li><li>Automated Recommendations</li><li>Real User Analytics Data</li></ul></div><div><a href="https://www.debugbear.com/signup" class="ctaButton_Uos9 hidden-when-logged-in"><span>Start Free Trial</span></a><a href="https://www.debugbear.com/app" class="ctaButton_Uos9 visible-when-logged-in"><span>Go To App</span></a></div></div></div></div>]]></content:encoded>
</item>

</channel>
</rss>