Largest Contentful Paint (LCP) is a metric that gauges how fast the main content (largest) of a web page loads and becomes visible to users (in the viewport/above the fold).
Don’t confuse LCP with FCP, which measures the time to render the first element on the page.
- LCP is commonly an image (featured image on a blog post, background hero image), but can also be text (header) or video element.
- It is classified as an official Core Web Vitals metric. Only LCP, INP, and CLS are official metrics that you must pass or fail. Every other metric is a notable metric, something that impacts them.
- LCP is commonly an image (featured image on a blog post, background hero image), but can also be text (header) or video element.
What is a good LCP score?
According to Google, they want you to have your LCP under 2.5 seconds.
They use the 75th percentile to determine where you stand. 75% of the visits/crawls need to meet the “good” threshold for you to get that classification.
You really want to aim for lower than 2.5 seconds because Google uses throttled 4G for mobile when crawling your site. They are purposely measuring your site using a slow connection to ensure users across the board have a good experience, not just those on a fast connection.
How to Measure LCP
There are many different tools you can use to measure LCP. A few of my favorites that I use on a regular basis are PageSpeed Insights (PSI), GTmetrix, and DebugBear.
I really like DebugBear because it has quick and easy labels for things like LCP, preloads, etc. I also like to simply use the “tabs” in the PageSpeed Insights report (example).
I always recommend testing at least three times before looking at the data. This is due to any factors that might influence your first test. Things like cache, network latency, etc., can all influence LCP. Never just rely on one data point.
PSI and Real-User Data
It’s important to understand the difference between lab data and real-user data. Lab data is at the bottom of the report under the “Diagnose performance issues” section. This top section is real-user data. It’s collected over an average of 28 days as users hit your site and are recorded for Core Web Vitals. Or rather, they are the only metrics that really matter. But remember, it’s always delayed (example).
Also, pay attention to this tab to see if there is enough data for your individual URL. Otherwise, the origin (average) of your site is shown.
Improving LCP
Server Response Time (TTFB)
One of the most important factors to improve LCP is having low TTFB (server response time). To improvethis, we recommend the following:
- Using a high-quality hosting provider (powerful servers, networking, Brotli compression, DNS, etc.)
- Have a cache solution in place (server-level, plugin).
- When enabling cache on a server in the same geographical location: LCP decrease of 20.67%. ????
- Utilize edge cache if you’re serving global visitors (Cloudflare).
- Without edge cache: LCP increase of 140.1%. ????
Check out our previous presentation on TTFB, which discusses everything above. If you skip this part, you will most likely struggle to achieve lower LCP.
JS and CSS Minification
We are going to start with some of the easiest things you can do to first to improve LCP. The first is to simply enable JS and CSS minification. This is the process of removing unnecessary characters from your code (whitespace, comments, shortening function and variable names, etc.), along with additional markup cleanup.
We have a JS and CSS minification feature in our Perfmatters plugin. We have exclusions and filters for fine-tuning things.
Reduce Unused CSS
Next, we have unused CSS. Many themes and plugins simply load their entire stylesheets everywhere. Because of this, you’ll have a lot of unused code.
You can clean this up using the Remove Unused CSS feature in our Perfmatters plugin. We have exclusions and filters for fine-tuning things.
In our testing, we’ve seen an average decrease in LCP of 19.66%. ????
Reduce Unused Javascript
Next, we have unused JS. Like with unused CSS, many themes and plugins simply load their JS everywhere. Same with third-party scripts. Because of this, you’ll have a lot of unused code.
You can use the Delay JavaScript feature in our Perfmatters plugin. Delay scripts not needed right away on user interaction. We have exclusions and filters for fine-tuning things.
Eliminate Render-Blocking Resources
The next thing you can do is to fix any render-blocking resources. Most CSS and JS is naturally render- blocking. There are a couple of ways you can fix this. Note: jQuery usually can’t be optimized.
First off, using the Remove Unused CSS and Delay JS features will automatically fix the render-blocking issues on those assets. That’s why I recommend focusing on unused CSS and JS first.
Second, you can defer JavaScript in our Perfmatters plugin. JS is downloaded during HTML parsing and will execute after the page has finished loading. We have exclusions and filters for fine-tuning things.
Ensure Text Remains Visible During Webfont Load
Next is the “ensure text remains visible during webfont load” warning. Modern browsers wait until the font has fully downloaded to display it. This can create a flash, otherwise known as FOIT (‘flash of invisible text’). That also means it could hold up LCP. To fix this, we recommend doing a few things (can be done in Perfmatters):
- First off, you should host your Google Fonts locally for faster performance.
- Second, you should add swap to your fonts. This means there is a temporary fallback to system fonts.
- Third, you should preload the fonts to minimize any CLS. Yes, sounds counter-intuitive.
- (Optional) Fourth, you can async your Google font CSS to fix the render-blocking issue. I recommend testing on and off due to CLS.
Avoid Chaining Critical Requests
Next is the “avoid chaining critical requests” warning. As Google states, “the greater the length of the chains and the larger the download sizes, the more significant the impact on page load performance.” This will impact LCP.
The good news is that the other things we’ve done, such as removing unused CSS, delaying JS, deferring JS, preloading local fonts, etc., will all reduce critical requests. So by the time you get to this point, you probably won’t have much left to do.
Avoid Enormous Network Payloads
Next is the “avoid enormous network payloads” warning. Essentially, this just means that any large resource (JS, CSS, image, font, etc.) is going to affect the performance of your site, and this can impact your LCP.
This is especially important for any assets that load above the fold. Every KB matters. A few common examples:
- Featured images or hero background images that aren’t sized or optimized properly.
- Oversized fonts. Many themes and plugins that don’t take performance into consideration might load an entire font icon library sitewide when only 1% of the library is being used (Font Awesome, Dashicons, etc.)
- Large external JS files.
Tip: I always recommend keeping individual images at 100 KB or less, especially for mobile. You can use an image optimization plugin like ShortPixel or Imagify. The free Squoosh tool from Google is also great for fine- tuning individual images. Use WebP/AVIF formats if needed.
Speaking of network payload sizes, it’s very important that you are lazy loading every single image possible below the fold. We have extensive lazy loading options in our Perfmatters plugin and filters to fine-tune things.
- Exclude leading images
- Lazy load iframes and videos (YouTube preview thumbnail feature)
- Exclusions (individual and parent selectors)
- Threshold (viewport) settings
Largest Contentful Paint Element
Next is the Largest Contentful Paint element. You will always have LCP, whether it’s an image, text, etc. You’re not trying to fix everything but improve it. I like to think of optimizing LCP in two parts. The first is everything else that might impact it (what we just went over), and the second is the LCP element itself.
The first thing we recommend doing is enabling is to enable preload critical images in our Perfmatters plugin. That will preload images, starting with those first in the HTML. Essentially this forces the image to load as soon as possible, moving it to the top of the waterfall.
We have extensive filters for preloads. You can exclude individual images, exclude where certain preloads are added, and also exclusions by parent classes. For example, let’s say you have a mega menu running with a few images that might still be in the viewport or HTML. You could exclude their parent class. You can really fine-tune what is and isn’t preloaded as needed.
What about background hero images in CSS? You can still preload these manually if needed using our individual preload feature. You can choose a location for where you want that image to load and separate preloads per device (mobile/desktop) if needed.
Another alternative or something to use alongside preloading is fetch priority. This is a hint to tell the browser that the resource should have. Think of it like preloading, but less powerful.
The latest versions of WordPress actually add fetch automatically. However, we’ve found this isn’t very accurate, and many times it will add fetch to the wrong image (below the fold). So we added a Disable Core Fetch option in Perfmatters. We might remove this if they improve core later down the road.
You can then fine-tune things better in Perfmatters.
Add fetch on <img>, <link>, and <script> tags and assign a priority of high or low. You can also use parent selectors if something doesn’t have a unique class on it.
After you’ve preloaded your LCP image, or utilized fetch priority, you want to make sure they are excluded from lazy loading. You never want to lazy loading your LCP element.
The good news is that we automatically exclude images from lazy loading that are using our preload critical image feature and fetch priority.
Another little trick I’ve seen folks doing is purposely making the LCP element text/header. You don’t always necessarily need a large image above the fold. But remember, an image is only part of what impacts LCP.
Disable Plugins or JS/CSS
Another way to improve LCP is to ensure that the scripts and CSS from plugins and themes aren’t loading where they shouldn’t.
The Script Manager in Perfmatters allows you to disable scripts on a per post/page basis or sitewide basis. And MU mode lets you disable entire plugins from running (MySQL queries, inline code, etc.).
This can be very powerful, but it is also a more advanced feature. For many users just starting out, we recommend starting with the other optimizations first (which are more automated) and then fine-tuning with the Script Manager at the end.
Speculative Loading Techniques
Not everything is about final page speed scores or tests. You always need to think about the user experience and perceived performance (how fast a site feels, quick to navigate, etc.). There are different speculative loading mechanisms you can use. And technically, this will help improve LCP for the user.
1. Preconnect allows the browser to set up early connections before an HTTP request, eliminating round-trip latency and saving time for users (DNS + TCP + TLS). This is great for third-party requests that might not already be delayed, or a CDN URL (cdn.domain.com). We have a preconnect feature in Perfmatters.
2. Prefetch lets you automatically fetch most of the resources required to render a URL in the background after a user hovers over a link. This results in faster load times and navigation. We have our Instant Page feature in Perfmatters that enables this.
3. Prerender goes a step further than prefetch, and actually renders the content ready to be shown after a user hovers over a link. This results in pretty much instant load times. The new and free Speculative Loading plugin from the WordPress performance team enables this for you. Highly recommend it!
Prefetch has more browser support at the moment, but prerender is also more powerful. You shouldn’t really use both, so it depends on what is most important to you. Is most of your traffic already from Chrome? If so, prerender might be the way to go.
Trying to Improve Your Core Web Vitals?
This article is part of a larger series, called Vitality, where we tackle notable metrics and Core Web Vitals!
Quick Summary of LCP
- Server response time (TTFB), including HTML doc size has a huge impact on LCP. The further the distance, the more it matters. Don’t skip this! See previous video on TTFB, caching, etc.
- Get LCP under 2.5 seconds or less. Remember, Google uses throttled 4G mobile connection.
- Minify your JS and CSS.
- Remove unused CSS.
- Delay unused JS until it’s needed on user interaction.
- Defer JS to help eliminate render-blocking resources and avoid chaining critical requests.
- Host your fonts locally, add swap, and preload them.
- Decrease any large resources. Image optimization, fixing large font libraries, etc.
- Lazy load any images below the fold.
- Preload your LCP image and make sure to exclude images above the fold from lazy loading. You can also use fetch priority.
- Disable JS/CSS and or entire plugins from loading where they shouldn’t with a tool like the Script Manager.
- Take advantage of speculative loading techniques.