SpeedCurve Blog https://www.speedcurve.com/blog/ Speed matters. Get the latest on how the areas of design and performance overlap with a focus on creating great user experiences. Performance Hero: Estela Franco https://www.speedcurve.com/blog/web-performance-hero-estela-franco <p>Continuing our series of Performance Heroes, this month we celebrate&nbsp;<strong>Estela Franco</strong>!</p> <p>Estela is a passionate web performance and technical SEO specialist with more than ten years of contributing to our community. She loves to talk and share about web performance optimization, technical SEO, JavaScript, and Jamstack whenever she can.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/486/perf-hero-estela-franco-main1.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p><p>By day, you can find Estela working as a web performance specialist for Schneider Electric in Barcelona, Spain. Outside of work, her contributions as a Google Developer Expert in Web Technologies, a Storyblok Ambassador, co-organizer of the <a href="https://www.meetup.com/barcelona-web-performance/">Barcelona Web Performance Meetup</a>, and co-founder of the <a href="https://www.mujeresenseo.es/">Mujeres en SEO</a> community have made a huge impact on developers and web performance aficionados around the globe.</p> <p>Estela has the winning combination of a web development background coupled with a background in business administration. She started on the marketing side, discovering the fundamentals of SEO and digging deeper into the code to learn how websites work and how to optimize for both robots and humans. This led her to specialize in technical SEO. With the announcement of the Core Web Vitals back in 2020, Estela made the decision to focus on web performance.</p> <p>In&nbsp;<a href="https://youtu.be/ZYX6jXGdlyg">her talk at Performance.now</a>&nbsp;in November 2023, Estela helped demystify optimizing for Largest Contentful Paint (LCP) with a focus on LCP subparts. Her data-backed approach was refreshing, practical, and very useful. (We certainly took note!)</p> <p>Here are a few ways you can find Estela and learn more about the great work she does in our community:</p> <ul> <li><a href="https://estelafranco.com">estelafranco.com</a></li> <li><a href="https://www.linkedin.com/in/estelafranco/">LinkedIn</a></li> <li><a href="https://toot.cafe/@guaca">Mastodon</a></li> <li><a href="https://twitter.com/guaca">Twitter</a></li> </ul> <p><span style="color: #1f1f1f;">Please join us in celebrating Estela Franco, a true Performance Hero!</span></p> <p><em>Do you have someone you'd like to recognize as a Performance Hero?&nbsp;<a href="mailto:support@speedcurve.com">Let us know!</a></em></p> Tue, 21 May 2024 00:00:00 +1200 NEW: RUM attribution and subparts for Interaction to Next Paint! https://www.speedcurve.com/blog/rum-attribution-subparts-interaction-to-next-paint <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/inp_heatmap.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Heatmap table showing INP selector performance sorted by page views" /></p> <p>Our newest release continues our theme of making your RUM data even more actionable. In addition to&nbsp;<a href="https://www.speedcurve.com/blog/bfcache-prerendering/">advanced settings, navigation types, and page attributes</a>, we've just released more diagnostic detail for the latest flavor in Core Web Vitals: Interaction to Next Paint (INP).</p> <p>This post covers:</p> <ul> <li>Element attribution for INP&nbsp;</li> <li>A breakdown of where time is spent within INP, leveraging subparts</li> <li>How to use this information to find and fix INP issues</li> <li>A look ahead at RUM diagnostics at SpeedCurve</li> </ul><h2>How quickly does my site respond to user input?</h2> <p>In short, Interaction to Next Paint measures the responsiveness of your pages. (If you want to dive deeper, check out our <a href="https://www.speedcurve.com/blog/check-core-web-vitals-inp/">INP primer</a>.)&nbsp;Delays in responsiveness can lead to user frustration, which affects user engagement, which in turn affects your business objectives, such as revenue. This is why you should care about INP.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/449/inp_v_conversion.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Correlation charts showing the relationship between INP and conversion rates for four different sites." /></p> <p style="text-align: center;"><em>Correlation charts showing <a href="https://www.speedcurve.com/blog/INP-user-experience-correlation/">how INP affects user engagement</a></em></p> <h2>Element attribution</h2> <p>We've been collecting Interaction to Next Paint data for a while. Early on, we found that poor INP was an issue for a lot of folks, <a href="https://www.speedcurve.com/blog/core-web-vitals-inp-mobile/">especially when looking at mobile users</a>.</p> <p>However, as a general time-based metric, INP didn't leave a lot of hints as to the source of the problem. Our early solutions leveraged our <a href="https://www.speedcurve.com/blog/interaction-to-next-paint-find-ix-elements/">IX elements as a proxy for element attribution</a> for INP. <strong>This is still a viable option for all non-Chromium browsers &ndash; which, to be clear, is probably more than half of your traffic!</strong> However, with the element selector directly attributed to INP for Chromium browsers, you are provided <strong>a lot</strong> of missing context.</p> <p>After a bit of research and plenty of consultation with our customers, we've decided to expose the INP element selector. In addition, we've improved our classification for IX elements, making it easier to cross reference attribution with non-Chromium browsers.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/inp_heatmap_element.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="INP heat map highlighting element selector column" /></p> <p style="text-align: center;"><em>INP heatmap available in your RUM Performance dashboard&nbsp;</em></p> <h2>INP subparts</h2> <p>After identifying which interactions are responsible for Interaction to Next Paint issues, you'll want to understand where that time is being spent. This is provided with INP subparts, which are now collected for all SpeedCurve RUM users.</p> <p>There are three main areas to look at when diagnosing INP times:</p> <ul> <li>Input delay</li> <li>Processing time</li> <li>Presentation delay</li> </ul> <p style="text-align: center;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/webdev_inp_illustration.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Diagram showing a user interaction and subpart timings" /></p> <p style="text-align: center;"><em>Source: <a href="https://web.dev/articles/inp#what's-in-an-interaction">INP: What's in an interaction?</a></em></p> <h3>Input delay</h3> <p>As you can see in the illustration above, input delay measures from the time that the user interaction started (when the input was received) until the event handler is able to run.&nbsp;</p> <h3>Processing time</h3> <p>Processing time includes the time it takes event callbacks, initiated by the interaction, to complete.</p> <h3>Presentation Delay</h3> <p>Simply put, presentation delay is the time it takes the frame to be presented after the event callbacks are completed.</p> <h2>Using SpeedCurve RUM to find and fix INP issues</h2> <p>Once you've identified that Interaction to Next Paint is an issue for your page (or pages), you can use the heatmap shown above in your RUM Performance dashboard to identify problematic elements on your page.</p> <h3>Step 1: Make sure you've set the RUM Performance dashboard filter to the 75th percentile</h3> <p>This is especially important if you are chasing INP issues you've identified via CrUX or Google Search Console.</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/485/filterp75.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Dashboard filter showing 75th percentile selected" /></p> <h3>Step 2: Navigate to the INP heatmap</h3> <p>Look for thresholds that have been exceeded, using the color-based Google-defined thresholds for INP:</p> <ul> <li>Green = &lt;200ms</li> <li>Yellow = 200-500ms</li> <li>Red = &gt;500ms</li> </ul> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/inptablep75.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="INP heatmap showing several poor INP element selectors" /></p> <h3>Step 3:&nbsp;Determine where the most time is spent</h3> <p>Below are a few examples to go along with this Web.dev post on <a href="https://web.dev/articles/optimize-inp">Optimizing INP</a> by Jeremy Wagner and Philip Walton.</p> <p><strong>Input delay</strong></p> <p><strong><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/inputdelayheatmap.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Slow INP element showing a large amount of time in input delay" /></strong></p> <p>Factors that affect input delay&nbsp;<em>generally</em>&nbsp;include contending main thread work. Look for Long Tasks that appear to be in conflict with the interaction, fetch handlers, timer functions, or other competing interactions.</p> <p><strong>Processing delay</strong></p> <p><strong><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/processingdelayheatmap.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Slow INP with high processing time" /></strong></p> <p>If time is spent here, look at optimizing event callbacks. As with Long Tasks, breaking things up into smaller chunks of work and deferring work not required for rendering is recommended.</p> <p><strong>Presentation delay</strong></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/presentationdelayheatmap.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Slow INP with long running presentation delay highlighted" /></p> <p>Issues with presentation delay are typically related to the complexity of the DOM. Other improvements to presentation delay may come by reducing the amount of client-side rendering required and deferring rendering of off-screen elements.</p> <p>For a deeper dive into troubleshooting INP issues, see <a href="https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp/">this post by Andy Davies</a> which takes you through using Chrome DevTools to profile interactions.&nbsp;</p> <h2>What about iOS?</h2> <p>The lack of support for web performance metrics in Safari is not a new complaint, but it's a big one. Developers are left to their own devices to troubleshoot performance on iOS devices. While Apple hasn't announced any plans to support any of the Core Web Vitals soon, there is some ability to triangulate on potential issues that might affect the user experience.</p> <p>As an example, the <strong>Interaction Metrics (IX) captured by SpeedCurve are available for Safari</strong>. With the latest upgrades to RUM, we've made it easier to identify those IX elements, which tend to align very closely with the INP element selectors we see for Chromium. This guide to <a href="https://www.speedcurve.com/blog/interaction-to-next-paint-find-ix-elements/">finding and fixing INP issues</a>&nbsp;using IX elements as a proxy still applies!</p> <h2>Looking ahead at RUM diagnostics</h2> <p>Team SpeedCurve is very excited! Here's what we'll be up to over the coming months:</p> <ul> <li>We'll be making a lot of updates and improvements to our data pipeline, which will allow us to continue our mission of making RUM even more actionable.</li> <li>We'll be focused on improving the diagnostic capabilities for the remaining Core Web Vitals, Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS).</li> <li>We'll also be focused on enhanced support for the increasing complexity of measuring the entire lifecycle of the page.</li> </ul> <p>We're excited to roll out this update for Interaction to Next Paint and hope you get a lot of use from it. As always, we value your feedback, so <a href="mailto:support@speedcurve.com">shoot us a note</a> and let us know what you think!<br /><br /></p> <p><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/485/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Wed, 01 May 2024 00:00:00 +1200 Performance Hero: Paul Calvano https://www.speedcurve.com/blog/web-performance-hero-paul-calvano <p>Celebrating performance wins is critical to a healthy, well-supported, high-performing team. This isn't a new idea. In fact, it's something that started in the early days of web performance when <a href="https://larahogan.me/">Lara Hogan</a>, who was an engineering manager at Etsy at the time, discussed the <a href="https://designingforperformance.com/changing-culture/#empowering">practice of empowering people</a>&nbsp;across the organization by celebrating 'performance heroes'.</p> <p>In that spirit, we're reigniting the tradition of spotlighting Performance Heroes from our awesome community. It seems appropriate that we'd start with someone who is currently focused on keeping Etsy's site as fast as possible: <strong>Paul Calvano</strong></p> <p><strong><img class="blog-img" src="https://blog-img.speedcurve.com/img/468/perf-hero-paul-calvano-hero.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></strong>Not only has Paul had a long career dedicated to making the web faster for some of the largest and most popular sites in the world, he is humble, incredibly talented, and one of the kindest people you'll ever meet.</p><p>I've known Paul since I got started in web performance, back in the days of load and performance testing at Keynote Systems (now part of Dynatrace). Paul took me under his wing and quickly showed me the art of breaking websites to prepare them for large influxes of traffic like Black Friday.</p> <p>Paul recently spoke about font performance at the <a href="https://www.meetup.com/web-performance-ny/">NY WebPerf Meetup Group</a>, which he co-chairs. Sharing insights from Etsy and how they use&nbsp;<a href="https://www.speedcurve.com/blog/performance-budgets/">performance budgets</a> continues the spirit of transparency and accountability that started at Etsy so many years ago.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/468/perfbudgetfonts.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Graph showing a performance budget for fonts being exceeded" /><br />Paul's list of accomplishments include (but are certainly not limited to):</p> <ul> <li>Speaking at multiple conferences</li> <li>Co-chair of the <a href="https://www.meetup.com/web-performance-ny/">New York UX Speed and Web Performance Meetup</a></li> <li>Co-maintainer of the&nbsp;<a href="https://httparchive.org/">HTTP Archive</a></li> <li>Multi-year contributor to the Web Performance Almanac</li> <li>Author of <a href="https://paulcalvano.com/tools/">many tools</a> aimed at helping people optimize their websites</li> </ul> <p>Paul is one of the most intelligent and humble people I know. He's given a lot to our community and continues to evangelize performance at every turn. Thank you for everything you've done for our community, Paul. It wouldn't be the same without you!</p> <p><em>Do you have someone you'd like to recognize as a Performance Hero? <a href="mailto:support@speedcurve.com">Let us know!</a></em></p> <p>&nbsp;</p> <p><a href="https://www.speedcurve.com/signup/"><em><img class="blog-img" src="https://blog-img.speedcurve.com/img/468/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></em></a></p> Tue, 23 Apr 2024 00:00:00 +1200 Five ways cookie consent managers hurt web performance (and how to fix them) https://www.speedcurve.com/blog/web-performance-cookie-consent <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/cookie-consent.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <h3>Cookie consent popups and banners are everywhere, and they're silently hurting the speed of your pages. Learn the most common problems &ndash; and their workarounds &ndash; with measuring performance with content manager platforms in place.</h3> <p>I've been spending a lot of time looking at the performance of European sites lately, and have found that the consent management platforms (CMPs) consistently create a false reality for folks when trying to understand performance using synthetic monitoring. Admittedly, this is not a new topic, but I feel it's important enough that it warrants another PSA.&nbsp;</p> <p>In this post, I will cover some of the issues related to measuring performance with CMPs in place and provide some resources for scripting around consent popups in SpeedCurve.</p><h2>What are CMPs and how do they work?</h2> <p>A consent management platform (CMP) is a tool that helps organizations handle user consent for data collection and processing, following privacy rules like <a href="https://gdpr-info.eu/">GDPR</a> or <a href="https://oag.ca.gov/privacy/ccpa">CCPA</a>. On websites, CMPs handle cookie popups. They tell users about cookies and ask for permission before saving them. Unless you've been abstaining from the internet for the past several years, you know consent managers well.</p> <h2>What challenges do CMPs create for performance?</h2> <p>These are some of the most common performance issues caused by content management platforms.</p> <h3>1. Single Point of Failure (SPOF)</h3> <p>As a third party, CMPs can have performance issues of their own that can affect the user experience. It's common to see the consent scripts blocking by design. This can have an impact on most metrics &ndash; such as Start Render and Largest Contentful Paint &ndash; downstream.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/spoffilmstrip.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Two filmstrips compared to show a long delay on the second due to a single point of failure from the CMP." /></p> <p>In this example, the synchronous requests for the CMP timed out, causing an extremely long delay in Start Render due to the SPOF. Consent scripts&nbsp;<a href="https://web.dev/articles/cookie-notice-best-practices#load_cookie_notices_scripts_asynchronously">should be loaded async</a>&nbsp;whenever possible.</p> <h3>2. Identifying the wrong LCP element</h3> <p>Most people assume the LCP element on a page is their main hero or product image, but they're frequently wrong. Oftentimes the text or element in the consent popup is identified as the LCP element. While this may be technically accurate, it's probably not what you want to measure.&nbsp;</p> <p>In this case, LCP is slower after opt-in, when the hero image has taken 2.5s longer to load.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/lcp-compare.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Comparison of two rendered images. The first shows LCP as the text in the consent popup while the 2nd shows a hero image which has taken longer to load" /></p> <h3>3. Consent banners can hurt Cumulative Layout Shift scores</h3> <p>Some sites choose to use a consent banner instead of a popup. As <a href="https://andydavies.me/blog/2021/03/25/bypassing-cookie-consent-banners-in-lighthouse-and-webpagetest/">Andy Davies discovered</a>, this can sometimes cause CLS issues, depending on how the banner is implemented. In this example, the consent banner causes a large layout shift for first-time viewers, pushing the CLS score well beyond recommended <a href="https://support.speedcurve.com/docs/get-started-with-core-web-vitals">Core Web Vitals thresholds</a>.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/cls.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Two frames showing a large layout shift due to the consent banner." /></p> <p><a href="https://sia.codes/">Sia Karamalegos</a> from Shopify provided <a href="https://performance.shopify.com/blogs/blog/how-to-optimize-cumulative-layout-shift-cls-on-shopify-sites#4.-optimize-your-animations">another great example</a> of how cookie notices that are animating position properties vs. using the preferred method of CSS transform can cause massive CLS scores. (<strong>Side note:</strong> This post is a great read for anyone looking to optimize for CLS their Shopify site)</p> <h3>4. Masking third-party performance</h3> <p>Assuming that you have visibility into your third-party performance is another pitfall when testing the first view of a site synthetically. For some site owners, the difference between the initial experience and an an opted-in experience can be extreme due to the presence of third-party JavaScript.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/compare_phahn.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Comparison of Peter Hahn homepage with and without opt-in consent" /></p> <p>If you were just looking at metrics, the event timeline comparison below may be a bit of a head-scratcher. LCP is deceptively slower in the first view, due to the late render of the consent popup, whose text block is identified as the LCP element. Meanwhile, Time to Interactive (TTI) is much faster. If you look at the highlighted activity timeline, it's apparent that the third-party JavaScript for the opted-in experience creates a lot of additional CPU activity and Long Tasks.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/timelinecompare.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Comparison of event timeline between opted-in and first view" /></p> <p>The opted-in experience also loads an additional 73 third-party requests!</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/uniquethirdpartyrequests.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="List comparing unique third-party requests " /></p> <h3>5. Interaction to Next Paint (INP) and cookie consent</h3> <p>In his <a href="https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp/">latest blog post on debugging INP</a>, Andy Davies provides an example (#3) of how the interaction of accepting the consent dialog causes high processing time. This is due to the functions called from the Event Handler. Given the <a href="https://www.speedcurve.com/blog/check-core-web-vitals-inp/">recent announcement</a> that INP has replaced First Input Delay as a Core Web Vital, this is certainly something to look out for.&nbsp;</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/consentinp.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Flame chart showing high interaction to next paint due to processing time" /></p> <h2>How do I bypass the CMP?</h2> <p>Testing an opted-in experience is highly recommended. This is possible by setting the correct cookie values or in some cases localStorage entries.</p> <p>If you're a SpeedCurve user, we've created a <a href="https://support.speedcurve.com/docs/scripting-cookie-consents">Scripting Cookie Consents Guide</a> with scripting examples for some of the more common CMPs. This includes LiveRamp, OneTrust, Quantcast Choice, TrustArc and Usercentrics.&nbsp;</p> <p>If possible, you should test both experiences &ndash; pre- and post-opt-in &ndash; and treat them as the unique experiences they are.</p> <h2>It's been said before...</h2> <p><a href="https://twitter.com/katiehempenius">Katie Hempenius</a>, <a href="https://twitter.com/simonhearne?lang=en">Simon Hearne</a>,&nbsp;<a href="https://sia.codes/">Sia Karamalegos</a>, <a href="https://twitter.com/AndyDavies">Andy Davies</a> and others have done deep dives into this topic. I've learned a ton from them, and frankly repeated a lot of what they said. Again, this is a PSA that warrants over-communication! ;)</p> <p>Here are some must-reads by these fine folks:</p> <ul> <li><a href="https://web.dev/articles/cookie-notice-best-practices">Best practices for cookie notices</a></li> <li><a href="https://simonhearne.com/2020/testing-behind-consent/">Measuring Performance Behind Consent Popups</a></li> <li><a href="https://andydavies.me/blog/2021/03/25/bypassing-cookie-consent-banners-in-lighthouse-and-webpagetest/">Bypassing Cookie Consent Banners in Lighthouse and WebPageTest</a></li> <li><a href="https://www.speedcurve.com/blog/element-timing-one-true-metric/">Element Timing: One true metric to rule them all?</a></li> <li><a href="https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp/">Debugging Interaction to Next Paint</a></li> <li><a href="https://performance.shopify.com/blogs/blog/how-to-optimize-cumulative-layout-shift-cls-on-shopify-sites">Optimizing CLS for Shopify sites</a></li> </ul> <p>&nbsp;</p> <p><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/481/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Mon, 15 Apr 2024 00:00:00 +1200 A Complete Guide to Web Performance Budgets https://www.speedcurve.com/blog/performance-budgets <p style="text-align: left;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-perf-budgets-social-new.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p style="text-align: left;">It's easier to make a fast website than it is to keep a website fast. If you've invested countless hours in speeding up your site, but you're not using performance budgets to prevent regressions, you could be at risk of wasting all your efforts.</p> <p>In this post we'll cover how to:</p> <ul> <li>Use performance budgets to fight regressions</li> <li>Understand the difference between performance budgets and performance goals</li> <li>Identify which metrics to track</li> <li>Validate your metrics to make sure they're measuring what you think they are &ndash; and to see how they correlate with your user experience and business metrics</li> <li>Determine what your budget thresholds should be</li> <li>Focus on the pages that matter most</li> <li>Get buy-in from different stakeholders in your organization</li> <li>Integrate with your CI/CD process</li> <li>Synthesize your synthetic and real user monitoring data</li> <li>Maintain your budgets</li> </ul> <p>This bottom of this post also contains a collection of case studies from companies that are using performance budgets to stay fast.&nbsp;</p> <p>Let's get started!</p><h2>Why prioritize fighting regressions?</h2> <p>There's a great quote from Michelle Vu (an engineering lead at Pinterest) from her talk at PerfNow a few years ago:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-perf-budgets-pinterest.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>In other words, why work on continuously filling the bathtub if you're not going to plug the drain?</p> <h2>Background: How performance budgets work</h2> <h3>1. What is a performance budget?</h3> <p>A performance budget is a threshold that you apply to the metrics you care about the most. You can then configure your monitoring tools to send you alerts &ndash; or even break the build, if you're testing in your staging environment &ndash; when your budgets are violated.</p> <p><a href="https://twitter.com/thomlbvr/status/1724795285631902178"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/unsplash-perf-budgets-tweet2.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> <h3>2. What should a performance budget look like?</h3> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-budget-sample.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>A good performance budget chart, such as the one above, should show you:</p> <ul> <li>The metric you're tracking</li> <li>The threshold you've created for that metric</li> <li>When you exceed that threshold</li> <li>How long you stayed out of bounds</li> <li>When you returned to below the threshold</li> </ul> <h3>3. How do you determine budget thresholds?</h3> <p>A good practice is to:</p> <ol> <li>Look at your last 2-4 weeks of data for a given metric</li> <li>Identify the worst number</li> <li>Set your performance budget for that number</li> </ol> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-lcp-budget-new.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>In the example above, you can see a time series chart that shows Largest Contentful Paint times over a one-month period. The slowest LCP time is 3.55 seconds, therefore the performance budget &ndash; represented by the red line &ndash; is set for 3.55 seconds. As the person responsible for the performance of this page, you don't want to see it get worse than this while you work to make things faster.</p> <h3>4. Performance budgets vs. performance goals</h3> <p>Your performance budgets are NOT the same as your performance goals.</p> <p><strong>Performance goals are aspirational.</strong>&nbsp;They answer the question <em>"How fast do I want to be eventually?"</em></p> <p><strong>Performance budgets are practical.</strong>&nbsp;They answer the question <em>"How can I keep my site from getting slower while I work toward my performance goals?"</em></p> <p>Let's continue with the example above, where the worst LCP time was 3.55 seconds, making that the most pragmatic performance budget. At the same time, the person responsible for this page might know that they would like the LCP time to be blazing fast at just 1 second or less. That's the goal, but it's not the budget.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-budgets-vs-goals.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>It's important to have your 1-second performance goal in mind, but it's not helpful to make that number your performance budget. If you do, you'll end up with a chart that looks like this:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-lcp-bad-budget.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>There are a few reasons why this chart isn't helpful:</p> <ul> <li><strong>It's demoralizing.</strong> It looks like a history of failure that's intended to shame you, not help you.</li> <li><strong>It's not actionable.</strong> Because you've already violated your budget, you won't get alerts if performance degrades even further.</li> <li><strong>It's ignorable.</strong> Because it's demoralizing and not actionable, you'll quickly learn to ignore it or rationalize it away.</li> </ul> <h3>5. Why do you need performance budgets?</h3> <p>Performance budgets mitigate two of the biggest challenges you probably face in your daily life: not enough time, plus too many people touching the site.</p> <p><strong>You're busy.</strong> You don't have time to check your charts daily to make sure your latest deploy hasn't introduced any regressions. After you've set up performance budgets, you can relax knowing that everything is fine until you get an alert in your inbox or Slack channel.</p> <p><strong>Your site has a number of people contributing content,</strong>&nbsp;such as unoptimized images and third-party tags that have the potential to seriously hurt the speed of your pages. You might not know that a new 1MB hero image is suddenly slowing down an important landing page, but the performance budget you created for tracking image weight violations knows.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-image-size.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>Now that you understand the "what" and "why", let's talk about getting started with your own budgets.</p> <h2>Get started with performance budgets</h2> <h3>6. Which metrics should you start with?</h3> <p>With hundreds of potential performance metrics to track, this is a huge question. While you can (and arguably should) track many metrics across your site, you don't need to set budgets for all of them. In fact, I strongly urge you <strong>not</strong> to do that.</p> <p>Instead, I recommend starting with what I call Minimum Viable Budgets.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/mvb.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>Even if you create performance budgets for just one or two metrics, that's a great start. That approach lets you:</p> <ul> <li>Get comfortable with the mechanics of budgets</li> <li>Confirm that your budgets are working (i.e., you're catching regressions in a timely manner)</li> <li>Teach other people in your organization why these metrics matter</li> <li>Avoid alert fatigue</li> </ul> <p>Here are a few metrics to consider, and why:</p> <p><strong>&gt; Backend (Synthetic and RUM)</strong></p> <p>Also known as Time to First Byte (TTFB), this is the time from the start of the initial navigation until the first byte is received by the browser (after following redirects). Even if you're not responsible for backend time (e.g., you're a front-end developer), it's a good idea to track it because it can delay all your other metrics.</p> <p><strong>&gt; Start Render (Synthetic and RUM)</strong></p> <p>Start Render time is measured as the time from the start of the initial navigation until the first non-white content is painted to the browser display. Even if that first visible paint isn't a meaningful amount of content, it's still a useful signal that the page is working, and it can help stop users from bouncing.</p> <p>People don't talk much about Start Render these days, perhaps because newer, shinier metrics have emerged. But I've participated in many usability studies that have found a strong, consistent correlation between Start Render and business and user engagement metrics such as conversions and bounce rate.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-start-render-vs-bounce.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>Other things that make Start Render a must-watch: It's available in both synthetic and real user monitoring tools, and it's broadly supported across browsers. This is hugely important if you care about understanding site speed for all your users, not just certain cohorts.</p> <p><strong>&gt; Largest Contentful Paint (Synthetic and RUM)</strong></p> <p>Largest Contentful Paint (LCP) is one of Google's&nbsp;<a href="https://www.speedcurve.com/blog/web-vitals-user-experience/">Core Web Vitals</a>. LCP is the time at which the largest visible element in the viewport is rendered. It's only tracked on certain elements, e.g., IMG and VIDEO.</p> <p>However, there are a <a href="https://www.speedcurve.com/blog/element-timing-one-true-metric/">number of caveats to using LCP</a>, such as the fact that different elements can be measured for first-time versus repeat views, or for desktop versus mobile views.&nbsp;</p> <p>Also, LCP is only available in Chromium-based browsers. If you have a significant number of users that come in via other browsers, you should consider tracking Last Painted Hero, below.&nbsp;</p> <p><strong><span style="color: #000000;">&gt; Last Painted Hero (Synthetic)</span></strong></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">Last Painted Hero (LPH) is a synthetic metric that's measurable in any browser. (Fun fact:&nbsp;</span><a href="https://www.speedcurve.com/blog/last-painted-hero/">Largest Contentful Paint was partially inspired by Last Painted Hero.</a><span style="color: #1f1f1f;">) LPH shows you when the last piece of critical content is painted in the browser. It's a handy metric for knowing when all your important content has rendered.</span></span></p> <p><strong><span style="color: #000000;">&gt; Cumulative Layout Shift (Synthetic and RUM)</span></strong></p> <p><span style="color: #000000;"><a href="https://www.speedcurve.com/blog/google-cumulative-layout-shift/">Cumulative Layout Shift (CLS)</a><span style="color: #1f1f1f;">&nbsp;is another one of Google's Core Web Vitals. CLS is a score that captures how often a user experiences unexpected layout shifts as the page loads. Elements like ads and custom fonts can push important content around while a user is already reading it. A poor CLS score could be a sign that page feels janky to your users.</span></span></p> <p><strong><span style="color: #000000;">&gt; Interaction to Next Paint (RUM)</span></strong></p> <p><span style="color: #000000;"><a href="https://www.speedcurve.com/blog/check-core-web-vitals-inp/">Interaction to Next Paint (INP)</a> is another Core Web Vital. </span><span style="color: #000000;">INP measures a page's responsiveness to individual user interactions.&nbsp;</span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">Like LCP, INP is only available in Chromium-based browsers, so if you have a significant number of users that come in via other browsers, you should also consider tracking other responsiveness metrics, such as Total Blocking Time (TBT). </span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;"><strong>&gt; Total Blocking Time (Synthetic)</strong> </span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">Total Blocking Time (TBT) lets you know how much time the various scripts on your page are blocking rendering. Because slow JavaScript is a major cause of delayed responsiveness, TBT is a good proxy for responsiveness metrics like INP. </span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">As a bonus, TBT shows you all the Long Tasks on a page. (More on this below.)</span></span></p> <p><strong><span style="color: #000000;">&gt; Long Tasks (Synthetic and RUM)</span></strong></p> <p><span style="color: #000000;"><a href="https://www.speedcurve.com/blog/javascript-long-tasks/">Long Tasks time</a><span style="color: #1f1f1f;">&nbsp;is the total time of all your JavaScript tasks over 50ms, from navigation start until the page is fully loaded. Tracking Long Tasks will give you a better understanding of the impact that Long Tasks have on the entire page load and your users. </span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-long-tasks-perf-budget.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">This can be especially handy if you have a lot of third-party tags on your pages, as third parties can be a heavy contributor to excessive Long Tasks time. Because you're measuring in synthetic, you can also get a detailed list of all the scripts on a page, along with their Long Task times.</span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-long-tasks2.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;">And if you're wondering, yes, Long Tasks correlate to business metrics like conversion rate.</span></span></p> <p><span style="color: #000000;"><span style="color: #1f1f1f;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-long-tasks-vs-conversion.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></span></p> <p><strong><span style="color: #000000;">&gt; Lighthouse Scores (Synthetic)</span></strong></p> <p><a href="https://developers.google.com/web/tools/lighthouse">Google Lighthouse</a>&nbsp;is an open-source tool that checks your page against rules for Performance, PWA, Accessibility, Best Practice, and SEO. For each of those categories, you get a score out of 100 and recommendations on what to fix.&nbsp;It can be a good idea to track your Performance score to make sure you're not regressing, and then if you do experience a regression, drill down into your audits to identify the cause.</p> <p><strong><span style="color: #000000;">&gt; Page Size (Synthetic)</span></strong></p> <p>If you're concerned about serving huge pages to your mobile users, or if you're worried about site contributors accidentally publishing huge unoptimized image and video files, then you should consider tracking metrics like page size and weight.</p> <p>In an ideal world, pages served to mobile devices would be under 1 MB &ndash; and definitely not more than 2 MB &ndash; but I often see pages in excess of 10 MB. Media sites are particularly prone to this issue.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-page-size.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>Above is a content breakdown for the home page of a mainstream news site. The page contains 725 requests and is over 17 MB in size. Looking at the resource breakdown, I would want to set performance budgets on JavaScript weight (8,680 KB) and image size (6,295 KB). Wow!</p> <p><strong>&gt; Image Size (Synthetic)</strong></p> <p>As said, if your pages contain a number of images &ndash; and if you have multiple content contributors touching your site &ndash; a specific performance budget for image size is a highly recommended guardrail.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-image-perf-budget-tweet2.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p><strong><span style="color: #000000;">&gt; Element Timing (Synthetic and RUM)</span></strong></p> <p>Similar to LCP, Element Timing measures when a DOM element is rendered. Unlike LCP, Element Timing allows you (rather than Chrome) to decide which elements you want to measure. And unlike LCP, Element Timing allows you to measure more than one element on a page. (Learn more&nbsp;<a href="https://www.speedcurve.com/blog/element-timing-one-true-metric/">here</a>.)</p> <p>Element Timing is a somewhat more advanced metric, so if you're just getting started, you might want to make note of it now and come back to it later, when you're ready.</p> <p><strong><span style="color: #000000;">&gt; User Timing (Synthetic and RUM)</span></strong></p> <p>You can create custom metrics to track everything from headlines to call-to-action buttons. Twitter has used custom timers to create a&nbsp;<a href="https://blog.twitter.com/engineering/en_us/a/2012/improving-performance-on-twittercom.html">Time to First Tweet</a>&nbsp;metric. Pinterest has created a&nbsp;<a href="https://timkadlec.com/remembers/2018-03-27-notes-on-making-pinterest-fast-at-perfmatters/#:~:text=Pinterest%20chose%20a%20custom%20metric,impact%20on%20the%20actual%20experience.">Pinner Wait Time</a>&nbsp;metric. Using the&nbsp;<a href="/blog/We%20recommend using our &quot;Long Tasks&quot; metric to track all the long tasks from initial page navigation right through to fully loaded. Do use TBT to help understand your Lighthouse score and Web Vitals metrics, but focus on the Long Tasks time metric to get a full understanding of the impact long tasks have on the whole page load and your users.">W3C User Timing spec</a>, you can add timestamps around the specific page elements that matter most to you. (<a href="https://support.speedcurve.com/docs/custom-metrics">Here's how</a>&nbsp;to add custom timers in SpeedCurve.)&nbsp;</p> <p>Like Element Timing, User Timing requires some expertise to identify what you want to track and then add the timestamps to your pages, as well as ongoing maintenance. Still, they're worth investigating (if not now, then later) if you have the resources and the need.</p> <h3>7. Focus on key pages</h3> <p>You don't need to apply performance budgets to all your pages. When it comes to the impact of page speed on metrics like conversion rate and bounce rate, <strong>some pages are more critical than others</strong>.</p> <p>These are some of the key pages for retail, ranked in order of impact:</p> <ul> <li>Product detail</li> <li>Product category&nbsp;</li> <li>Shopping cart</li> <li>Home&nbsp;</li> </ul> <p>And these are some key pages for media and other sites:</p> <ul> <li>Articles</li> <li>Search</li> <li>Home</li> </ul> <p>Keep in mind that your budgets will most likely vary from page to page, because the performance of your pages may differ widely due to how each page is built.</p> <h3>8. Get buy-in from different stakeholders</h3> <p>Everyone who touches a page should understand the performance impact of changes they introduce to that page. They should also collaborate on setting performance budgets and remediating budget violations.</p> <p>For example, if your marketing team is responsible for adding and maintaining third-party tags, they should:</p> <ul> <li><strong>Have a basic understanding of the metrics</strong> &ndash; such as Long Tasks time &ndash; that measure the performance of each tag.</li> <li><strong>Collaborate on setting the performance budget</strong> &ndash; again, based on the worst result over the previous 2-4 weeks &ndash; for each metric.</li> <li><strong>Receive alerts</strong> (typically via email, Slack, or whatever webhook you use) when the performance budget is violated.</li> <li><strong>Participate in identifying and fixing the issue</strong>&nbsp;(or at least be cc'ed) and get alerted when the budget has been resolved.</li> </ul> <p>In SpeedCurve, you can <a href="https://support.speedcurve.com/docs/custom-charts-dashboards">set up separate dashboards for each stakeholder group</a> in your organization. You can create charts and performance performance budgets within each dashboard, and then configure alerts to be sent only to specific stakeholders.</p> <p>Below is an example of a dashboard created for an SEO team. It focuses on the Lighthouse SEO score, as well as Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift, as those are both Core Web Vitals and therefore important search ranking factors.&nbsp;</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-seo-dashboard.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>A couple of things to note:</p> <ul> <li>For any metrics that are measurable in synthetic and RUM, it's helpful to track them in the same chart. Set the performance budget on your RUM metric so you get an alert when the budget is violated. Then drill down into the synthetic test data to identify and fix the issue. (More on this further down in this post.)</li> <li>In any of the charts where synthetic test data is collected, you can click on any data point to drill down into your&nbsp;<a href="https://support.speedcurve.com/docs/lighthouse">test details</a> where, among other things, you can get detailed audits that recommend what you can fix on the page.</li> </ul> <h3><span style="color: #000000;">9. Use synthetic testing to visually validate your metrics</span></h3> <p><span style="color: #000000;">The metrics mentioned above are not hard-and-fast suggestions. That's because a metric that is relevant and helpful for one page may not be helpful for another.&nbsp;</span><span style="color: #000000;">Before you invest the time and energy in setting up performance budgets for a metric, first take a good look at how that metric aligns with your own data. </span></p> <p><span style="color: #000000;">The easiest way to validate your metrics is to look at rendering filmstrips in your synthetic test data, like this:</span></p> <p><span style="color: #000000;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/check-metrics.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <p><span style="color: #000000;">In the example above (taken from our&nbsp;<a href="https://app.speedcurve.com/benchmark/retail-us/test/230426_9H_62a12a785f91f8d0e2d8843acaf29245/?share=3ssmi8mdfi7g5j2m3oinu6d74c9tae">Industry Benchmarks</a>) you can see:</span></p> <ul> <li><span style="color: #000000;">Start Render does correlate to content appearing in the viewport.</span></li> <li><span style="color: #000000;">Largest Contentful Paint doesn't quite align with the appearance of the largest image.</span></li> <li><span style="color: #000000;">Last Painted Hero, on the other hand, does align with the largest image.</span></li> <li><span style="color: #000000;">Visually Complete comes in much later and arguably isn't helpful for this page.</span></li> </ul> <p><span style="color: #000000;">Based on these observations, you might choose to focus on <strong>Start Render</strong> and <strong>Last Painted Hero</strong>.</span></p> <p><span style="color: #000000;">If you need to validate more metrics, you can <a href="https://support.speedcurve.com/docs/test-details">look at your waterfall chart</a> and see how the various metrics line up with the rendering filmstrip, like this:</span></p> <p><span style="color: #000000;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/waterfall.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <p><span style="color: #000000;">Using this view, it's relatively fast and easy to see which metrics work or don't work for a given page. It's important to keep in mind that just because a metric isn't relevant for one page, that doesn't necessarily mean it's a bad metric. Often, any variability you might see is due to how the page is built.</span></p> <h3><span style="color: #000000;">10. Use real user monitoring to validate user engagement and business impact</span></h3> <p><span style="color: #000000;">This is a good way to give yourself the confidence that you're tracking the right metrics. Ultimately, you want to know that changes you make to your site &ndash; for better or for worse &ndash; will directly affect user behaviour and business outcomes.</span></p> <p><span style="color: #000000;">This is where real user monitoring (RUM) really shines. RUM can track data about bounce rate and conversion rate (along with other user experience and business KPIs). Using this data alongside your performance data, you can <a href="https://support.speedcurve.com/docs/create-correlation-charts">create correlation charts</a> that demonstrate the relationship between performance and business outcomes.</span></p> <p><span style="color: #000000;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/site-1-lcp.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <p><span style="color: #000000;">In the correlation chart above, you can clearly see that as LCP times get slower, bounce rate gets worse. This chart demonstrates that, for this particular site, LCP time is a good metric to set a performance budget for.</span></p> <h3>11. Synthesize your synthetic and real user monitoring data</h3> <p>In an ideal world, you're using both synthetic and real user monitoring (RUM). Several metrics are available in both tools, so you can create charts in which you track the same metric in both synthetic and RUM.</p> <p>(It's important to know that your synthetic and RUM metrics most likely will not match, for reasons explained <a href="https://support.speedcurve.com/docs/synthetic-vs-lux-data">here</a>. This is nothing to be concerned about. The important thing to track is consistency and changes within a single tool and settings.)</p> <p>For a metric that's available in synthetic and RUM, such as Start Render or Largest Contentful Paint, you might want to consider this type of setup:</p> <p><strong>&gt; Track the metric for synthetic and RUM within the same chart.</strong></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/syn-rum-0.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p><strong>&gt; Create the performance budget for the RUM metric, so you get an alert when the budget is violated. This lets you know that real users are experiencing this issue.</strong></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/syn-rum-1.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p><strong><span style="color: #000000;">&gt; Because you're tracking synthetic data in the same chart, you can easily drill down and get detailed test results and diagnostics.</span></strong></p> <p><span style="color: #000000;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/syn-rum-2.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <p><strong><span style="color: #000000;">&gt; Add a note to the chart, stating when you implemented the necessary fixes.&nbsp;</span><span style="color: #000000;">After your fixes go live, you can see (and get an alert) when your metric returns to normal.</span></strong></p> <p><span style="color: #000000;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/syn-rum-3.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <p><span style="color: #000000;">This is just one potential configuration. If you're using your RUM and synthetic data in other ways, I'd love to learn more about it!&nbsp;</span></p> <h3>12. Set up alerting (but not too much!)</h3> <p>Avoiding alert fatigue is crucial to the success of your performance budget strategy. If you're just starting out, it's absolutely fine to focus on just a handful of metrics. You can create performance budgets for all of them, but if you're setting up alerting, focus on just setting up alerts for critical metrics such as:</p> <ul> <li>Backend Time</li> <li>Start Render</li> <li>Largest Contentful Paint</li> <li>Image Size</li> </ul> <h3>13. Integrate with your CI/CD process</h3> <p>You can <a href="https://support.speedcurve.com/docs/continuous-integration">integrate your performance budgets and alerts with your CI/CD process</a>.&nbsp;This gives you the ability to do a few of things:</p> <ul> <li><strong>Run synthetic tests in your staging/development environment</strong> and get alerts if any changes you've introduced have caused budget violations before the page goes live. You can even opt to break the build if any of your budgets are violated.</li> <li><strong>Run tests each time you do a deploy</strong>, catching issues immediately after they go live.&nbsp;</li> <li><strong>Run tests against GitHub pull requests</strong>, so you can test the performance of your PRs before they're merged.</li> </ul> <h2>Keep your budgets relevant</h2> <p>Your budgets will ideally change over time, as your various metrics (hopefully) improve. After you've taken the time to create your performance budgets, you want them to stay relevant and helpful.&nbsp;</p> <h3>14. Update your budgets</h3> <p>If you're taking the practical, iterative approach recommended above, then you should revisit your budgets every 2-4 weeks and adjust them (hopefully downward) accordingly.&nbsp;</p> <p>You should also periodically revisit your metrics &ndash; going through the validation steps described in steps 9 and 10 above &ndash; to make sure you're still tracking the right things go through the validation Are you still tracking the right metrics?&nbsp;</p> <h3>15. Celebrate wins!</h3> <p>If you consistently improve a metric and have just updated your budget, share your charts and let your teams (and your boss!) know. It's important to celebrate even small wins, because big wins are rare. Performance improvement is cumulative. Getting faster should always be celebrated!</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/2024-perf-budgets-celebrate.jpg?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <h2>Case studies</h2> <p>Here's how some of our customers have used performance budgets to stay fast:</p> <ul> <li><a href="https://web.dev/telegraph/">Improving Cumulative Layout Shift at The Telegraph</a></li> <li><a href="https://medium.com/farfetch-tech-blog/how-to-build-a-performance-culture-at-scale-1ed8dc8e79cd">How Farfetch built a performance culture at scale</a></li> <li><a href="https://www.shopify.com/partners/blog/narrative-web-performance">Crafting Faster Themes at Shopify</a></li> <li><a href="https://responsivewebdesign.com/podcast/vox-media-performance/">Building a mobile-first and performance-first culture at Vox Media</a></li> <li><a href="https://nooshu.com/blog/2020/06/17/example-synthetic-web-performance-monitoring-dashboards-using-speedcurve/">How GOV.UK uses performance budgets to keep their site accessible</a></li> <li><a href="https://tech.holidayextras.com/tackling-single-page-application-performance-at-scale-85c67613e4b7">Holiday Extras tackles SPA performance at scale</a></li> <li><a href="https://www.zillow.com/tech/bigger-faster-more-engaging-budget/">Zillow Gets Bigger, Faster, and More Engaging While on a Budget</a></li> <li><a href="https://medium.com/wehkamp-techblog/how-performance-budgets-and-speedcurve-are-helping-us-keeping-a-high-performant-website-283c0233daba">How performance budgets help Wehkamp keep a highly performant website</a></li> <li><a href="https://medium.com/adeo-tech/fostering-a-web-performance-culture-on-leroymerlin-fr-41619e1473d6">Fostering a web performance culture on leroymerlin.fr</a></li> </ul> <h2>More resources</h2> <p>If you're a SpeedCurve user, these resources will help you get started with performance budgets. If you're not using SpeedCurve yet, <a href="https://www.speedcurve.com/signup/">signing up for a free trial is easy!</a></p> <ul> <li><a href="https://support.speedcurve.com/docs/performance-budgets-and-alerts">Create performance budgets and alerts</a></li> <li><a href="https://support.speedcurve.com/docs/status-dashboard">See all your performance budgets at a glance on your Budgets Dashboard</a></li> <li><a href="https://support.speedcurve.com/docs/continuous-integration">Integrate your synthetic testing into your CI/CD environment</a></li> <li><a href="https://support.speedcurve.com/docs/first-third-parties">Track individual first and third parties</a></li> <li><a href="https://support.speedcurve.com/docs/get-started-with-core-web-vitals">Get started with Core Web Vitals</a></li> </ul> <p><em>(This post has been updated from an earlier version published in May 2023.)<br /><br /></em></p> <p><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/442/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Wed, 27 Mar 2024 00:00:00 +1300 Navigate your way to better performance with prerendering and the bfcache https://www.speedcurve.com/blog/bfcache-prerendering <p>I was inspired by <a href="https://twitter.com/TimVereecke">Tim Vereecke's</a> excellent talk on <a href="https://www.youtube.com/watch?v=2shIN0uiYsI&amp;t=5457s">noise-cancelling RUM</a> at <a href="https://perfnow.nl/">PerfNow</a> this past November. In this talk, he highlighted a lot of the 'noise' that comes along with capturing RUM data. Tim's approach was to filter out the noise introduced by really fast response times that can be caused by leveraging the browser cache, prerendering, and other performance optimization techniques.</p> <p>I thought Tim's focus on 'human viewable navigations' was a great approach to use when looking at how to improve user experience. <strong>But there also may be times when you want to understand and <em>embrace</em> the noise.</strong> Sometimes there are opportunities in the signals that we often forget are there.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/navigations-hero.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>In this post, I'll demonstrate how you can use SpeedCurve RUM to identify all types of navigations, their performance impact, and potential opportunities for delivering lightning-fast page speed to your users.&nbsp;</p> <p>We'll cover things like:</p> <ul> <li>Understanding SPA navigations and performance</li> <li>Whether or not to track hidden pages (such as pages opened in background tabs)</li> <li>How to take advantage of prerendering and the back-forward cache (aka bfcache)&nbsp;</li> </ul><h2>Understanding navigation types</h2> <p>We've recently released a new filter in RUM that allows you to explore navigation types. You can find navigation types in the filters of your RUM and Favorites dashboards:</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/476/navfilter.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Filter showing navigation types in dropdown" /></p> <p>The different navigation types we track are:</p> <p style="padding-left: 30px;"><strong>Navigation</strong>&nbsp;&ndash; Full-page navigation&nbsp;</p> <p style="padding-left: 30px;"><strong>Reload</strong>&nbsp;&ndash; Page is reloaded from the browser history</p> <p style="padding-left: 30px;"><strong>Back-Forward Navigation&nbsp;</strong>&ndash;&nbsp;Page navigation using back/forward navigation (also known as bfcache navigation) controls</p> <p style="padding-left: 30px;"><strong>Other </strong>&ndash; All other navigations</p> <p>Not all navigations are created equal.</p> <p>For example, full-page navigations have very different characteristics than bfcache navigations. It's helpful to see this in a histogram, where we can see the distribution for each navigation type for a metric such as Largest Contentful Paint (LCP):<br /><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/navhisto.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Multiple histograms showing LCP for different navigation types" /></p> <h2>Understanding slow page reloads</h2> <p>In doing research for this post, I have to admit that I had an 'uh-oh' moment. Looking at the reloads from the previous chart on the surface was a bit of a head-scratcher:</p> <p style="padding-left: 30px;"><em>How could LCP be so much slower on a reload versus a full-page navigation?</em></p> <p>After a closer look at the histogram, I noticed there were a lot of reloads that happen to be slower in the long tail of the histogram:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/reloadhisto_highlight.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Histogram showing LCP for reload navigation type with a 'bump' in the long tail." /></p> <p>When comparing the fast versus slow reloads, I found that these reloads were for our <strong>RUM Live</strong> dashboard. This dashboard forces a reload automatically. This was for a specific user who was loading the page on a very slow connection.</p> <p><strong>Lesson learned:</strong>&nbsp;<a href="https://www.speedcurve.com/blog/real-user-monitoring-compare-dashboard/">Segmenting your pages in to cohorts</a> is&nbsp;<em>extremely</em> helpful when exploring anomalies like this one.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/reload_live.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Bubble chart showing fast vs slow LCP for Live dashboard" /></p> <h2>Introducing Page Attributes</h2> <p>Another useful filter that we recently added is for something we refer to as <strong>Page Attributes</strong>. This goes a step further in explaining the different types of navigations &ndash; both visible and hidden from the end user.</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/476/pageattributesfilter.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Filter for page attributes with values in dropdown" /></p> <p>This is extremely useful when looking at pages that have unique performance characteristics including:</p> <p style="padding-left: 30px;"><strong>Page was a soft navigation&nbsp;</strong>&ndash; When implementing RUM for a&nbsp;<a href="https://support.speedcurve.com/docs/single-page-applications">SPA</a>, you can use this attribute to compare initial page loads/hard navigations to SPA/soft navigations.</p> <p style="padding-left: 30px;"><strong>Page visibility was hidden*</strong>&nbsp;&ndash; For pages that are loaded in a hidden state, such as when you open a link in a background tab for viewing later, the performance can vary greatly given the browsers ability to mitigate resource consumption in an effort to preserve the user experience.&nbsp;</p> <p style="padding-left: 30px;"><strong>Page was prerendered</strong>&nbsp;&ndash; Prerendering can happen <a href="https://developer.chrome.com/docs/web-platform/prerender-pages#how_is_a_page_prerendered">automagically in the browser</a>&nbsp;or by using the <a href="https://wicg.github.io/nav-speculation/speculation-rules.html">Speculation Rules API </a>. When this occurs, pages that are activated appear to load instantaneously and have unique characteristics compared to other types of navigations. For example, in SpeedCurve, prerendered pages will have a value of '0' for most metrics.</p> <p style="padding-left: 30px;"><strong>Page was restored from back-forward cache*&nbsp;</strong>&ndash;&nbsp;The <a href="https://web.dev/articles/bfcache">bfcache</a> essentially stores the full page in memory when navigating away from the page. This browser optimization has the effect of instantaneous page loads when a user is navigating back (or forward) to a previously viewed page.&nbsp;</p> <p><strong>*Important:</strong>&nbsp;Currently you need to opt-in for tracking of hidden pages and bfcache restores. This is an option in your advanced RUM settings.</p> <h2>Understanding your SPA performance</h2> <p>Single-page application (SPA) performance can be hard to get your head around. <strong>The benefits of a SPA can sometimes be hindrances when you are trying to understand the user experience.</strong> In a SPA soft navigation (versus a full-page navigation), you don't always get the metrics you are looking for, such as render metrics like First Contentful Paint (FCP) and Largest Contentful Paint (LCP). Often you'll have to revert back to traditional timing metrics or those that are triggered by using <a href="https://support.speedcurve.com/docs/metrics">custom metrics</a>.</p> <p>This custom metric comparison illustrates that <strong>performance characteristics can be drastically different between soft navigations and full-page navigations</strong>:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/softnavseries.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Time series chart showing full vs. soft navigation for a custom metric called Hero Image loaded." /></p> <p>The differences between the full and soft SPA navigations can have a big impact on other derived metrics as well, such as user happiness:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/happiness.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="User happiness comparison between a soft and hard navigation showing more happy users for the soft nav" /></p> <h2>Hidden pages: To track or not to track?</h2> <p>If a tree falls in the forest, does anybody hear? By default, SpeedCurve does NOT track pages that are hidden from the user, such as a page opened in a background tab. However, you may want to understand if those pages are having issues.&nbsp;</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/476/openintab.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Right clicking on product image to open link in new tab" /></p> <p><span style="color: #1f1f1f; font-size: 16px;">Be warned that rendering of hidden pages is deprioritized by the browser when trying to conserve resources, which may or may not have something to do with your site. The charts below illustrate that, all things equal, hidden pages are more than a second slower to load than visible navigations.&nbsp;</span></p> <p><span style="color: #1f1f1f; font-size: 16px;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/hiddenpageperf.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Time series data showing page load time slower for hidden pages than visible navigations." /></span></p> <h2>Take advantage of prerendering</h2> <p>Prerendering pages based on where you expect users to click next may sound a little creepy, but it sure does make your user experience a lot faster. In this example of product pages for a major online retailer, prerendered pages were 200% faster than full navigations:</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/476/prerenderedtimeline.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Event timeline comparison showing faster performance times for prerendered pages" /></p> <p>What is this mysterious prerendering magic we speak of, and how do you take advantage of it? Prerendering has been around in Chrome for a little while, but just recently the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API">Speculation Rules API</a> was introduced, which supersedes the now deprecated <code>&lt;link rel="prerender"&gt;</code>.</p> <p>Using prerender json instructions within&nbsp;<code><span class="token tag" style="color: var(--code-token-attribute-value); background-color: initial; font-family: var(--font-code); font-size: var(--type-smaller-font-size); box-sizing: border-box;"><span class="token punctuation" style="box-sizing: border-box; color: var(--code-token-punctuation);">&lt;</span>script</span> <span class="token attr-name" style="color: var(--code-token-attribute-name); background-color: initial; font-family: var(--font-code); font-size: var(--type-smaller-font-size); box-sizing: border-box;">type</span><span class="token attr-value" style="color: var(--code-token-attribute-value); background-color: initial; font-family: var(--font-code); font-size: var(--type-smaller-font-size); box-sizing: border-box;"><span class="token punctuation attr-equals" style="box-sizing: border-box; color: var(--code-token-punctuation);">=</span><span class="token punctuation" style="box-sizing: border-box; color: var(--code-token-punctuation);">"</span>speculationrules<span class="token punctuation" style="box-sizing: border-box; color: var(--code-token-punctuation);">"</span></span><span class="token punctuation" style="color: var(--code-token-punctuation); background-color: initial; font-family: var(--font-code); font-size: var(--type-smaller-font-size); box-sizing: border-box;">&gt;</span></code>, browsers will prefetch and load the page into memory cache, making subsequent navigations appear instantaneous.&nbsp;</p> <p>Chrome also uses prerendering for addresses typed into the omnibox for pages with a high confidence. The search bar may also leverage prerendering, depending on the provider.</p> <p><a href="https://twitter.com/tunetheweb">Barry Pollard</a> provides a comprehensive overview of the ins and outs of prerendering <a href="https://developer.chrome.com/docs/web-platform/prerender-pages">here</a>.</p> <h2>Putting the BF (blazing fast) in BFCache</h2> <p>Another notable cheat code for web performance is the use of the browser's bfcache, which essentially stores the fully rendered page in memory. Used in the aforementioned back/forward navigation, <strong>if the page is in the bfcache, you're in for another 'instant' page load</strong>.</p> <p>Bfcache is available in all modern browsers. As shown here, the performance difference between a full-page navigation and a bfcache restore &ndash; 2.59 seconds versus 0.07 seconds &ndash; is pretty impressive!</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/bfcachecompare.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Comparison of two distributions, one is for bf cache restores and much faster than the other which is a full page navigation." /></p> <p>If you are a <a href="https://developer.chrome.com/docs/lighthouse/overview">Lighthouse</a> user or familiar with the audits provided in SpeedCurve, you may have noticed the following audit as of Lighthouse 10:<br /><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/bfaudit.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Example of a failed audit for bfcache" /></p> <p>For Chrome, there are a number of reasons why a bfcache restore may fail. Some of them are within your control, while others are not. Here is a great resource for understanding&nbsp;<a href="https://web.dev/articles/bfcache#optimize_your_pages_for_bfcache">how to optimize your pages for bfcache</a>.</p> <p><strong>Important:</strong>&nbsp;The criteria for a page entering the bfcache is different between Chrome and other browsers. Safari has been leveraging bfcache for quite some time and appears to be far less restrictive.&nbsp;</p> <p>For the same site listed above &ndash; which failed the bfcache audit &ndash; Safari (desktop and mobile) has a very large number of bfcache restores, while Chrome and Firefox are missing all together!</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/bfcachebybrowser.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Time series chart showing bfcache restores by browser" /></p> <h2>Get started</h2> <p>Low-hanging fruit tastes the best. While everything else you're doing to speed up your pages is by no means a wasted effort, understanding how to leverage the browser in a more effective way for repeated navigations is totally worth it!</p> <p>If you're already using SpeedCurve RUM, then you can take advantage of all the insights described in this post. If you're not using our RUM yet, we'd love to have you try it! <a href="https://www.speedcurve.com/signup/">Sign up for your free trial</a> and follow the steps in <a href="https://support.speedcurve.com/docs/welcome-to-speedcurve">our welcome guide</a> to get started.<br /><br /></p> <p><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/476/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Mon, 25 Mar 2024 00:00:00 +1300 Hello INP! Here's everything you need to know about the newest Core Web Vital https://www.speedcurve.com/blog/check-core-web-vitals-inp <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/hello-inp-hero.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>After years of development and testing, Google has added Interaction to Next Paint (INP) to its trifecta of <a href="https://web.dev/articles/vitals">Core Web Vitals</a>&nbsp;&ndash; the performance metrics that are a key ingredient in its search ranking algorithm. INP replaces First Input Delay (FID) as the Vitals responsiveness metric.</p> <p>Not sure what INP means or why it matters? No worries &ndash; that's what this post is for. :)</p> <ul> <li>What is INP?</li> <li>Why has it replaced First Input Delay?</li> <li>How does INP correlate with user behaviour metrics, such as conversion rate?</li> <li>What you need to know about INP on mobile devices</li> <li>How to debug and optimize INP</li> </ul> <p>And at the bottom of this post, we'll wrap thing up with some inspiring case studies from companies that have found that improving INP has improved sales, pageviews, and bounce rate.&nbsp;</p> <p>Let's dive in!</p> <p>&nbsp;</p><h2>What is Interaction to Next Paint?</h2> <p style="padding-left: 30px;"><em>"Chrome usage data shows that 90% of a user's time on a page is spent after it loads. Thus, careful measurement of responsiveness throughout the page lifecycle is important. This is what the INP metric assesses."</em></p> <p style="padding-left: 30px; text-align: right;"><em>~Jeremy Wagner, Google&nbsp;</em></p> <p>In other words, we need a reliable metric that helps us understand <strong>how a page's responsiveness (or lack thereof) during the entire time a user is on the page helps (or hurts) their experience</strong>.</p> <p>When you interact with a page, you want the page to respond seamlessly. The longer the wait, the worse the user experience, as you start wondering if the page is broken and start anticipating a frustrating, laggy experience. (This frustration is hardwired, as you can learn in <a href="https://www.speedcurve.com/blog/psychology-site-speed/">this post about the psychology of site speed and human happiness</a>.)&nbsp;</p> <p>This is where measuring Interaction to Next Paint can help. INP measures the time from when a user starts an interaction &ndash; such as a mouse click, touchscreen tap, or physical or onscreen key press &ndash; until the next frame is painted in the browser. The faster the INP time, the more seamless the interaction feels.</p> <p><strong>According to Google, an INP of 200 milliseconds or less is ideal.</strong>&nbsp;Having said that, you may wish to aim for a faster INP for your own pages, for reasons I'll go into further down in this post.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/inp-thresholds.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>In <a href="https://web.dev/articles/inp">this excellent post</a>, Jeremy Wagner explains how Interaction to Next Paint is calculated and how Google's INP thresholds (pictured above) are determined.</p> <h2>Farewell, First Input Delay!</h2> <p>Before we go any further, you might find it interesting to learn a bit more about First Input Delay (FID), the interactivity metric that preceded INP in Core Web Vitals, and why it was deprecated.&nbsp;</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/fid-conversions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>Here at SpeedCurve, we definitely get excited about emerging metrics. But we also approach each new metric with an analytical eye. Way back in 2020, Cliff Crocker took a closer look at First Input Delay and found that <a href="https://www.speedcurve.com/blog/first-input-delay-google-core-web-vitals/">FID did not meaningfully correlate with actual user behaviour</a>.&nbsp;</p> <h2>Does INP correlate to user behaviour?</h2> <p>The point of measuring <em>responsiveness</em> is because <em>unresponsiveness</em> hurts the user experience &ndash; which ultimately hurts your business metrics, such as bounce rate and conversions. If this is true, then <strong>we should be able to draw a direct line between Interaction to Next Paint and business metrics</strong>.&nbsp;</p> <p>This is where correlation charts come in super handy.&nbsp;</p> <p><a href="https://support.speedcurve.com/docs/create-correlation-charts">Correlation charts</a> give you a histogram view of all your user traffic, broken out into cohorts based on performance metrics such as INP. The chart also includes an overlay that shows you a user engagement metric or business metric &ndash; such as bounce rate or conversion rate &ndash; that correlates to each of these cohorts. This lets you see at a glance the relationship between performance, user engagement, and your business.</p> <p>A few months ago, Cliff Crocker turned his attention to analyzing INP. In his <a href="https://www.speedcurve.com/blog/INP-user-experience-correlation/">exploration of INP's correlation to conversion rate</a> for a handful of different sites, Cliff found that yes, there typically is a correlation: <strong>when INP gets worse, conversions suffer.</strong></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/inp-correlations.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>However, Cliff also made the following observations:</p> <ul> <li><strong>Results vary across sites</strong> &ndash; Not surprisingly, the impact is different based on the slope of the conversion line, as well as the distribution of INP across user sessions.</li> <li><strong>There is no consistent correlation with Google's thresholds&nbsp;for 'Good', 'Needs Improvement', and 'Poor'.</strong> This is a hugely important observation. As Cliff states:
"For one site, conversions suffer when INP is 100ms &ndash; well within Google's 'good' parameter of 200ms. This doesn't mean it's a bad idea to have a general set of thresholds. It just means those thresholds might not apply to your site. You must look at your own data."</li> </ul> <h2>Mobile INP is really important!</h2> <p>After further analysis, Cliff discovered still more important INP insights, including:</p> <h3><span style="white-space: normal;">1. Only two-thirds of mobile sites have 'good' INP&nbsp;</span></h3> <p><span style="white-space: normal;">Looking at data from the HTTP Archive, which tracks performance metrics for the top million sites on the web, the percentage of sites that have good INP is 96.8% for desktop, but only 64.9% for mobile. One of the biggest culprits: latency, which is typically worse on mobile.</span></p> <p><span style="white-space: normal;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/inp-desktop-vs-mobile.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span></p> <h3><span style="white-space: normal;">2. Mobile INP = Android INP&nbsp;</span></h3> <p><span style="white-space: normal;">This is due to the lack of Safari support for INP (among other performance metrics). If a significant number of your users are coming to you from Safari, you need to track a different responsiveness metric.</span></p> <h3><span style="white-space: normal;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/android-mobile-inp.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></span><span style="white-space: normal;">3. Mobile INP has an <em>even stronger correlation</em> with bounce rate and conversions than desktop INP&nbsp;</span></h3> <p><span style="white-space: normal;">You can see this in the charts below. Ignoring mobile responsiveness isn't something most of us can afford to do.</span></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/desktop-inp-conversions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/mobile-inp-conversions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>One of the many important takeaways from this post is that responsiveness on mobile is absolutely crucial to business and UX metrics. But if you're focusing on just INP to measure responsiveness, you're only getting insights into mobile performance for just one cohort of your users.&nbsp;</p> <h2>How to debug and optimize INP</h2> <p>Now that you understand how slow INP hurts your users and your business, let's talk about solutions. In <a href="https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp/">this in-depth post</a>, Andy Davies walks through what INP is, how to identify and debug slow interactions, and some approaches he's used to improve them.</p> <p style="padding-left: 30px;"><em>"Many sites tend to be in the 'Needs Improvement' or 'Poor' category. My experience over the last few months is that <strong>getting to 'Good' (under 200ms) is achievable, but it's not always easy</strong>."</em></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/inp-reduction.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>In his very detailed and comprehensive post, Andy walks through:</p> <ul> <li>How he helps people identify the causes of poor INP times</li> <li>Examples of some of the most common issues</li> <li>Approaches he's used to help sites improve their INP</li> </ul> <h2>INP case studies</h2> <p>The best way to understand the importance of optimizing INP is to look at your own RUM data for your own site. The second-best way is to look at case studies from other companies that have had success. Here's a handful for you to check out:</p> <ul> <li><a href="https://web.dev/case-studies/trendyol-inp">Trendyol reduced INP by 50%</a>, resulting in a 1% increase in click-through rate</li> <li><a href="https://web.dev/case-studies/redbus-inp">redBus improved INP</a> and increased sales by 7%</li> <li><a href="https://web.dev/case-studies/redbus-inp">The Economic Times reduced INP from 1s to 257ms</a>, leading to a 50% decrease in bounce rate and 43% increase in pageviews</li> </ul> <h2>Takeaways</h2> <p><strong>1. You definitely should be monitoring Interaction to Next Paint</strong> for your site, ideally using real user monitoring as the best source of truth.</p> <p><strong>2. You may find it helpful to create correlation charts</strong> to validate INP as a meaningful business-related metric.</p> <p><strong>3. When you create correlation charts, take careful note of when your business metrics start to suffer.</strong> Even though Google's recommended 'Good' INP threshold is 200 milliseconds, good INP for your own site may be higher or lower than that.&nbsp;</p> <p><strong>4. Look at INP separately for mobile and desktop.</strong> Your numbers could be quite different. You may also find that INP correlated to business metrics differently in each environment.</p> <p><strong>5. Think beyond INP.</strong> This is crucial if you have a lot of users coming to your site from different browsers. Remember that INP is only supported in Chrome-based browsers.&nbsp;&nbsp;</p> <h2>How to monitor INP in SpeedCurve</h2> <p>If you're not already using our RUM to monitor INP alongside your other important metrics, we'd love to have you give us a try!&nbsp;</p> <ul> <li><a href="https://www.speedcurve.com/signup/">Start your free 30-day trial</a></li> <li><a href="https://support.speedcurve.com/docs/setup-guide">Follow our handy guide to enabling RUM</a></li> <li><a href="https://support.speedcurve.com/docs/track-core-web-vitals">Create your Core Web Vitals dashboard</a> (it's easy!) so you can get alerts when any of your metrics start to suffer</li> <li>Check out our <a href="https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp/">guide to debugging INP</a></li> <li><a href="https://www.speedcurve.com/blog/rum-attribution-subparts-interaction-to-next-paint/">Understand INP subparts</a> so you can quickly home in on issues</li> <li>Contact us at support@speedcurve.com with questions or feedback</li> </ul> <p><br /><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/482/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Tue, 12 Mar 2024 00:00:00 +1300 Continuous performance with guardrails and breadcrumbs https://www.speedcurve.com/blog/continuous-web-performance <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/guardrails-top.jpg?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p>The hardest part about web performance isn&rsquo;t making your site faster &ndash; it&rsquo;s keeping it that fast. Hearing about a company that devoted significant effort into optimizing their site, only to find their performance right back where it started a few months later, is all too familiar.</p> <p><strong>The reality is that, as critical as site speed is, it&rsquo;s also very easy to overlook</strong>. It doesn&rsquo;t jump out like a blurry image or a layout issue. And the majority of modern tools and frameworks that are used to build sites today make it all too easy to compound the issue.</p> <p>Making performance more visible throughout the development process is one of the most critical things a company can do.</p> <p>I like to think of it as setting up guardrails and breadcrumbs.</p> <ul> <li>We need&nbsp;<em>guardrails</em>&nbsp;to help protect us from shipping code that will result in unexpected regressions.</li> <li>We need&nbsp;<em>breadcrumbs</em>&nbsp;that we can follow back to the source to help us identify&nbsp;<em>why</em>&nbsp;a metric may have changed.</li> </ul> <p>Guardrails and breadcrumbs need to work together. Setting up guardrails without the ability to dive in more will lead to frustration. Having proper breadcrumbs without guardrails in place all but assures we will constantly be fighting regressions&nbsp;<em>after</em>&nbsp;they&rsquo;ve already wreaked havoc on our sites and our users.</p> <p>Let&rsquo;s take a look at both of these concepts and how they should work together.</p><h2>Guardrails</h2> <p>The default stance of most tooling today is to make it easier to add code to your site or application at a moment&rsquo;s notice. (Hey there,&nbsp;<code>npm install</code>.) What they don&rsquo;t prioritize nearly as much is making you aware that you&rsquo;re doing something that&rsquo;s going to negatively impact your performance.</p> <p>To combat that, we need to find ways to put guardrails into our workflows to help us notice when we're at risk of causing a performance regression. Luckily we have a few tools at our disposal.</p> <h3>Performance budgets</h3> <p>Tammy&nbsp;<a href="https://www.speedcurve.com/blog/performance-budgets/">has written quite a bit</a>&nbsp;about performance budgets, and it&rsquo;s something worth repeating. While a budget alone doesn&rsquo;t ensure good performance, <strong>I have yet to see a company sustain performance over the long haul without using some sort of performance budget</strong> (whether they use that term or not).</p> <p>I like to define a performance budget as <em>a clearly defined limit on one or more performance metrics that the team agrees not to exceed</em>. That budget then is used to alert on potential regressions, break deployments when a regression is detected, and guide design and development decisions.</p> <p>SpeedCurve comes with some default performance budgets, but you&rsquo;ll want to reassess for yourself, probably on a 2-4 week basis to make sure the budgets you have set align with your reality. We&rsquo;re looking for a balance of "alerts if there's a regression" and "doesn&rsquo;t alert so much that we start ignoring the alerts".</p> <p>Here's an example from a recent KickStart engagement. (KickStarts are <a href="https://www.speedcurve.com/features/consulting/">consulting projects</a> where we help companies get set up and running with their monitoring.) The budget for JS Scripting was set to 2000ms (that&rsquo;s the red line), but the site was well below budget. The budget was useless. They would have to have a regression of over 500% to trigger any sort of alert!</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/underbudget.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A chart showing a performance budget set so low that it never triggers" /></p> <p>We ended up setting the budget at 375ms based on the last two weeks of data at the time. That enables us to get alerted on regressions without getting alert fatigue.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/newbudgetjs.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A chart showing a properly configured budget that will catch regressions" /></p> <p>Looking at the chart, if they continue on the current trend, the next time they reassess their budget they may want to bring it down a little bit further, as some recent changes seem to have resulted in improvements.</p> <p>On the other hand, their Start Render budget was too aggressive. They were constantly over, resulting in notification fatigue &ndash; it was always over, so why pay attention?</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/startrenderover.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A chart showing a Start Render budget that is too aggressive...it's always triggered." /></p> <p>Adjusting the budget to 3 seconds makes it much more actionable.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/startrenderfixed.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A chart showing a Start Render budget now adjusted to catch regressions, but not fire daily" /></p> <p>Now they will only get emailed when the budget is triggered by a regression, so they know it's something they should take action on.</p> <h3>Automated testing of code changes</h3> <p>Another important guardrail is to have automated performance testing when code changes occur. Just as important, those test results should show up somewhere in the development process &ndash; where the developers are. <strong>Requiring the team to go looking for results in another tool every time adds unnecessary friction.</strong></p> <p>A great way to do this is to have an automated test triggered with every pull request, and then have the results put right back into the details of the pull request for easy review.</p> <p>I&rsquo;m a big fan of the&nbsp;<a href="https://www.speedcurve.com/blog/web-performance-test-pull-requests/">Github integration</a>&nbsp;for this reason. With zero code changes (just a few button clicks to get GitHub and SpeedCurve talking to each other), you can get automated performance testing set up on every pull request. (If you&rsquo;re not using GitHub, you can also use the&nbsp;<a href="https://support.speedcurve.com/reference/get-all-deploys">deploy API</a>&nbsp;to trigger automated tests.)</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/githubi.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="The Github integration in action, showing perf data on a Github pull request" /></p> <p>Now when a team makes a code change, they get immediate performance feedback right in the pull request review process, helping performance stay front of mind.</p> <h2>Breadcrumbs</h2> <p>Guardrails are awesome and important for helping catch regressions before they occur, but they&rsquo;re only half the battle. <strong>If we can see that we&rsquo;re suffering from &ndash; or about to suffer from &ndash; a regression, but we can&rsquo;t figure out why, we&rsquo;ll quickly become frustrated</strong>... and may even lose faith in the tools and processes we're using.</p> <p>We need to leave ourselves breadcrumbs &ndash; a path back to identifying the actual source of a regression so we can fix things.</p> <h3>Deployment tracking</h3> <p>If you&rsquo;re using the <a href="https://www.speedcurve.com/blog/web-performance-test-pull-requests/">GitHub integration</a>, you get a breadcrumb by default. When the integration comments on the pull request, you&rsquo;re given a link back to the deployment report. (You also get the report when you use the Deploy API, minus the Github specific information.)</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/details.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A deployment details page showing a failed deployment with 4 of 5 budgets exceeded." /></p> <p>The deployment report lets you see:</p> <ul> <li>The associated code repository and pull request (when using the GitHub integration)</li> <li>The code branch</li> <li>The commit ID</li> <li>The test results</li> <li>The status of any budgets for that test and whether or not the test failed or passed</li> <li>Full, comprehensive test results, so you can dig in further</li> </ul> <p>Don&rsquo;t overlook the importance of that last one! Having automated testing that provides a basic overview report with no way to really dig in is a fast track to frustration.</p> <h3>Notes</h3> <p>Deployment tracking automatically adds notes to your charts, so you can quickly spot what changed, and when.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/notes.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="A chart of a Cumulative Layout Shift graph. There's a big improvement right when the deployment note shows" /></p> <p>You can also manually add notes for situations where a deployment wasn&rsquo;t the cause of the change. For example, if you&rsquo;ve made changes to your CDN configuration, or a third-party provider had an outage.</p> <p>Notes don&rsquo;t clutter the charts (they show up as little icons below each chart and only bring up more detail when hovered over), so you can &ndash; and probably should &ndash; use them liberally to help you remember why you may be seeing a shift in metrics at a particular point in time. Again, <strong>think of these as little breadcrumbs you&rsquo;re leaving for you and your teammates to be able to quickly identify the source of changes in the future</strong>.</p> <p>For deployments, you&rsquo;ll also be able to click on the notes to be taken back to the deployment details page and dive right back in.</p> <h2>Guardrails and breadcrumbs</h2> <p>Performance isn&rsquo;t something we fix once and then walk away from. As the content and composition of our pages change, we need to make performance a continuous focus.</p> <p>Guardrails and breadcrumbs work together to help us get a comprehensive picture of what's happening.</p> <ul> <li><strong>Performance budgets</strong> let us set thresholds, with alerting, on key metrics so we know right away if there's a problem</li> <li><strong>Automated code testing</strong> puts performance information right in front of the developers, using those same performance budgets to give a clear indication of the impact of every code change</li> <li><strong>Pairing automated testing with detailed test results</strong> ensure that developers are able to dive in and quickly identify the source of the regression</li> <li><strong>Having annotations appear in historical charting</strong> that connects to those deployments &ndash; as well as other changes &ndash; ensures the entire team has full context in why performance may have shifted</li> </ul> <p>Putting up the appropriate guardrails to protect ourselves from regressions &ndash; then pairing that with a trail of breadcrumbs so that we can dive in and quickly identify what the source is when a regression occurs &ndash; are essential steps to ensure that when we make our sites fast, they stay that way.</p> <p><br /><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/478/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Mon, 04 Mar 2024 00:00:00 +1300 NEW: On-demand testing in SpeedCurve! https://www.speedcurve.com/blog/on-demand-web-performance-testing <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/adhoc-testing-hero.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></p> <p style="text-align: right;"><sup><em>Image by <a href="https://www.freepik.com/free-vector/finger-pressing-red-start-button_2947389.htm#query=finger%20pressing%20button&amp;position=3&amp;from_view=keyword&amp;track=ais&amp;uuid=f3ff2ad6-50be-46d6-ae4a-7b03d8b6ba86">Freepik</a></em></sup></p> <p>On-demand testing has sparked a lot of discussion here at SpeedCurve over the past year. You've always had the ability to manually trigger a round of tests &ndash; based on the scheduled tests in your settings &ndash; using the 'Test Now' button. But there hasn't been a lot of flexibility to support nuanced use cases, such as...</p> <p style="padding-left: 30px;"><em>"I just deployed changes to my site and want to check for any regressions."</em></p> <p style="padding-left: 30px;"><em>"I saw a change to my RUM data and I want to see if I can replicate it with synthetic for further diagnostics."</em></p> <p style="padding-left: 30px;"><em>"I have a paused site that I don't want to test regularly, but would like to test from time to time."</em></p> <p style="padding-left: 30px;"><em>"Please just let me test any URL I want without setting up a site and scheduling testing."</em></p> <p style="padding-left: 30px;"><em>"I need to quickly debug this script without kicking off tests for my entire site."</em></p> <p style="padding-left: 30px;"><em>"I would like to get a first look at a page in order to troubleshoot regressions I saw in RUM."</em></p> <p><strong>Based on your feedback, we've just launched new capabilities for <a href="https://support.speedcurve.com/docs/ondemand-site-testing">on-demand testing</a>.</strong> We're pretty excited about these, and we hope you will be, too!</p> <p>In this post, we'll:</p> <ul> <li>Highlight the differences between on-demand and scheduled testing</li> <li>Cover the various types of on-demand testing, including some of the more common use cases we've heard from SpeedCurve users</li> <li>Step you through running an on-demand test</li> </ul> <p>Let's goooooooo!</p><h2>What are the two types of tests within SpeedCurve?</h2> <p>Synthetic performance testing comes in two forms:</p> <h3>Scheduled testing</h3> <p>Baselining. Benchmarking. Continuous performance testing. Tried-and-true performance monitoring goes by many names. This is a necessary offering that keeps folks honest, supports the use of <a href="https://www.speedcurve.com/blog/performance-budgets/">performance budgets</a>, and gives you a lot of consistency when identifying what has changed over time or between deploys.</p> <h3>On-demand testing</h3> <p>This is something our new release fully embraced. Based on feedback from our customers &ndash; as well as the industry at large &ndash; we now give you the ability to run tests when debugging, benchmarking, or just because you feel like it. This is a highly sought after arrow in your web performance quiver.</p> <h2>On-demand testing in SpeedCurve</h2> <p>You now have two options for testing on demand:&nbsp;</p> <h3>Site testing</h3> <p>For each site you have configured in your SpeedCurve test settings, you have the ability to test on demand. Using this option, you'll test the existing URLs you have configured for a Site using the pre-defined configuration in your settings.</p> <h3>Custom URL testing</h3> <p>You now have the ability to test any URL using selected browsers and locations. You can also script a test if you are testing something using any of the scripting options, such as blocking third parties or testing a page within a multi-step transaction.</p> <h2>How do I run tests on demand?</h2> <p>You can trigger on-demand tests either automatically or manually, using the options described below.</p> <h3>Automatic: API, CLI, GitHub integration</h3> <p>On-demand testing of a site can be triggered using these options:</p> <ul> <li><a href="https://support.speedcurve.com/reference/get-all-deploys">SpeedCurve REST API</a></li> <li><a href="https://github.com/SpeedCurve-Metrics/speedcurve-cli">SpeedCurve CLI</a></li> <li><a href="https://support.speedcurve.com/docs/github-integration">SpeedCurve Github integration</a>&nbsp;&ndash; NEW! This is a great option for CI/CD or other means of triggering non-scheduled tests.</li> </ul> <h3>Manual: 'Test Now'</h3> <p>We've added new options to the 'Test Now' feature in SpeedCurve. To run an on-demand test, simply click on 'Test Now' from the side menu.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/test-now-button.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="SpeedCurve portal with Test Now button highlighted" /></p> <p><strong>Support article:</strong> <a href="https://support.speedcurve.com/docs/manual-deployment">Trigger deployment tests</a></p> <h2>On-demand site testing</h2> <p>Here are some common use cases that may sound familiar to you:</p> <p style="padding-left: 30px;"><em>"I just deployed changes to my site and want to check for any regressions."</em></p> <p style="padding-left: 30px;"><em>"I saw a change to my RUM data and I want to see if I can replicate it with synthetic for further diagnostics."</em></p> <p style="padding-left: 30px;"><em>"I have a paused site that I don't want to test regularly, but would like to test from time to time."</em></p> <p>To test an existing site, select the site (or sites) to be tested. You can optionally add a note here, or elect to group the tests as a deployment. (I'll discuss that later in this post.)</p> <p><em><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/477/sitetest.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Dialog for testing an existing Site configuration" /></em></p> <p><strong>Support article:</strong> <a href="https://support.speedcurve.com/docs/ondemand-site-testing">Test a site on demand</a></p> <h2>Custom URL (adhoc) testing</h2> <p>Some of these use cases may be familiar to you as well:</p> <p style="padding-left: 30px;"><em>"Please just let me test any URL I want without setting up a site and scheduling testing."</em></p> <p style="padding-left: 30px;"><em>"I need to quickly debug this script without kicking off tests for my entire site."</em></p> <p style="padding-left: 30px;"><em>"I would like to get a first look at a page in order to troubleshoot regressions I saw in RUM."</em></p> <p>There are many reasons you may want to execute an adhoc test in SpeedCurve. The custom URL option when selecting 'Test Now' allows you to do just that.</p> <p>To test a custom URL, click the 'Test Now' button and select the custom URL in the dialog. You have the option to add one or more URLs for testing, as well as the ability to select different regions, browser types, and the number of times to test the URL.<br /><br /><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/477/customurltestnow.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Dialog for running an on-demand test with custom url selected" /></p> <p>You also have the option to add basic authentication, as well as a <a href="https://support.speedcurve.com/docs/synthetic-test-scripts">scripted test</a>. This can be very useful if you are trying to debug a script before adding it to a site, or if you simply need advanced options for the site or user flow you are testing.</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/477/customscript.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Dialog of a custom url test using a script command" /></p> <p><strong>Support article:</strong> <a href="https://support.speedcurve.com/docs/adhoc-testing">Adhoc (custom URL) testing</a></p> <h2>Viewing on-demand tests</h2> <p>Once your test(s) are kicked off, you'll be directed to the <strong>Synthetic Tests</strong> dashboard. From here, you can see the status and history of all of your tests &ndash; and even filter by test type.</p> <p>For each test, you have the option to:</p> <ul> <li>View the results&nbsp;</li> <li><a href="https://support.speedcurve.com/docs/bookmark-and-compare-tests#how-to-bookmark-and-compare-synthetic-tests">Compare the results</a> with another test</li> <li>Retest with the same on-demand settings</li> </ul> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/testsinqueue.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Tests dashboard showing queued custom url tests." /></p> <h2>Test details</h2> <p>Once your tests have completed, the <a href="https://support.speedcurve.com/docs/test-details">Test Details dashboard</a> is ready for viewing.</p> <p>If you are new to this dashboard, here is a summary of what's captured and displayed for every test.</p> <h3>Test overview and Lighthouse scores</h3> <ul> <li>See what was tested, including your test settings</li> <li><a href="https://support.speedcurve.com/docs/lighthouse">Lighthouse results</a> with details are provided for every synthetic test</li> </ul> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/testdetailslighthouse.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details with lighthouse scores" /></p> <h3>Render times</h3> <p>Key rendering moments of the page lifecycle are visualized with user focused milestone metrics. Both the LCP and&nbsp;<a href="https://www.speedcurve.com/blog/last-painted-hero/">Last Painted Hero</a> elements are highlighted.</p> <h3><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/rendertimes.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details with render times visualization" /></h3> <h3>Compressed and expanded waterfall</h3> <p>The best of both worlds. Seeing a simplified event timeline makes it easy to understand how key metrics line up with the actual filmstrip through the use of a scrubber.&nbsp;</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/waterfall_condensed.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Condensed version of waterfall" /></p> <p>Expanding the waterfall exposes a great amount of detail for every request. If you are looking for more detail, click on 'Detailed Results' to see the full test results for every test run.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/waterfall_expanded.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details expanded waterfall" /></p> <h3>CPU and content breakdowns</h3> <p>Understanding the impact that JavaScript has on CPU usage can be seen in these visuals for three points in the page lifecycle: Start Render, Page Load, and Fully Loaded.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/cpubreakdown.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details with breakdown by CPU" /></p> <p>Page construction &ndash; both HTTP request count and size &ndash; is a helpful indicator of good/bad performance. This breakdown shows you how the content you choose affects the overall size, weight, and complexity of the page.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/contentbreakdown.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details with breakdown by content type" /></p> <h3>CLS diagnostics</h3> <p><a href="https://www.speedcurve.com/blog/cls-windows-core-web-vitals/">Cumulative Layout Shift</a>&nbsp;is broken down by each layout shift and displayed within session windows. Start with the largest layout shifts in the highlighted window first!</p> <h2><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/layoutshifts.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Test details dashboard with layout shift diagnostics including CLS windowing" /></h2> <h2>Grouping tests as a deployment</h2> <p>For all on-demand tests, you have the option to group them as a deployment. You'll want to add a name and any details you wish to include.</p> <p><img class="blog-img-md" src="https://blog-img.speedcurve.com/img/477/sitetestdeploy.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Dialog showing deployment notes" /></p> <p>Once the deployment test(s) are triggered, you'll be taken to the <strong>Deployments</strong> dashboard in lieu of the synthetic tests dashboard to view your deploy.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/deploydash.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Deploys dashboard showing queued on-demand tests" /></p> <p>Once completed, you'll be able to see the high-level pass/fail results for the deploy.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/deployfail.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Deployments showing failed test status." /></p> <p>Clicking through to the <strong>Deployment Details</strong> gives you details around the deployment, including performance budget status, filmstrips, and more for each test in the deployment.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/deploydetails.gif?auto=format,compress&amp;fit=max&amp;w=2000" alt="Deployment details dashboard showing details for the on-demand test deployment" /></p> <p><a href="https://support.speedcurve.com/docs/deployment-testing-synthetic">Read this article</a>&nbsp;to learn more about deployments.</p> <h2>Summary</h2> <p>You asked, we listened. We hope you continue to get value from your testing in SpeedCurve with the on-demand testing capabilities we've introduced. As always, <a href="mailto:%20support@speedcurve.com">your feedback</a> is welcome!&nbsp;</p> <p>Not a SpeedCurve customer? Start a <a href="https://www.speedcurve.com/signup/">free trial</a> today!</p> <p><br /><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/477/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Thu, 29 Feb 2024 00:00:00 +1300 Debugging Interaction to Next Paint (INP) https://www.speedcurve.com/blog/debugging-interaction-to-next-paint-inp <p>Not surprisingly, most of the conversations I've had with SpeedCurve users over the last few months have focused on improving INP.</p> <p><strong>INP measures how responsive a page is to visitor interactions.</strong> It measures the elapsed time between a tap, a click, or a keypress and the browser next painting to the screen.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/inp.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Definition of INP" /></p> <p>INP breaks down into three sub-parts</p> <ul> <li><strong>Input Delay</strong>&nbsp;&ndash; How long the interaction handler has to wait before executing</li> <li><strong>Processing Time</strong>&nbsp;&ndash; How long the interaction handler takes to execute</li> <li><strong>Presentation Delay</strong>&nbsp;&ndash; How long it takes the browser to execute any work it needs to paint updates triggered by the interaction handler</li> </ul> <p>Pages can have multiple interactions, so the INP time you'll see reported by RUM products and other tools, such as Google Search Console and Chrome's UX Report (CrUX), will generally be the worst/highest INP time at the 75th percentile.</p> <p>Like all Core Web Vitals, INP has a set of thresholds:</p> <p style="text-align: center;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/inp-thresholds.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="INP thresholds for Good, Needs Improvement and Poor" /><br /><em>INP thresholds for Good, Needs Improvement, and Poor</em></p> <p><br />Many sites tend to be in the Needs Improvement or Poor categories. My experience over the last few months is that getting to Good is achievable, but it's not always easy.</p> <p>In this post I'm going to walk through:</p> <ul> <li>How I help people identify the causes of poor INP times</li> <li>Examples of some of the most common issues</li> <li>Approaches I've used to help sites improve their INP</li> </ul><h2>Identifying Interactions</h2> <p>The Chrome UX Report (CrUX) can provide a high-level view of INP. Individual pages can be spot checked via the CrUX API or tools such as Page Speed Insights&nbsp;</p> <p>But as Cliff's already covered in&nbsp;<a href="https://www.speedcurve.com/blog/interaction-to-next-paint-find-ix-elements/">How to find (and fix!) INP interactions on your pages</a>, CrUX is no substitute for having your own RUM data that you can group and filter by dimensions such as the different page and device types.&nbsp;<br /><br />My favourite place to start is with the Web Vitals heatmap on SpeedCurve's <strong>RUM &gt; Performance</strong>&nbsp;dashboard. It gives a high-level summary that can be filtered by page label to check if the behavior is consistent across all paths in the group.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/heatmap2.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Heatmap showing 75th Percentile values for Core Web Vitals per Page Group" /></p> <p style="text-align: center;"><em>Heatmap of the most popular pages and their Web Vitals metrics</em></p> <p><br />I then typically switch to the&nbsp;<strong>RUM &gt; Design</strong> dashboard and use the list of popular interaction elements to determine which ones I want to investigate further.</p> <p style="text-align: center;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/common-interactions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Common visitor interactions ranked by frequency" /><br /><em>Most popular interactions</em></p> <p><br />Ideally we'd have a view that shows which interactions are responsible for high INP times. (We're currently working on adding full attribution for INP to SpeedCurve.) In the meantime, we've discovered that, in practice, just knowing which page types have high INP times and the interactions visitors are using on those pages is really effective at identifying interactions to investigate further.</p> <p>Some companies I work with don't have RUM. In those cases, we think about the common interactions visitors are likely to use &ndash; dismissing cookie dialogs, opening menus, zooming on product images, etc. &ndash; and investigate those further. The caveat here is that it's not as effective as having RUM data to work from and can lead improvements that don't seem to influence INP much.</p> <h2>Profiling Interactions</h2> <p>Once we know which pages have high INP times, and what are the popular interactions on those pages, I switch to Chrome DevTools, profile the interactions, and identify ways to improve them.</p> <p>The Performance panel can be overwhelming &ndash; even for experienced engineers &ndash; as it exposes how much work the browser is doing to load pages or handle interactions.</p> <p>Here is the approach I use when debugging interactions. Although I'm using Chrome Canary in these examples, the same approach works in stable Chrome and other Chromium-based browsers.</p> <h3>1. Switch to a guest user profile</h3> <p>As guest user profiles don't load extensions, they help minimise some of the noise that extensions and other factors can have on performance analysis.</p> <p>Guest profiles also&nbsp;start with empty caches, empty cookie stores, empty browser storage, etc. These may get populated during testing, but we can clear them at any time via&nbsp;<em>Application</em> &gt; <em>Storage</em> &gt; <em>Clear Site Data</em> in DevTools.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/chrome-guest-profile.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Switching to a guest profile in Chrome" /></p> <p style="text-align: center;"><em>Opening a guest profile in Chrome</em><br /><br /></p> <h3>2. Open DevTools and switch to the Performance panel</h3> <p>As mobile visitors tend to be the majority of visitors for most sites, I also switch to mobile emulation.</p> <p><img class="blog-img" style="display: block; margin-left: auto; margin-right: auto;" src="https://blog-img.speedcurve.com/img/472/chrome-devtools-performance-panel.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools Performance Panel" /></p> <p style="text-align: center;"><em>Switching to the DevTools Performance panel<br /><br /></em></p> <h3>3. Load a page</h3> <p>Load the page you want to investigate. Wait until has finished load before profiling it.</p> <h3>4. Hit 'Record' and interact with the page</h3> <p>After the page has loaded, press the record icon in the DevTools toolbar, wait for the profile to start recording, and then interact with the page.</p> <p>The profiler starting up often creates a Long Task right at the start of the profile, so I tend to wait a second or so before actually interacting.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/chrome-devtools-recording.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Starting a trace in the DevTools Performance panel" /></p> <p style="text-align: center;"><em>Recording a profile<br /><br /></em></p> <h3>5. Stop recording</h3> <p>After you've recorded data on the interactions you're interested in, stop recording. After a few moments you should be greeted with a view something like the one below.</p> <p>In this view I've opened the tracks for Frames, Interactions, and Main Thread so I can see what's visible on the page when I interacted with it as well as the activity that happened on the main thread.</p> <p style="text-align: center;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/performance-profile.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Example performance profile from Chrome DevTools" /><br /><em>Example performance profile in Chrome DevTools</em><br /><br /></p> <p>In the Main Thread track you can see the Profiling Overhead task right at the start of the profile and then a second call stack in response to the interaction.&nbsp;</p> <p>A quick guide to interpreting this panel:</p> <ul> <li>The width of each cell in the call stack represents the <strong>elapsed time</strong> it (and its children) executed.</li> <li>The dark yellow, magenta, and green cells represent <strong>internal browser work</strong>.</li> <li>The pastel cells represent the <strong>scripts</strong> included in the page. (Each script gets its own color.)</li> </ul> <p>Clicking on an individual cell will show more detail in the summary panel at the bottom of the tab (not shown in screenshot). You can zoom in/out and scroll using either the mouse or the W A S D keys.</p> <h2>Analyzing Interactions</h2> <p>After we've captured profiles, we can start analyzing them to understand why we're seeing long INP times, and perhaps more importantly, what we can to do reduce them.</p> <p>While writing this post, I tested interactions on a few sites and chose three examples that illustrate the common issues I see.</p> <p>The examples were captured in Chrome Canary on a 2020 i5 MacBook Pro without CPU throttling enabled. If CPU throttling was enabled or the tests were carried out on an actual Android device, then I'd expect the INP times to be higher.</p> <p>If you want to explore the traces in more detail I've uploaded them to <a href="https://toot.cafe/@paul_irish">Paul Irish's</a>&nbsp;<a href="https://trace.cafe">trace.cafe</a></p> <h3>Example 1 &ndash; Opening the menu on H&amp;M</h3> <p>In this first example, I opened the menu on the mobile version of H&amp;M by clicking on the icon in the top right.&nbsp;</p> <p>Even though I only clicked on the page once, multiple event handlers were invoked. The one for the menu was the longest and had INP time of 350ms &ndash; in other words, 150ms longer than Google's 200ms threshold for 'Good'.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/hm-three-interactions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools showing three interactions as the menu was opened" /></p> <p style="text-align: center;"><em>Long interaction when opening the menu on H&amp;M</em></p> <p><br />In this case, most of the time is spent in the actual event handler (<em>Processing Time</em>) for the menu, but there is a slight delay before the event handler can execute.</p> <p>Examining the flame chart reveals four main groups of processing that happen in response to the interaction:</p> <ol> <li>Akamai's bot manager is the source of the first two event handlers. These event handlers execute before the one for the menu, so creating the <em>Input Delay</em> for the menu interaction.</li> <li>Within the longest event handler, the first group of processing creates an analytics event to record the visitor opening the menu.</li> <li>The second group is a JS component that constructs the menu and then adds it to the DOM, triggering style recalculations and layout.</li> <li>The last group adds a style element to the DOM, again triggering style recalculations.</li> </ol> <p><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/hm-flame-chart-overlay.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Flame Chart with overlay showing the main split in work" /></p> <p style="text-align: center;"><em><span style="text-align: center;">Main thread activity when opening the menu on H&amp;M</span></em></p> <p><br />Here I'd start by focusing on what's the source of the long <em>Processing Time</em>, asking questions such as:</p> <ul> <li>Can the menu be rendered without using React?</li> <li>Does the stylesheet need to be injected?</li> <li>Could the design of the interaction be changed to avoid it?</li> </ul> <p>&gt; <a href="https://trace.cafe/t/gyeN0QKToq">Explore the trace</a></p> <h3>Example 2 &ndash; Opening the menu on John Lewis</h3> <p>For the second example, I've also chosen to open the menu. The trace for John Lewis shows similar patterns to the one for H&amp;M.</p> <p>Again there's another event handler that fires before the handler for the menu, but the execution of the both handlers is also delayed by a separate task on the Main Thread. These tasks create a 170ms <em>Input Delay</em> before the interaction handler for the menu executes.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/john-lewis---interactions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="DevTools sowing long interactions when opening the menu on John Lewis" /></p> <p style="text-align: center;"><em><span style="text-align: center;">Long interaction when opening the menu on John Lewis</span></em></p> <p><br />Breaking down the main thread activity shows eight groups of activities that delay the response to the interaction:</p> <ol> <li>Initial interaction occurs while a Long Task caused by a customer feedback widget is executing.</li> <li>Even though feedback widget isn't visible, it triggers a style recalculation and layout.</li> <li>A <em>pointerdown</em> event handler within the site's own code executes.</li> <li>Akamai's bot manager is listening to <em>pointerdown</em> and <em>touchstart</em> events, and handlers for these events execute.</li> <li>Handlers within the site's own code for&nbsp;<em>gotpointercpature</em>, <em>lostpointercapture</em>, <em>pointerup</em>, <em>pointerout</em> and <em>touchend</em> events execute.</li> <li>A style recalculation (which I believe is triggered by the bot manager) and a&nbsp;<em>mousedown</em>&nbsp;handler registered by Akamai bot manager execute.</li> <li>The menu hander finally executes and generates the DOM for the menu.</li> <li>Lastly, a style recalculation triggered by the menu hander executes.</li> </ol> <p>John Lewis uses New Relic. New Relic wraps many of the script calls, and this has some impact on the duration of the tasks. If I were investigating this further, I'd profile with New Relic disabled to measure what impact it's having (if any).<br /><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/john-lewis---call-stacks.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools showing the Main Thread activity during an interaction" /></p> <p style="text-align: center;"><em>Main thread activity when opening the menu on John Lewis</em></p> <p><br />The main question I'm asking when I see this kind of profile is this:</p> <p>What can be done to reduce the <em>Input Delay</em>&nbsp;&ndash; the Long Task at the start, then focusing in on the intermediate event handlers, and lastly the style and layout calculations?</p> <p>(In the chart above, the whisker for the <em>Presentation Delay</em> extends into a GTM task, but I believe this is a Chrome issue. You might also notice Chrome Canary doubles up some Long Tasks in the Profile, too.)<br /><br />&gt; <a href="https://trace.cafe/t/46PZ6lDnH7">Explore the trace</a></p> <h3>Example 3 &ndash; Accepting the consent dialog on Wales Online</h3> <p>For the last example, I'm closing the consent dialog that all sites in Europe are required to display before they inject third-parties such as ads and analytics into the page.</p> <p>Here the main issue is the amount of work the event handler is trying to complete in a single task. The <em>Processing Time</em> for the interaction is 382ms</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/wales-online---interactions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools showing the long interaction when the Consent Manager is closed" /></p> <p style="text-align: center;"><em>Long interaction when clicking 'accept' on Wales Online</em></p> <p><br />Examining the flame chart reveals six main groups of processing that happen in response to the interaction:</p> <ol> <li>Closing the dialog is actually pretty quick as it just needs to be removed from the DOM.</li> <li>The consent manager starts communicating consent to the ad providers, so they can begin to load.</li> <li>Amazon Ads executes.</li> <li>Prebid executes.</li> <li>A second Prebid component executes .</li> <li>A 'Bad Ads reporting tool' adds a stylesheet. After the styles are parsed and recalculated, something forces a layout task.</li> </ol> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/wales-online---call-stacks.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools showing the main browser tasks when someone clicks Yes in the Consent Manager on Wales Online" /></p> <p style="text-align: center;"><em>Main thread activity after clicking 'accept' on Wales Online</em></p> <p><br />One thing that's noticeable with the Wales Online example is that the <em>Processing Time</em>&nbsp;is entirely due to third-party scripts. That can limit the options to reduce it, but even then it should be possible to divide the task up.<br /><br />&gt; <a href="https://trace.cafe/t/Jeqw44miet">Explore the trace</a></p> <h2>Fixing Interactions</h2> <p>After we've identified why an interaction has a high INP time, our next goal is to reduce it. I find that separating how I think about <em>Input Delay</em> versus&nbsp;<em>Processing Time and Presentation Delay</em>&nbsp;can help.</p> <ul> <li><strong><em>Input Delay</em></strong>&nbsp;is due to other tasks blocking the main thread and so delay when the interaction handler can execute. As such,&nbsp;<em>Input Delay</em>&nbsp;is outside an interaction handler's control.</li> <li><strong><em>Processing Time and Presentation Delay</em></strong> are the time the interaction handler takes to execute, and then the time it takes the browser to complete layout, styling, paint, and other tasks created by the event handler.</li> </ul> <p style="text-align: center;"><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/inp-input-delay-vs-processing-time-and-presentation-delay.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Division between Input Delay, and combined Processing Time and Presentation Delay" /></p> <p style="text-align: center;"><em>Split between Input Delay, and combined Processing Time and Presentation Delay</em></p> <p><br />As <em>Processing Time</em> and <em>Presentation Delay</em> are easier to identify and fix, I'm going to cover them first before moving on to <em>Input Delay.</em></p> <h3>How to improve Processing Time and Presentation Delay</h3> <p>When it comes to reducing&nbsp;<em>Processing Time</em>&nbsp;and&nbsp;<em>Presentation Delay</em>, many articles focus on breaking up Long Tasks up or 'yielding to the main thread' with <code>setTimeout</code>, <code>scheduler.yield</code> or <code>requestIdleCallback</code>, etc.</p> <p>While that is one place to start, it's not the only approach. My view is that reducing the time Long Tasks take to execute is just as important as splitting tasks up.</p> <p>My other guiding view is to focus on what's most important from a user perspective and optimize that. For example, if the user is opening a menu, then showing them the menu is the most important activity. Anything else that might be triggered by the same action should be secondary.</p> <h4>1. Defer less important activities&nbsp;</h4> <p>Both the H&amp;M and John Lewis menus record an analytics event when someone opens the menu. These calls happen before the menu is actually displayed. (I've seen this pattern on many other sites, too.)</p> <p>While analytic events are useful to help us understand our visitors' behavior, they're secondary and shouldn't delay the visitors primary goal, in this case opening the menu.</p> <p>Scheduling these events into a new task via setTimeout (e.g. <code>setTimeout(analytics_fn, 0)</code> or <code>scheduler.postTask</code> for browsers that support it) moves the work out of the interaction handler to be executed later and allows the interaction handler to complete sooner.</p> <p>The same method can be used with Wales Online's consent manager. After the visitor has clicked 'accept' or 'reject' they want to get on and read the news rather than wait for multiple ad providers to be given permission to load (or not). Scheduling <code>setConsentInfo</code> into a separate task enables the browser to paint the next frame sooner, while the ad providers can carry on loading in the background.</p> <p>Here's an example of what this looks like in a trace:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/cmp-with-timeout.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="DevTools profile showing Long Task scheduled in to new task" /></p> <p style="text-align: center;"><em>Breaking up a click event handler by scheduling work into a separate task</em></p> <p style="text-align: left;"><br />The Long Task was originally part of the click event handler. Using <code>setTimeout</code> to schedule it into its own separate task allows the browser to paint before the Long Task executes. The Long Task might still be a problematic if someone interacts while it's executing, but it's no longer part of the click handler's INP.</p> <p>I've seen many examples where publishers have improved INP by scheduling the setting of consent into a separate task. I expect consent managers to adopt this approach as a default.</p> <h4>2. Do less work</h4> <p><a href="/blog/@ryantownsend@webperf.social">Ryan Townsend</a> spoke about <a href="https://www.youtube.com/watch?v=f5felHJiACE">The Unbearable Weight of Massive JavaScript</a> at <a href="https://perfnow.nl/">performance.now()</a> in November 2023. He shared a case study where they replaced over 50,000 lines of JavaScript with native HTML and CSS features. The result was a faster user experience with more maintainable codebase.</p> <p>H&amp;M relies on JavaScript components to create the menu elements, add them to the DOM, and apply styles. The result: a processing time of 303ms.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/hm-three-interactions.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Chrome DevTools showing three interactions as the menu was opened" /></p> <p style="text-align: center;"><em>Long interaction when opening the menu on H&amp;M</em></p> <p><br />Let's compare this to another fashion retailer, French Connection. French Connection creates the menu elements when they render the page server-side, and then just changes the elements styles to display the menu. This illustrates the dramatic difference in processing time between the two approaches:</p> <ul> <li>H&amp;M processing time: <strong>303ms</strong></li> <li>French Connection processing time: <strong>22ms</strong> (of which nearly half is sending an analytics event to Google Tag Manager!)</li> </ul> <p><strong><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/french-connection-menu.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Performance Profile when opening the menu on French Connection" /></strong></p> <p style="text-align: center;"><em>Interaction when opening the menu on French Connection</em></p> <p><br />Of course the French Connection page is going to have more DOM elements. When tools like Lighthouse warn you to "avoid an excessive DOM size", it's tempting to choose other approaches without perhaps fully considering the tradeoffs. Menus often contain large numbers of DOM elements. The choice is whether they're created when the page is initially generated, or at runtime using JavaScript when the menu is requested.</p> <p>Lighthouse warns about DOM size because it "will increase memory usage, cause longer style calculations, and produce costly layout reflows." But when used carefully, CSS properties like&nbsp;<em>content-visibility</em>, <em>isolation</em>, and <em>will-change</em> can help reduce the cost of a large number of DOM nodes.</p> <p>Talking of CSS, you might have noticed that in some of the examples above, INP was affected by some long style and layout calculations. These were caused by interaction handlers injecting styles that affected the whole DOM, or by interaction handlers querying style or size properties via methods like&nbsp;<em>getComputedStyle</em> or <em>getBoundingClientRect</em>, so forcing recalculations. (Paul Irish keeps a list of JavaScript methods that typically&nbsp;<a href="https://gist.github.com/paulirish/5d52fb081b3570c81e3a">trigger style and layout calculations</a>.)</p> <p>Think about the work you're asking the browser to do and whether there are more efficient ways of achieving the end result.</p> <h4><strong>3. Yield to the main thread</strong></h4> <p>Sometimes there isn't work that can be deferred, or the efficiency of interaction handlers can't be improved. In those cases, we just need give control back to the main thread so that it can get on with painting the next frame.</p> <p>One approach is to use <em>setTimeout</em> wrapped in a Promise:<br /><code></code></p> <div> <p><code>function yieldToMain() {</code></p> <p><code>&nbsp; return new Promise(resolve =&gt; {</code></p> <p><code>&nbsp; &nbsp; setTimeout(resolve,0);</code></p> <p>&nbsp; &nbsp; <code>});</code></p> <p><code>}</code></p> </div> <p>&nbsp;</p> <p>And then at suitable points in the code insert:<br /><br /></p> <div> <p><code>// Yield to the main thread:</code></p> <p><code>await yieldToMain();</code></p> </div> <p>&nbsp;</p> <p><em>setTimeout</em> creates a new task, so enabling the browser's scheduler to take over and process other tasks like input before resuming.</p> <p><a href="https://www.linkedin.com/in/malchata">Jeremy Wagner</a>&nbsp;discusses this approach in more detail in his web.dev posts on <a href="https://web.dev/articles/optimize-inp#yield_to_the_main_thread_often">Optimizing INP</a>&nbsp;and <a href="https://web.dev/articles/optimize-long-tasks#use_asyncawait_to_create_yield_points">Optimizing Long Tasks</a>. I'd suggest you read those for a deeper view.</p> <p>The other option to consider for tasks that are hard to optimize is whether the work they're doing can be moved off the main thread via a Web Worker. I've not had the need to use this approach with clients yet.</p> <h3>How to improve Input Delay</h3> <p>Diagnosing the causes of slow Input Delay isn't always easy with just Synthetic monitoring and DevTools. That's because the length of the delay depends on when the visitor interacted with the page and what tasks were executing when the visitor interacted.&nbsp;<br /><br />The&nbsp;<a href="https://developer.chrome.com/docs/web-platform/long-animation-frames">Long Animations Frame (LoAF) API</a>, which is set to ship in Chrome 123, will help RUM tools identify the tasks that caused <em>Input Delay</em>. Once identified, we will be able to profile the tasks in DevTools.</p> <p>Until LoAF is widely supported, there are profiling approaches in DevTools that can help identify some of the problematic scripts.</p> <h4><strong>1. Investigate other interaction handlers</strong></h4> <p>As the H&amp;M and John Lewis examples demonstrated, other touch, mouse, and keyboard event handlers are also triggered by interactions and can execute before our event handler for the main interaction.</p> <p>Fortunately these event handlers are captured in the DevTools profile. We can also inspect which event handlers are active using the&nbsp;<em>Event Listeners</em> panel in the right sidebar of the <em>Elements</em> panel in DevTools.<br /><br /><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/event-listeners.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="DevTools Event Listeners Panel" /></p> <p style="text-align: center;"><em>Viewing active event listeners in Chrome DevTools</em></p> <p><br />Some monitoring products, such as New Relic, wrap other scripts calls. This can make identifying the code that's actually going to execute a bit harder. To identify the actual event handler, you can either:</p> <ul> <li>Block the external instrumentation script</li> <li>Use DevTools&nbsp;<em>Content Overrides</em> to create a copy of the page with New Relic, etc., removed</li> </ul> <p>Once we've identified event listeners that are active for click, key, mouse, and tap events, we can review and remove any that aren't really necessary. <br /><br />If third-party tags are adding their own event handlers, then it's a case of:</p> <ol> <li>Evaluating the tradeoff between the features the third party provides and its impact on the visitors experience</li> <li>Raising the issue with the provider</li> <li>Expecting the provider to fix the issue</li> </ol> <p>Some third-party providers are serious about addressing the impact they have on INP. If you're using one that's not, then I'd advocate switching to an alternative.</p> <h4>2. Investigate other Long Tasks</h4> <p>It's harder to identify any other Long Tasks that contribute to <em>Input Delay.</em>&nbsp;It depends on what task is executing when the visitor interacts (this is where LoAF will really help) and how long the task continued executing after the initial interaction.</p> <p>But we do know there is a relationship between total Long Task Time and INP:<br /><br /></p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/total-long-task-time-vs-inp.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Relationship between Total Long Task Time and Interaction to Next Paint" /></p> <p style="text-align: center;"><em>Relationship between Long Tasks and Interaction to Next Paint (INP)</em></p> <p><br />And we also know that visitors start to interact shortly after they start to see content:</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/fcp-vs-first-interation.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Correlation chart showing relationship between First Contentful Paint and First Click Interation" /></p> <p style="text-align: center;"><em>Relationship between First Contentful Paint (FCP) and First Click Interaction</em><br /><br /></p> <p>The exact relationships will vary from site to site, but the overall pattern was pretty consistent across the many sites I checked.</p> <p>Knowing this, we can make an informed guess that any Long Tasks that occur after useful content starts to appear are in danger of contributing to <em>Input Delay</em>.</p> <p>In John Lewis' case, profiling the page while it loads shows there are a bunch of Long Tasks that happen after 2.2s &ndash; notice the gap in the filmstrip &ndash; and these are likely to lead to higher INP times if the visitor tries to interact at this point.</p> <p style="text-align: center;"><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/john-lewis-long-tasks.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="Main Thread activity when loading John Lewis' home page" /><br /><em>Profile showing Long Tasks during John Lewis home page loading</em>&nbsp;</p> <p><br />Some other things you might want to experiment with:</p> <ul> <li>Profiling a page while it loads and then trying to interact as soon as there's visible content.</li> <li>Profiling the acceptance of a cookie consent dialog and then interacting immediately after while third parties might be still starting up.</li> <li>If you have tasks that repeat at a regular frequency (e.g. ad refreshes), you can profile what happens if a visitor interacts during those.</li> </ul> <p>As far as optimising these Long Tasks goes, my advice is very similar to optimising slow interaction handlers:</p> <ul> <li>Defer secondary work into new tasks</li> <li>Optimize code so it uses the browser efficiently</li> <li>Yield to the main thread appropriately</li> </ul> <p>One thing to watch out for:</p> <p>There's often a Long Task just before the DOM Content Loaded event. This is because<a href="https://issues.chromium.org/issues/40894694">&nbsp;any deferred and module scripts execute as a single &ndash; potentially long &ndash; task just before DOM Content Loaded</a>. Until browser makers change this behaviour, there's always a potential for this Long Task to create <em>Input Delay</em> if someone interacts at this point.</p> <h2>Wrapping up</h2> <p>Getting to the root of high INP times and fixing them can be quite complex and sometimes overwhelming. It's important to remember that even small incremental changes add up to larger overall improvements.</p> <p>Some other things to keep in mind...</p> <h3>Use RUM when you can</h3> <p>RUM is great for quickly identifying pages and interactions with high INP times. But even without RUM it's possible to start improving INP. There's just a danger that you might not be profiling the most influential interactions.</p> <p>When it comes to actually understanding and optimizing INP:</p> <ul> <li>Profile in a guest window to remove noise caused by extension or previous state</li> <li>Identify secondary activities and defer them into separate tasks</li> <li>Optimize the primary tasks &ndash; lean on the native power of browsers but watch activities that create unnecessary style and layout calculations</li> <li>Break remaining Long Tasks up by yielding to the main thread</li> <li>Review other interaction handlers to check they're necessary and aren't contributing to&nbsp;<em>Input Delay</em></li> </ul> <h3>It's easy to write a list of actions, but not always easy to implement them</h3> <p>This is especially true if a site is heavily reliant on a JavaScript framework.</p> <h3>Measurement of INP isn't a perfect science</h3> <p>You may come across things that don't quite make sense. I've seen <code>requestAnimationFrame</code> and <code>setTimeout</code> loops delay input handlers. I've also seen JavaScript dialogs really affect INP. As with all Core Web Vitals, it's a work in progress. I expect the Chrome team will address some of these edge cases eventually.</p> <h3>Progress may not be linear</h3> <p>The reported INP measurement represents the worst interaction on the page ,and pages can have many interactions. If the slowest interaction has an INP time of 500ms, and the second slowest has an INP time of 450ms, then fixing the worst interaction will only reduce INP by 50ms!</p> <p>To borrow the words of Pok&eacute;mon, you gotta catch 'em all!</p> <h3>If you need some inspiration...</h3> <p>I've been using the techniques from this post to help companies improve their INP time. For one company, we reduced INP by more than 50% in the space of just a couple of weeks.</p> <p><img class="blog-img" src="https://blog-img.speedcurve.com/social/472/inp-75th.png?auto=format,compress&amp;fit=crop&amp;ar=2:1&amp;w=1200" alt="https://blog-img.speedcurve.com/social/472/inp-75th.png?auto=format,compress&amp;fit=crop&amp;ar=2:1&amp;w=1200" /></p> <p style="text-align: center;"><em>Reduction in INP due to Long Tasks improvements</em></p> <h2>Need help measuring and fixing INP?</h2> <p>If you'd like to start measuring INP effectively,&nbsp;<a href="https://www.speedcurve.com/signup/">we offer a free 30-day trial</a> that includes both real user and synthetic monitoring.</p> <p>We also have <a href="https://www.speedcurve.com/features/consulting/">some of the most experienced web performance consultants</a>&nbsp;in the world. If you're not sure where to start with INP, or are stuck with what to do next, feel free to get in touch via <a href="mailto:support@speedcurve.com">support@speedcurve.com</a>.<br /><br /><br /><a href="https://www.speedcurve.com/signup/"><img class="blog-img" src="https://blog-img.speedcurve.com/img/472/customer-logos-free-trial-banner.png?auto=format,compress&amp;fit=max&amp;w=2000" alt="" /></a></p> Mon, 26 Feb 2024 00:00:00 +1300