Skip to Main Content Skip Table of Content

How to identify & fix Core Web Vitals issues?

In this Case study of my website, I am going to show you how I identify and fix the Core Web Vitals reported on the Page Speed Insights - field data. You will learn what mistakes I made and you can avoid

Pass Core Web Vitals
A huge Thank you to Massimo Villa for the corrections and for giving me more insights. Much appreciate it.

Keywords to remember

  1. Chrome User Experience Report (CrUX).
  2. Page Speed Insights (PSI)
  3. Core Web Vitals (CWV)
  4. Largest Contentful paint (LCP)
  5. Cumulative Layout Shift (CLS)
  6. First Contentful Paint (FCP).
  7. Time To First Byte (TTFB).
I noticed my Core Web Vitals (CWV) failing in June. Whatever optimization I have learned in the past few years, I have applied everything & from there, I have learned a lot and wanted to share with you.Want to know How I pass the Core Web Vitals Assessment? Just follow along, and you will learn how I did it and how I made mistakes so you can take precautions and never do it. 

Chrome UX Report (CrUX)

The Chrome User Experience Report (CrUX) provides user experience metrics for how real-world Chrome users experience popular destinations on the web.
You can find my latest website CrUX data here.Latest CrUX data for

First Contentful Paint (FCP) –

First Contentful paint Performance report from Chrome User experience

Larget Contentful Paint (LCP)

Largest Contentful Paint Performance report from Chrome User experience

Cumulative Layout Shift (CLS)

Cumulative Layout Shift Performance report from Chrome User experienceIf you have CrUX data/field data and wanted to access it. You can do it in multiple ways – As you can see from the picture below I have no issue with Google Search Console – Core Web Vitals and Page experience report but the Page Speed Insights (PSI) – field data is telling me otherwise because field data in PSI update regularly.
Difference between Field Data in Page Speed Insights (PSI) and CrUX dataset on BigQuery is that PSI’s data is updated daily, while the BigQuery dataset is updated monthly and limited to origin-level data. Both data sources represent trailing 28-day periods.

Google Search Console Report

Core Web Vitals Report

Google Search Console Report suggest there is no Core Web Vitals issue

Page Experience Report

Page Experience Report

PSI – Field data

I have failed the Page Speed Insights assassement on 26 January 2023

Reasons behind the failure of field data in PSI


To improve my FCP & LCP performance, I inline web vitals JS initiator (that initiates web vitals js libraries) and lite-youtube js (lightweight YouTube embedded) to the footer. This way my LCP image (Featured image) loads earlier in the waterfall chart but when I implement this method. In a few days, the score is getting worse because 2 JavaScripts have to execute earlier.


I tried to revamp my blog post design to do so I set up a Maintenance page so that I can safely create the page. While in maintenance mode all the users are hitting the non-optimize page and that page has the code snippets that handle preloading the stylesheets that I forget to generate Critical CSS which leads to Flash of Unstyled Content (FOUC) because of this my CLS score suddenly spikes and out of control.


I didn’t realize hosting an LCP image on image CDN (without custom domain functionalities) is a bad idea when I first set it up for 2 to 3 days there was no issue and I did not see any effects with my LCP score later the score started to degrade from 1.8sec to 2.7sec (see the image above).

How did I identify and fix the issue?

To identify the real issues, I started using Real User Monitoring (RUM) service to monitor my Core Web Vitals performance daily. First, I used Web Vitals JS libraries but turns out it is very expensive for me so I switch to Cloudflare Web analytics which is free to pinpoint the issues that Lab data could not.

What is Real User Experience (RUM)?

Real user monitoring (RUM) tracks and measures the end-user experience in an application, including how long it takes for elements on a web page to load, whether a page has errors, and how long AJAX and HTTP requests take.You can also use RUM to better understand how your users interact with your websites, giving you valuable insights on how to improve your sites and deliver value to your customers.
If you wanted to know why RUM is so important. You can learn more from the New Relic article.Many 3rd parties services offer RUM solutions to help you gather real data from real users and these are the two services I use:

Web Vitals JS

Watch the video above on how to set up web vitals JS (Tutorial I use previously to monitor).
When I start collecting the RUM data. I know exactly the issues I have, & opportunities to improve my web performance like-
  1. Which selectors cause the layout shift,
  2. Whether an image or heading is the LCP.


Data studio show the highest Metric values by debug target for LCP
Data studio shows the highest Metric values by debug target for LCP


Data studio shows the highest Matric values by debug target for CLSWith these insights from the web vitals JS libraries and a combination of lab data testing tools. Identifying, analyzing & fixing the issues is so much easier compared to those who do not set up any RUM solution.
The web vitals JS libraries I was using before didn’t support Time To First Byte (TTFB), First Contentful Paint (FCP), and Interaction Next Paint (INP) metrics. If you want an advanced version that supports all the metrics above, you can follow Tony McCreath’s article on Web Site Advantage Core Web Vitals Tracking.

Cloudflare’s Browser Insights

If you’re using Cloudflare you can use Cloudflare’s Browser insights to collect RUM data. I set it up for more than a week after I remove the web vitals JS and have had similar results. You can automatically inject the JS or you can manually setup which is so much better compared to the web vitals JS libraries I previously used.


LCP performance from Cloudflare's Browsers insights


CLS performance from Cloudflare's Browsers insightsAfter you gather all the data from real users, what are the things we can do? The best thing to do is to fix the issues and later we can compare them with the old data.

Fixes & Comparisons-

You can also see the latest version of my Page Speed Insights’ Field-data Page Speed Insights's field-data for 04th May

Largest Contentful Paint (LCP)


To improve the LCP metric:
  1. I use Cloudflare Images (paid) with the help of Offload, Store, Resize & Optimize with Cloudflare Images plugin to integrate and deliver my image in next-gen image format.
  2. To discover the image earlier by the browsers, I use the rel=”preload” hints to preload my feature image & using the fetch priorities hint to give the image higher priorities boost. (optional)

Comparisons of Lab data and PSI-field data

Before (Cloudinary) add an unnecessary connection time (around 600ms) to the image (number 6) After (Cloudflare images with sub-domain) no unnecessary connection is added to the image.Webpage test waterfall after the image is been self-hosted and make the image loads earlierBefore (PSI- field data)2.7 sec Largest Contentful paint which is not good Core Web VitalsAfter (PSI – Field data)After the Largest contentful paint fixes

Cumulative Layout Shift


To fix the CLS issues:
  1. I included the latest CSS in the critical CSS process.
  2. I preloaded my self-hosted fonts.

Comparisons of PSI-field data

Before0.11 score on Layout Shift which is bad, it means the content will be move around when the page load which is bad User ExpereinceAfterAfter the fix there is no Cummulative layout detected

First Contentful Paint


To improve my FCP performance:
  1. I remove most of the redundant CSS rules like the !important CSS, and duplicate style.
  2. Remove the unnecessary preconnect call by the Lite-YouTube embedded JS.
  3. I start Removing unused CSS from all my posts.

initImagePlaceholder() {
    LiteYTEmbed.addPrefetch('preconnect', '');
    const posterUrlWebp = `${this.videoId}/${this.posterQuality}.webp`;
    const posterUrlJpeg = `${this.videoId}/${this.posterQuality}.jpg`;
    this.domRefImg.fallback.loading = this.posterLoading;
    this.domRefImg.webp.srcset = posterUrlWebp;
    this.domRefImg.jpeg.srcset = posterUrlJpeg;
    this.domRefImg.fallback.src = posterUrlJpeg;
    this.domRefImg.fallback.setAttribute('aria-label', `${this.videoPlay}: ${this.videoTitle}`);
    this.domRefImg?.fallback?.setAttribute('alt', `${this.videoPlay}: ${this.videoTitle}`);

        // After

 initImagePlaceholder() {        
    const posterUrlWebp = `${this.videoId}/${this.posterQuality}.webp`;
    const posterUrlJpeg = `${this.videoId}/${this.posterQuality}.jpg`;
    this.domRefImg.fallback.loading = this.posterLoading;
    this.domRefImg.webp.srcset = posterUrlWebp;
    this.domRefImg.jpeg.srcset = posterUrlJpeg;
    this.domRefImg.fallback.src = posterUrlJpeg;
    this.domRefImg.fallback.setAttribute('aria-label', `${this.videoPlay}: ${this.videoTitle}`);
    this.domRefImg?.fallback?.setAttribute('alt', `${this.videoPlay}: ${this.videoTitle}`);



FCP recorded on 26th August
First Contentful Paint (FCP) – 2.4s recorded on 26th August
After2 sec First contentful paint performance recorded after the fixThis is not happening once, it happens more than twice, from there I learned a lot, here are the tips and caution you need.


  1. If your featured image is a background image, consider preloading the image so browsers discover it earlier.
  2. Reduce your inline CSS size. Unnecessary inlining of CSS can lead to increases in Document/ HTML size which can hurt your Mobile users. Inline assets (CSS, JS, and images) cannot cache.
  3. Do not use the rel preload hints to preload all the resources unnecessarily. Use it sparingly.


  1. When fixing Core Web Vitals issues, people miss the Server Response time or Time for First Byte (TTFB) metrics because it is notable metrics but if you see it properly TTFB plays a huge role (but tricky to debug), if it fluctuates a bit it can affect your Largest Contentful Paint (LCP), and First Contentful Paint (FCP) metrics even because TTFB is the first metric after that FCP and LCP come after.Here is the tutorial on how to optimize the Time To First Byte Metric from the
  2. Serving and delivering LCP images from different origins is a bad practice because it unnecessarily added time spent downloading the LCP image. Always, self-hosted or use image CDN that supports custom domain or sub-domain functionalities. With Cloudinary- Web page test
  3. If you’re changing/updating your website style on a specific page just make sure you regenerate Critical CSS on that page or if you’re updating a site-wide, consider regenerating critical CSS for all the pages. This will make sure it flushes all the old critical CSS and regenerate new critical CSS and it will be included in the new process.
  4. Unnecessary, do not inline your CSS and JS for the sake of page speed score. I saw lots of tutorials recommending this terrible approach. If you’re using Elementor, do not set the CSS Print Method to Internal Embedding in Elementor > Settings > Advanced because It unnecessarily inlines your frontend CSS which can be over 30KB (Brotli compression) when Improved CSS loading experiments are turned off.
  5. Try to reduce 3rd parties calls on the initial page load as much as possible.
When I requested Massimo Villa from the altsetup to review my article. He raised an interesting question
Since you use Elementor on your site, why do you use Lite-YouTube embeded instead of the Native Facade (“overlay”) feature replacing YouTube player with local image placeholder?
The answer is quite simple-
  1. No dependencies
  2. Lightweight

What are the alternatives?

If my blog design has lots of features like motion effects ( sticky header, parallax effects, Table of Content, etc) then there is no point in using the alternative solution.As you can see from my article, my design is basic and there is no point in adding all the bells and whistles (features).  

lite-Youtube embed VS Elementor Video

My website is built with Elementor and it has its own video widget that supports YouTube, Vimeo, Dailymotion & Self-Hosted Video, and other amazing features like Lazy-loading & facade (“image overlay”) as Massimo Villa suggested.YouTube WidgetElementor Video widget settingsImage overlay (Facade)Elementor video widget's Overlay featureTo use all the features I will end up loading over 80KB of JS which sometimes is unnecessary for me whereas lite-youtube JS only loads 3.3KB which is substantially lower and have zero dependencies on jQuery.If you want to use lite-youtube embed on your website, you can download the widget from my store.Lite YouTube embedded JS file size

Image CDN 

Here are some of the 3rd parties image CDN services that offer custom Domain/sub-domain functionalities like
  1. Webp Express plugin preloading <picture> tag is trickier than the <img> tag but it will serve your image in webp.
  2. Upgrade to Cloudflare Pro if you’re using the free plan.
  3. Shortpixel Adaptive AI
  4. Bunny Optimizer
  5. Imgix
  6. Optimole
  7. Cloudflare images

LuckyWP Table of Contents

Elementor has a Table of Content widget which is super flexible compared to the one I am using but has the situation as lite-youtube embedded jsElementor's Table of Content widgetsFor an alternative solution, I use the LuckyWP Table of Contents and setup to automatically insert headings not via the shortcode method. This plugin is not dependent on jQuery.Lucky WP Table of Content settingsHere are some of the plugins I usually recommend and most of them are affiliate links, if you purchase one of them from my links so Thank you for supporting me.

Plugin Recommendations:

All the plugins I recommend below have the feature for generating critical CSS, removing unused CSS, the ability to compress images, CSS and JS, and serving the images in Next-Gen image format automatically such as-
  1. FlyingPress
  2. Wp Rocket
  3. Swift Performance
  4. Perfmatters
  5. Autoptimize + RapidLoad + Critical CSS API + Shortpixel Adaptive AI combined (This is great if you already have Server-side caching & CDN that handle your page level caching & you don’t want any conflict).


  1. Optimizing Largest Contentful Paint- CSSWizardry
  2. A deep dive into optimizing LCP – Google Chrome Developers. (Video)
  3. Web-Vitals JS libraries – Github
  4. Measure and debug performance with Google Analytics 4 and BigQuery-

Deep dive:

  1. Pagespeed Insights – Field Data report vs CrUX
  2. RUM & CrUX difference
  3. Chrome UX report update
  4. Dear WordPress Plugin/Theme Devs, You Don’t Need jQuery by WP Speed Matters.

  5. Highly recommend reading Massimo Villa’s article on how to get 100% in speed tests.


Stop assuming your lab data score is enough for you to pass the Core Web Vitals Assessment that is what I thought and fail twice. So learn it from my mistakeThe best solution is to set up the RUM solution and start identifying the real issue and fixing the problems so your real users do not have to suffer.
Thangjam Kishorchand

Thangjam Kishorchand

Hi there! I'm Kishorchand, and this is my blog where I share my Elementor tips and tricks that I've learned over the past two years. I'm mostly active on Quora and Facebook, and I love experimenting with design trends like variable fonts and dark mode.

Upgrade to Elementor pro Today

Scroll up further to Load all the comments...