Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Performance - Time to First Pizza

Avatar for Ian Duffy Ian Duffy
September 16, 2026
58

Web Performance - Time to First Pizza

Avatar for Ian Duffy

Ian Duffy

September 16, 2026

Transcript

  1. HELLO MY NAME IS IAN DUFFY I WORK AT JET2HOLIDAYS

    AS A WEB PERFORMANCE ENGINEER BEEN WORKING IN WEB DEVELOPMENT FOR ABOUT 10 YEARS WEBSITE: IANKDUFFY.COM
  2. Imagine you are at a Pizza place. Think about 1

    The time between entering, getting a menu and actually seeing there is something on the menu you want. 2 The interactions you have from entering to leaving, which ones do you remember? 3 Finding out the ingredients for the pizza you wanted are not available after you have ordered.
  3. Focus On The Speed Web Pages Load, Responsiveness To User

    Interactions And The Visually Stability.
  4. 100 Lighthouse !== Perfect Performance 1 Lighthouse is a Lab

    test and not measurement of real user experience including interactions. A Google Engineer found Almost half of all pages that scored 100 on Lighthouse didn’t meet the recommended Google metrics in 2021 2 3 Chasing Lighthouse Points can lead to implementing "optimisations" that harm the overall user experience.
  5. Core Web Vitals LCP INP Largest Contentful Paint Interaction to

    Next Paint How soon the user sees the main content How listened to do the users feels when trying to complete their tasks on the page 2.5s Good 4s Needs Improvement CLS Cumulative Layout Shift Greater than 4s 200ms 500ms Greater than 500ms Good Needs Improvement Poor Poor Lighthouse: partial – page load tested, excludes delayed fetches and SPAs, often inaccurate Lighthouse: not measured whatsoever How comfortable the user is on the page 0.1 0.25 Greater than 0.25 Good Needs Improvement Poor Lighthouse: partial - only measured during page load
  6. Based on Studies on UX and Human Perception Play Cause

    0-100ms Mixed 100-200ms Unrelated Over 200ms The 1946 experiment that defined the INP threshold
  7. Largest Contentful Paint (LCP) The render time of the largest

    (in pixel size) image or block element visible in the viewport. Images Background Images Text Video including <img/>, <picture>, <image> in SVG including <div style="background-image: url()" /> including <h1>, <h2>, <p> including video cover image or first frame
  8. Interaction to Next Paint (INP) Measures user events throughout page

    lifespan, and reports the longest duration. Long Javascript Tasks Analytic / Third Party Scripts Blocking Main Thread Delayed visual feedback
  9. Cumulative Layout Shift (CLS) Measures the largest bursts for every

    unexpected layout shift during the lifespan of a page added together. Images with missing width and height Web Fonts resizing text Page elements added via javascript with no space reserved
  10. // Record the time immediately before running a task. performance.mark('myTask:start');

    await doMyTask(); // Record the time immediately after running a task. performance.mark('myTask:end'); // Measure the delta between the start and end of the task performance.measure('myTask', 'myTask:start', 'myTask:end'); Create Your Own Metrics Using performance.mark() API, elementtiming (soon container timing api), and Performance Observer you can design custom performance metrics that match your business needs. // Create the performance observer. const po = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { // Log the entry and all associated details. console.log(entry.toJSON()); } }); po.observe({type: 'measure', buffered: true}); <script> // Create the performance observer. const po = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { // Log the entry and all associated details. if (entry.name === 'hero') { console.log(entry.toJSON()); } } }); po.observe({type: 'element', buffered: true}); </script> <img src="hero.png" style="width: 100px; height: 100px;" elementtiming="hero" />
  11. async function pizzaAndPullRequest() { performance.mark('time-to-first-pizza:travel-start'); await travelToNewcastleCityCenter() performance.mark('time-to-first-pizza:travel-end'); performance.mark('time-to-first-pizza:wait-in-lobby-startt') await

    waitInLobbyAndGetElevatorUp(); performance.mark('time-to-first-pizza:wait-in-lobby-end'); Time to First Pizza performance.mark('time-to-first-pizza:arrive-and-find-pizza-start'); await enterAndFindPizza(); performance.mark('time-to-first-pizza:arrive-and-find-pizza-end'); performance.mark('time-to-first-pizza:eat-pizza-start'); await eatPizza(); performance.mark('time-to-first-pizza:eat-pizza-end'); If we wrote typical journey to this event in code, it might look something like this with performance markings: // Overall time to first pizza performance.measure('time-to-first-pizza', 'time-to-first-pizza:travel-start', 'time-to-first-pizza:eat-pizza-end'); // Or Measure time to travel to the pizza place performance.measure('time-to-travel-to-pizza', 'time-to-first-pizza:travel-start', 'time-to-first-pizza:travel-end'); }
  12. Web Performance is about User Experience People's attention spans are

    diminishing, we become more impatient when it comes to technology, we expect things to load fast, we expect things to respond to us instantly, and we get frustrated when we lose our focus due to content popping in.
  13. Web Performance is about User Experience Core Web Vitals and

    Web Performance at large have been proven to correlate with business KPIs, whether it's conversion, bounce rate, or Average Order Value.
  14. Data-driven approach to web performance led to A 31% improvement

    in LCP increased sales by 8% Vodafone redBus improved their website's Interaction to a 20% reduction in user site issues and Next Paint (INP) and increased sales by 7% conversion rate of prospect visits with shopping intent improving 60% over the same period. RedBus T-Mobile Plenty of other case studies can be found at: Web.dev Case Studies WPOStats
  15. Downtime Vs Slowtime 1 Akamai found that visitors may be

    more likely to permanently abandon slow sites than unavailable sites 2 Slow time could have up to 2X more impact on revenue than downtime, as slow time is more common. Downtime vs Slowtime from Speedcurve 3 Slow and frustrating experiences can lead to damaged brand perception and loss of trust.
  16. Marketing Campaigns not reaching their potential Business spend a fortune

    when it comes to marketing, for the user possibly getting no where because poor User Experience after loading the site has lead the user to leave the session and lost a potential marketing ad conversion.
  17. Core Web Vitals are considered in Search Rankings Google does

    tell us that Passing Core Web Vitals metrics are apart of the Page Experience Ranking Signal which is used when ranking pages in search results. This tells focusing on improving the User Experience of potential customers is what is important which can lead to better search ranking.
  18. The Web is getting heavier Mobile +10%, Desktop +15% Increase

    between May 2025 - March 2026 https://bsky.app/profile/tkadlec.bsky.social/post/3mhxwzlsqhc2b
  19. Chrome User Experience Report (CrUX) Google collects data from real

    user experience using Chrome (non-iOS) browsers which collects information on device type, navigation types and performance metrics including Core Web Vitals. For sites with a larger number of users this can provide insights in how your site is performing and even your business competitors site is performing. Open Lightbox
  20. How to Access CrUX data 1 Via Chrome Performance Panel

    in Dev Tools for the current page/origin to see current data 2 Via cruxvis.withgoogle.com to see a history of CrUX data over 40 weeks 3 Via the CrUX API for either History or current data for your own dashboards
  21. Real User Monitoring Tools (RUM) RUM Tools can provide even

    more meaningfully information including in the last year cross browser support for LCP and INP. Some of these RUM tools can even provide information in which element was the target of a particular performance issue helping you diagnose and fix the performance issues.
  22. import {onCLS, onINP, onLCP} from 'web-vitals/attribution'; Web Vitals JS function

    sendToGoogleAnalytics({name, delta, value, id, attribution}) { const eventParams = { // Built-in params: // Custom params: metric_id: id, // Needed to aggregate events. metric_value: value, // Optional. metric_delta: delta, // Optional. }; switch (name) { case 'CLS': eventParams.debug_target = attribution.largestShiftTarget; break; case 'INP': eventParams.debug_target = attribution.interactionTarget; break; case 'LCP': eventParams.debug_target = attribution.element; break; } If you don't have RUM, the Web Vitals JS Library by the Google team can help you measure CWV and send the data to your own servers or analytics platforms. } gtag('event', name, eventParams); onCLS(sendToGoogleAnalytics); onINP(sendToGoogleAnalytics); onLCP(sendToGoogleAnalytics);
  23. In the Lab Chrome Performance Panel Inside the Chrome Performance

    Panel, even if the page doesn't have CrUX data, it can still provide insights into how you experienced performance on all three metrics, including what elements were involved. Open Lightbox
  24. In the Lab Chrome Performance Panel via a Recording Inside

    the Performance Panel you can record a reload or user interactions to help find performance bottlenecks and what triggered them. Open Lightbox
  25. In the Lab Lighthouse Insights Last year Google updated the

    Lighthouse Performance report to have more meaningful insights into performance during load. These insights can also be found in the Chrome DevTools Performance panel. Open Lightbox
  26. Long Animation Frames (LoAFs) The LoAF API can help us

    identify the work under the hood including what top level scripts ran and why, including third party scripts. Time until First Pizza Bite Order Processing Pizza Cooking 🤷‍♂️ Delivery Time
  27. What We Found! Within a day it identified maps scripts

    were creating 18 seconds of LoAFs, on investigation we found this was being caused by an analytics tool triggering large query selectors. Also, we used it to show how a few third parties like analytics, were already taking around 100ms off every click interaction.
  28. Fixing LCP Priority Of Resources When the LCP element is

    a image, it is important to ensure that the browser can find the LCP resource as soon as possible. Make sure LCP element is discoverable in the initial HTML and not lazy loaded or added via Javascript. Use fetchpriority='high' on the LCP element or use preload link in the head. Lower the priority of any competing images which may not be visible to users.
  29. Fixing LCP Optimise the LCP element Once the browser has

    found and requested the LCP element, the next part is improving the resource load this could be image optimisation or font optimisation. Looking how browsers choose the right image to load with srcset, dpr, and sizes | Iankduffy Use Modern Image Formats like Webp and Avif Responsive Images to load appropriately sized images based on size and DPR Font Optimisation to ensure the font is loaded as quickly as possible Open Lightbox
  30. Fixing INP Break up long tasks via yielding Long tasks

    that are looping over a large number of items can block the main thread, stopping user interactions. By yielding we can unblock the browser and allow for smoother interactions. Recommend yielding before doing analytics event pushes. function yieldToMain() { if (window?.scheduler && window?.scheduler?.yield) { // Use the scheduler API to yield control back to the browser return scheduler.yield(); } return new Promise(resolve => { setTimeout(resolve, 0); }); } async function processItems(items) { for (let i = 0; i < items.length; i++) { // Process the item console.log(items[i]); } } // Yield control to the browser every 100 items if (i % 100 === 0) { await yieldToMain(); }
  31. Fixing INP Understand Damage of Third Party Scripts Third party

    scripts can have serious impact on both page load and user interacting with the page. If these scripts are blocking the main thread it means the user is blocked from completing their aim. Open Lightbox
  32. Fixing INP Modern Browser APIs In the last decade the

    web has changed so much, we now have new APIs such as native lazy loading, CSS scroll snap, dialog element and even the popover API to create mobile menus with no Javascript. Building Mobile Menu with the Popover API| Iankduffy 1/6
  33. Fixing INP Avoid Layout Thrashing Layout thrashing happens when you

    repeatedly update the styles of an element and then read its styles, which cause slow calculations slowing interactions. function resizeAllParagraphsToMatchBlockWidth () { // Puts the browser into a read-write-read-write cycle. for (let i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = box.offsetWidth + "px"; } }
  34. Fixing CLS Add Width and Height to img and source

    elements <picture> <!-- Desktop image --> <source width='1200' height='900' media="(min-width: 1024px)" /> <!-- Tablet Image --> <source width='800' height='600' media="(min-width: 600px)" /> <!-- Mobile Image at 1/1 aspect ratio --> <img width='600' height='600' /> </picture> By adding width and height attributes to img and sources in picture elements, with a bit of CSS the browser can reserve the space needed for the image, avoiding layout shifts after the image loads. Handling Layout shift with img and picture tag | Iankduffy img { width: 100%; height: auto; }
  35. Fixing CLS Reserve space for dynamic content loaded in For

    content that will be added to the page via Javascript after load, it's best to reserve space to avoid the user experiencing layout shifts that could lead to user misclicking and being navigated of the page.