What Core Web Vitals actually measure
Core Web Vitals are a set of metrics Google defined to describe what real visitors experience. There are three today. LCP, Largest Contentful Paint, measures how long the biggest element in the first screen, usually a hero image or a headline, takes to appear. A good score is 2.5 seconds or less.
CLS, Cumulative Layout Shift, measures how much content jumps around without the user asking. Picture reaching for a button just as an image loads and pushes it down. A good score is 0.1 or less. INP, Interaction to Next Paint, measures how long the page takes to show a response after someone taps, clicks or types. A good score is 200 milliseconds or less.
INP replaced FID, First Input Delay, as an official Core Web Vital in 2024. The difference matters: FID only looked at the delay on the first interaction, while INP considers interactions across the whole visit. That makes it much better at catching a menu that freezes or a form that stutters while you type.
Images, fonts and JavaScript: where the weight comes from
On most sites images are the largest files, and often the LCP element too. A common mistake is uploading a full-size photo straight from a camera or design tool and letting the browser shrink it. Send a size that fits each screen, use modern formats such as WebP or AVIF, and set width and height up front so the layout does not shift.
Fonts matter as well, especially for Thai sites, where font files are often larger than Latin ones. Load only the weights you use, serve them from your own domain, and set font-display so text appears first and swaps when the font arrives, rather than leaving a blank gap. JavaScript is the main cause of poor INP, because the browser must download, parse and run it before the page can respond.
Third-party scripts, such as chat widgets, ad tags and analytics, tend to go uncounted even though together they can weigh as much as your own code. Audit them now and then and remove any that nobody uses.
- Images: right-sized, WebP or AVIF, always set width and height
- Fonts: only the weights you need, self-hosted, with font-display set
- JavaScript: ship only what each page uses and defer the rest
- Third-party scripts: load with async or after interaction, and delete unused ones

Caching: stop doing the same work twice
The fastest way to serve a page is not to build it again. Static files such as images, CSS and JavaScript should carry a long Cache-Control lifetime and a hash in the file name. When the file changes, the name changes, so visitors get the new version immediately without waiting for an old cache to expire.
For pages whose content does not change every second, such as articles, service pages or product pages, generating them ahead of time and serving them through a CDN means a visitor in Bangkok gets the file from a nearby server instead of a distant origin. It also takes load off your database. Content that changes often can use a short cache lifetime, or you can purge the cache when an editor saves a change.
Practical habits in Next.js
Next.js already ships tools for most of the above. The next/image component resizes and converts images per device, lazy-loads them and reserves space to prevent layout shift. next/font bundles fonts with your site and reduces the flash when fonts swap. Set priority on the image that is your LCP element, and never lazy-load the top image on a page.
For JavaScript, the idea behind Server Components in the App Router is that components needing no interaction run on the server and never reach the browser. Add 'use client' only where you truly need state or event handlers. Heavy parts that are not needed immediately, like a map or a chart, can be split out with dynamic import, and Suspense lets finished parts of a page show first.
Finally, check what your dependencies cost. Some libraries add far more to the bundle than expected, and opening a bundle analyzer once before launch usually reveals something easy to remove.
Speed is not a task you finish at launch; it is a habit you check every time something new goes on the page.
Field data versus lab data
Lighthouse, and the test-run part of PageSpeed Insights, produce lab data: one simulated device and network, repeatable on demand. That is ideal for finding causes and comparing before and after a code change. It does not tell you what your visitors experience, because they open your site on many phones over 4G connections of uneven quality.
Field data comes from real visits, for example the Core Web Vitals report in Search Console or the Chrome UX Report. Google assesses the 75th percentile of visits, and this is the data closest to what is used for evaluation. INP in particular needs real interactions to be measured. For finer detail you can add the web-vitals library and send the values to your own analytics.
A workflow that works: use field data to find which pages have a problem, use lab data to find the cause and try fixes, then return to field data after release. That last check may need some time for data to accumulate.
Key takeaways
- Core Web Vitals are three: LCP for loading, CLS for stability and INP for responsiveness, with INP replacing FID in 2024.
- Images, Thai font files, JavaScript and third-party scripts are the first four places to look.
- Cache static files for a long time and serve rarely changing pages through a CDN.
- In Next.js, make next/image, next/font, Server Components and dynamic import part of your routine.
- Use field data to find problems, lab data to find causes, then recheck field data after fixing.
FAQ
Related services
Have a project like this in mind?
Tell us where you are today and we will suggest a sensible first step, with no obligation.
Talk to us


