Cloudflare Core Web Vitals, in Plain English
Cloudflare Web Analytics has a Core Web Vitals section. It looks simple: three metrics, colored ratings, a few charts, and a debug table.
But if you do not work with frontend performance every day, it is easy to stare at it and ask the wrong question.
The question is not:
“Is my page fast?”
The better question is:
“Which part of the user experience is hurting: loading, interaction, or layout stability?”
That is what Core Web Vitals are trying to split apart.
The three metrics
Cloudflare shows the same three user-experience metrics Google uses for Core Web Vitals.
LCP: Largest Contentful Paint
LCP measures perceived loading speed.
More specifically, it asks: how long did it take for the largest meaningful piece of content to appear?
On a landing page, that might be the hero image. On a blog post, it might be the headline or main text block. On a catalog page, it might be the main product grid.
If LCP is bad, users feel like the page is slow to become useful.
Common causes:
- oversized hero images
- slow server response
- render-blocking CSS or JavaScript
- web fonts delaying visible text
- lazy-loading the wrong image
- CDN/cache misses
Good LCP work usually starts by finding the actual LCP element. Guessing is dangerous. The bottleneck might be an image, but it might also be text waiting on CSS or a server response.
INP: Interaction to Next Paint
INP measures responsiveness.
It asks: after a user interacts with the page — click, tap, key press — how long does it take before the browser can paint the next visual update?
This replaced the older First Input Delay idea because one early interaction is not enough. A page can load fine and still feel sticky once JavaScript starts doing work.
If INP is bad, users feel like the page is laggy.
Common causes:
- large JavaScript bundles
- long-running event handlers
- expensive client-side rendering
- too much work on the main thread
- slow third-party scripts
- interactions that trigger large DOM updates
For Rails/Hotwire apps, INP can be interesting. You can have a mostly server-rendered app with low JavaScript, but still create bad interactions with heavy Turbo updates, large DOM swaps, or expensive Stimulus controllers.
CLS: Cumulative Layout Shift
CLS measures visual stability.
It asks: how much did the page jump around while loading or updating?
This is the metric behind the annoying experience where you try to click a button, an image loads above it, and the button moves.
If CLS is bad, users feel like the page is unstable.
Common causes:
- images without width/height
- ads or embeds inserted without reserved space
- fonts swapping and changing text dimensions
- banners appearing above existing content
- late-loading UI that pushes content down
CLS is often the easiest metric to improve because the fix is usually concrete: reserve space before content arrives.
Why Cloudflare’s view is useful
Cloudflare Web Analytics does not just show one aggregate score. It lets you explore Core Web Vitals by dimensions like URL, browser, operating system, country, and element.
The element view is the important part.
For each metric, Cloudflare’s debug view shows the top elements with negative impact. Selecting an element gives more detail, including percentile views like P50, P75, P90, and P99.
That is more useful than a single average.
Percentiles: why P75 matters
Performance data is not evenly distributed.
A page can feel instant for you on a desktop with a warm cache and still be poor for users on slower devices, mobile networks, or unlucky cache paths.
That is why Core Web Vitals usually talk about percentiles, especially P75.
P75 means 75% of observations were at or below that value, and 25% were worse.
So if an element has LCP of 3,900 ms at P75, it means a meaningful chunk of users are seeing that content arrive slowly. It is not just one weird outlier.
Cloudflare also exposes P50, P90, and P99 in the debug view:
- P50: the median user experience
- P75: a practical “most users should be okay” threshold
- P90/P99: the long tail, where slow devices and bad network paths show up
When debugging, I usually look at P75 first, then glance at P90. If P75 is fine but P99 is terrible, that may be a long-tail issue. If P75 is bad, the mainstream experience needs work.
Field data, not just a lab test
One reason I like Cloudflare’s view is that it is based on real browser visits collected by its Web Analytics beacon.
According to Cloudflare’s docs, the beacon loads from static.cloudflareinsights.com/beacon.min.js. For proxied sites, data is sent through /<domain>/cdn-cgi/rum; for non-proxied sites, it goes to cloudflareinsights.com/cdn-cgi/rum.
Cloudflare says it collects timing metrics without cookies, localStorage, or tracking users across customer sites.
That makes it different from a one-off Lighthouse run.
Lighthouse is still useful because it is repeatable and gives concrete diagnostics in a controlled environment. But field data tells you what real users experienced.
You want both:
- Lighthouse to reproduce and fix problems locally
- Cloudflare Web Analytics to see whether real-user experience improved after deploy
How I read the dashboard
My order of operations is usually:
- Open Core Web Vitals.
- Filter by the page or path I care about.
- Check which metric is worst: LCP, INP, or CLS.
- Open debug view for that metric.
- Identify the element responsible.
- Fix the class of problem, not just the symptom.
- Deploy and wait for field data to update.
For example:
- Bad LCP on a homepage hero probably means image/CDN/render-blocking work.
- Bad INP on a search page probably means JavaScript or DOM update work.
- Bad CLS on a catalog page probably means dimensions or reserved space.
The metric tells you where to look. The debug element tells you what to inspect. The fix still requires engineering judgment.
Practical fixes by metric
For LCP:
- compress and resize images
- use modern formats where practical
- preload the hero image if it is truly the first important content
- avoid lazy-loading the LCP image
- reduce render-blocking CSS/JS
- cache HTML and assets properly
- improve server response time
For INP:
- ship less JavaScript
- break up long tasks
- debounce expensive handlers
- avoid huge DOM replacements
- defer non-critical third-party scripts
- profile interactions in Chrome DevTools
For CLS:
- set image and video dimensions
- reserve space for embeds and banners
- avoid injecting content above existing content
- tune font loading to avoid large swaps
- make skeleton states match final layout dimensions
The trap: optimizing the score instead of the page
Core Web Vitals are useful because they map to user experience. But they are still metrics.
The goal is not to make a dashboard green at all costs. The goal is to make the page feel better for the users you care about.
Sometimes that means a simple fix: add missing image dimensions. Sometimes it means a product decision: remove a heavy third-party widget. Sometimes it means accepting a tradeoff because a page has richer functionality than a static document.
The useful habit is to treat each metric as a debugging lens:
- LCP: when does the page become useful?
- INP: does the page respond when touched?
- CLS: does the page stay where the user expects?
That is the plain-English version I keep in my head when reading the Cloudflare dashboard.