Measuring Largest Contentful Paint

Updated: 16 September 2020
Measuring Largest Contentful Paint

Largest Contentful Paint (LCP) is a measurement of how long the largest element on the page takes to render. It’s one of several Web Vital metrics that measure how real users perceive the performance of modern web applications. New measurements like Largest Contentful Paint are increasingly important as JavaScript and SPA’s render more content after page load is completed.

Largest Contentful Paint

The Largest Contentful Paint metric works under the assumption that the page is useful to the user once they can see the largest piece of content. It’s an important “core web vital” metric that Google will soon be considering when ranking search results.

LCP is not a single measurement, but a series of measurements. An additional LargestContentfulPaint entry is created every time a new largest element is rendered. The LCP metric can be boiled down to a single value by using the last LargestContentfulPaint entry in a page load. Only image, video and text-containing block level elements can trigger LCP entries.

What constitutes “largest” varies by element type. Image element size is determined by the size of the image as shown on the page. Text-containing element size is the smallest box than encompasses the text itself.

In this contrived example, the largest rendered element is highlighted. Some elements are in the base HTML and rendered right away. Later, JavaScript inserts additional elements:

Largest Contentful Paint Example
Largest Contentful Paint Example. The current LCP element is highlighted in blue.

But what is a good value for Largest Contentful Paint? Helpfully, Google has determined some recommended times using data gathered from the Chrome browser:

Largest Contentful Paint threshold recommendations from Google.
Largest Contentful Paint threshold recommendations from Google.

Largest Contentful Paint API

The Largest Contentful Paint API is a proposed standard to expose largest paint measurements through JavaScript. It is currently supported in Blink-based browsers, such as Chrome, Edge, and Opera. NOTE: As a draft standard, there are occasionally changes to how LCP is determined.

We can test the API’s behavior with a little code:

new PerformanceObserver(entryList => {
    console.log(entryList.getEntries());
}).observe({ type: "largest-contentful-paint", buffered: true });
Basic use of the Largest Contentful Paint API

Note that the buffered: true option returns all entries that occurred before the PerformanceObserver was configured. The sloth example page returns entries like this:

LargestContentfulPaint performance entries
LargestContentfulPaint performance entries

Using the Largest Contentful Paint API In Production

The API example above glossed over two issues that need to be addressed before being used in a production setting.

1. Don’t Measure Pages Loaded In The Background!

Last Contentful Paint should not be measured when the page is loaded in a background tab. The measurement only indicates when the user first brought the tab to the foreground in that case. An additional check prevents measurement of background tabs:

var hiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;

document.addEventListener('visibilitychange', (event) => {
    hiddenTime = Math.min(hiddenTime, event.timeStamp);
}, { once: true });

new PerformanceObserver(entryList => {
    entryList.getEntries().forEach((entry) => {
        if (entry.startTime < hiddenTime) {
            // This entry occurred before the page was hidden
            console.log(entry);
        }
    };
}).observe({ type: "largest-contentful-paint", buffered: true });
Don't measure Largest Contentful Paint in background tabs

2. Largest Contentful Paint API Feature Detection

Not all browsers support the Largest Contentful Paint API. Try/catch is the only reliable way to detect the feature because some browsers throw an exception when the API is used:

try {
    new PerformanceObserver(entryList => {
        console.log(entryList.getEntries());
    })
    // Some browsers throw when 'type' is passed:
    .observe({ type: "largest-contentful-paint", buffered: true });
}
catch (e) {
    // The Largest Contentful Paint API is not supported by this browser
}
Detect Largest Contentful Paint API with try/catch

Largest Contentful Paint API Quirks And Gotchas

The Largest Contentful Paint API is not without its quirks. There are a number of situations that result in surprising behaviors.

LargestContentfulPaint Entries Can “Revert” To Previous Values

Previous LargestContentfulPaint entries can be re-issued if the current “largest element” is removed from the DOM. The last entry returned from entryList.getEntries() has a shorter startTime than the previous entry when this happens:

Largest Contentful Paint reverts on element removal.
Largest Contentful Paint Reverts to former value after element removal.

A Block Element’s Border and Background Do Not Contribute To Its Size

The “largest” element in LargestContentfulPaint entries can be rather un-expected. Often, the visually largest element is not largest according to the LCP size rules. This happens because borders and colored backgrounds are not included in an element’s size calculation. Only the text’s bounding box is used:

Largest Contentful Paint: Unexpected largest element
Largest Contentful Paint: Unexpected "largest" element

User Interaction Stops Further LCP Entries

New LargestContentfulPaint entries are created while content continues to render and the user has not interacted with the page. As soon as the page is clicked or scrolled, LCP measurements are halted. Ironically, users who interact with a slow page out of frustration can hide the actual largest paint:

User Interactions Stop LargestContentfulPaint measurements
User Interactions Stop LargestContentfulPaint measurements

Conclusion

As the above quirks show, Largest Contentful Paint doesn’t always tell the whole story. It is just another tool in the web performance toolbox. When paired with traditional performance measurements and other new ones like Cumulative Layout Shift, a better understanding of your users’ experience can be seen.

Chart page views and the distribution user load time

About Request Metrics

The easiest way to monitor your web performance. Request Metrics records how real users experience your website and shows you simplified metrics and alerting. And at a price that's easy on your budget.