{"id":1001,"date":"2026-10-10T10:00:00","date_gmt":"2026-10-10T10:00:00","guid":{"rendered":"https:\/\/kryloweb.com\/blog\/?p=1001"},"modified":"2026-10-29T06:58:32","modified_gmt":"2026-10-29T06:58:32","slug":"how-to-improve-core-web-vitals","status":"publish","type":"post","link":"https:\/\/kryloweb.com\/blog\/how-to-improve-core-web-vitals\/","title":{"rendered":"How to Improve Core Web Vitals: What Worked on Our Own Site"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Core Web Vitals are three measurements Google uses to judge how a page feels to use: how fast the main content appears (Largest Contentful Paint, good under 2.5 seconds), how fast the page responds to a tap or click (Interaction to Next Paint, good under 200 milliseconds), and how much the layout jumps while it loads (Cumulative Layout Shift, good under 0.1). How to improve Core Web Vitals comes down to one method: find out which of the three is failing, find the file or script that causes it, and fix that, one change at a time, measuring after each.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the whole method. The rest of this post is what it looked like on a real site: ours. The homepage of kryloweb.com runs a 3D particle scene, which is about as heavy as a business website gets. When we first ran it through Google&#8217;s PageSpeed Insights, the desktop performance score was 64 and Total Blocking Time was over 20 seconds. After the work below, a Lighthouse test with the same desktop settings scores 99, with 40 milliseconds of blocking time, and the scene looks the same.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2400\" height=\"1074\" src=\"https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1.jpg\" alt=\"How to improve Core Web Vitals: before and after PageSpeed desktop score, Total Blocking Time and main thread work on kryloweb.com\" class=\"wp-image-3076\" srcset=\"https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1.jpg 2400w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1-300x134.jpg 300w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1-1024x458.jpg 1024w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1-768x344.jpg 768w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1-1536x687.jpg 1536w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-before-after-1-2048x916.jpg 2048w\" sizes=\"auto, (max-width: 2400px) 100vw, 2400px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What the three Core Web Vitals measure<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Each metric answers a different question, and each has its own usual causes.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Metric<\/th><th>Question it answers<\/th><th>Good<\/th><th>Poor<\/th><th>Usual causes when it fails<\/th><\/tr><\/thead><tbody><tr><td>Largest Contentful Paint (LCP)<\/td><td>How long until the main content is visible?<\/td><td>Under 2.5 s<\/td><td>Over 4 s<\/td><td>Large images, slow server, render-blocking styles and fonts<\/td><\/tr><tr><td>Interaction to Next Paint (INP)<\/td><td>How quickly does the page react when you tap or click?<\/td><td>Under 200 ms<\/td><td>Over 500 ms<\/td><td>Long JavaScript tasks, heavy third-party scripts<\/td><\/tr><tr><td>Cumulative Layout Shift (CLS)<\/td><td>Does the page jump around while loading?<\/td><td>Under 0.1<\/td><td>Over 0.25<\/td><td>Images without set sizes, late banners, font swaps<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Google judges each one at the 75th percentile of real visits, so three quarters of your visitors need a good experience for the page to pass.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2400\" height=\"1282\" src=\"https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1.jpg\" alt=\"Core Web Vitals thresholds for LCP, INP and CLS\" class=\"wp-image-3077\" srcset=\"https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1.jpg 2400w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1-300x160.jpg 300w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1-1024x547.jpg 1024w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1-768x410.jpg 768w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1-1536x820.jpg 1536w, https:\/\/kryloweb.com\/blog\/wp-content\/uploads\/2026\/10\/improve-core-web-vitals-thresholds-1-2048x1094.jpg 2048w\" sizes=\"auto, (max-width: 2400px) 100vw, 2400px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Field data and lab data are not the same thing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This tripped us up at first, and it trips up most site owners. PageSpeed Insights shows two kinds of numbers on the same screen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Field data comes from real Chrome users over the last 28 days. It is what Google uses for search, and it appears only once a page has enough traffic. A new site often has none.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lab data is a single test run on one of Google&#8217;s machines, with a simulated phone and network. It gives the performance score out of 100 and lists what slowed the page down. It is useful for finding causes, but it is one machine on one day.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our 64 was a lab score. That matters for what follows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The problem: a test machine without a graphics card<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our blocking time was more than 20 seconds, which made no sense on a computer with a normal graphics chip, where the 3D scene ran smoothly. The answer was in the test machine. PageSpeed runs on servers without a graphics card, so the browser draws 3D graphics in software on the main processor. Our scene, which takes a graphics chip a few milliseconds, took the processor seconds, and every second counted as blocking time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Real visitors with a graphics chip never saw that cost. A visitor on a weak phone could have seen some of it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How we improved Core Web Vitals, one fix at a time<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Skip the 3D scene when there is no real graphics chip<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before loading the 3D code at all, the page now asks the browser whether it would draw in software. If it would, the page shows a painted version of the sky instead and never downloads the 3D files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a local Lighthouse test that imitates the PageSpeed machine, Total Blocking Time fell from 540 milliseconds to 0, and main thread work from 8.9 seconds to 1.7 seconds.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Load the heavy code after the page is usable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The 3D files now load when the browser is idle, after the text and buttons are already on screen. The visitor can read and scroll first; the scene arrives a moment later.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Remove the styles that block the first paint<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The page used to load its stylesheet as a separate file, and the browser waits for that file before it draws anything. The styles are now written into each page, so there is nothing to wait for. The site&#8217;s CSS is small enough for this to be the faster choice. On a site with a large stylesheet it might not be.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Stop redrawing things nobody can see<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some fixes came from Safari, which was slower than Chrome on the same machine. We found a full-page grain texture that the browser blended over everything on every frame, a gradient that was regenerated as a new image every frame, and hidden sections that were still being composited. Removing the grain, moving the gradient instead of redrawing it, and fully hiding inactive sections made scrolling noticeably smoother in Safari&#8217;s engine.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5. Lower quality only when the device really needs it<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The scene can reduce its own detail on slow devices. Our first version lowered quality whenever the frame rate dropped below 45 a second. That backfired on Macs and iPhones in Low Power Mode, which cap every page at 30 frames a second however light it is, and the scene dropped to its lowest quality for no reason. It now times how long a frame takes to draw before deciding, so a capped browser keeps full quality and a genuinely slow device still steps down.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What didn&#8217;t work<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Four things we tried first and had to change.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Trusting our own test machine.<\/strong> Our first local tests scored the site far lower than it deserved. The antivirus on the computer running the tests was adding about 900 KB of its own scripts and styles to every page, and Lighthouse counted them against us. Once we blocked those addresses in the test, the mobile score of our services page went from 65 to 90. If your local scores look worse than PageSpeed Insights, check the network list for files that don&#8217;t come from your site.<\/li>\n\n\n\n<li><strong>Trusting the browser&#8217;s own warning.<\/strong> Browsers can report when 3D would be slow, but the software renderer used on test machines passed that check. We had to read the renderer&#8217;s name as well.<\/li>\n\n\n\n<li><strong>Blurring smaller areas to save work.<\/strong> Moving a blur effect from the whole screen to just the text blocks looked cheaper, but Safari drew a stray coloured line at the edge of each blurred box. We put the blur back on the full screen.<\/li>\n\n\n\n<li><strong>Averaging frame times.<\/strong> The first version averaged frame times to decide whether a device was slow, and a few stutters while the page loaded skewed the average. Using the middle value instead fixed it.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The lesson from all four: measure on the browsers your visitors use, and keep each change small enough to undo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where we are now, and what is left<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On our latest desktop test the homepage scores 99 for performance, with Largest Contentful Paint at 0.8 seconds, Total Blocking Time at 40 milliseconds and almost no layout shift. Our services page, which has no 3D scene, scores 100 on desktop and 90 on mobile.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The homepage on mobile is not finished. Lighthouse&#8217;s mobile test slows the processor to imitate a mid-range phone, and there the homepage scored 56 and 71 in two runs, with blocking time of 590 to 740 milliseconds. The cause is the 3D scene itself: on a slow processor, even a graphics chip can&#8217;t hide the work of setting it up. Our next step is to start the scene later on small screens, or show the painted sky on phones with weak processors. We will update this post when it is done.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One caution about comparing numbers: these runs used Lighthouse 12 on our own machine with Google&#8217;s settings, which is close to PageSpeed Insights but not identical. Scores move several points between runs, especially on mobile, so look at the trend over several tests.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A checklist for your own site<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open PageSpeed Insights, test your homepage and your most visited page, and note which of the three metrics fail, on mobile and desktop separately.<\/li>\n\n\n\n<li>If LCP fails, find the largest element in the report. It is usually an image: resize it, serve it as WebP or AVIF, and don&#8217;t lazy-load it.<\/li>\n\n\n\n<li>If INP or Total Blocking Time fails, open the list of long tasks and look for the script behind each one. Third-party tags and chat widgets are common culprits.<\/li>\n\n\n\n<li>If CLS fails, give every image and embed a width and height, and reserve space for anything that appears late, such as a cookie banner.<\/li>\n\n\n\n<li>Fix one thing, test again, and keep a note of the numbers.<\/li>\n\n\n\n<li>Check Search Console&#8217;s Core Web Vitals report about four weeks later, when field data has caught up.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">For the common causes of slow pages and the fixes for each, see our <a href=\"https:\/\/kryloweb.com\/blog\/website-speed-optimization-guide\/\">website speed optimization guide<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the report points at things you can&#8217;t change yourself, such as theme code or a heavy page builder, that is where a developer helps. We do this work as a <a href=\"https:\/\/kryloweb.com\/website-speed-optimization\">website speed optimization service<\/a>, and the same approach shapes every site we build, including those on <a href=\"https:\/\/kryloweb.com\/astro-website-development\">Astro<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Google, &#8220;Web Vitals&#8221; and &#8220;Interaction to Next Paint (INP)&#8221;, web.dev, for the metric definitions and thresholds.<\/li>\n\n\n\n<li>KRYLOweb&#8217;s own PageSpeed Insights and Lighthouse 12 measurements of kryloweb.com, September and October 2026.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Our homepage runs a 3D scene, and PageSpeed scored it 64 with more than 20 seconds of blocking time. Here is what we changed, what didn&#8217;t work, and how to apply it to your site.<\/p>\n","protected":false},"author":1,"featured_media":2001,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[8,9,10,11],"class_list":["post-1001","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-speed-and-performance","tag-core-web-vitals","tag-page-speed","tag-pagespeed-insights","tag-website-performance"],"_links":{"self":[{"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/posts\/1001","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/comments?post=1001"}],"version-history":[{"count":2,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/posts\/1001\/revisions"}],"predecessor-version":[{"id":3164,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/posts\/1001\/revisions\/3164"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/media\/2001"}],"wp:attachment":[{"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/media?parent=1001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/categories?post=1001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kryloweb.com\/blog\/wp-json\/wp\/v2\/tags?post=1001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}