Skip to content
Engineering24 Mar 2026 · 7 min read

Core Web Vitals for business web applications: what matters

LCP, INP and CLS for product owners: why they matter for apps Google never indexes, and the rendering, image, font and script decisions that move them.

DODaniel OkaforHead of Engineering
A laptop displaying code, on a desk

Core Web Vitals get discussed as an SEO topic, which is why product owners of internal tools and logged-in business applications tend to ignore them. That is a mistake. The three metrics measure how quickly your application shows something useful, whether it responds when someone clicks, and whether the page holds still while it loads. Those things decide how many orders get placed and how many support tickets get raised. They also decide how much your staff quietly resent the software they use for eight hours a day.

Here is what the metrics mean, why they matter for applications Google will never index, and the handful of engineering decisions that move them.

The three metrics, in plain terms

Largest Contentful Paint (LCP) is how long it takes for the biggest visible thing on the screen (usually a hero image, a heading or a data table) to appear. The target is under 2.5 seconds for 75% of page loads. It answers "how long until I can see something useful?"

Interaction to Next Paint (INP) measures the delay between a user doing something (clicking, typing, tapping) and the screen visibly responding. It replaced First Input Delay in 2024 and it is a much harsher judge, because it looks at every interaction across the whole session instead of only the first. The target is under 200 milliseconds. It answers "does this thing respond when I use it?" For business applications, INP is the metric that matters most and is worst most often.

Cumulative Layout Shift (CLS) measures how much the page moves around after it has started rendering. The target is under 0.1. This is the "did the button move just as I went to click it?" metric, and a CLS problem is what makes someone approve the wrong invoice.

Each is reported at the 75th percentile of real users. That detail matters. Your own laptop on the office network is nowhere near the 75th percentile. Your regional manager's four-year-old Android phone on a train is closer.

Why it matters beyond rankings

Public benchmarks are consistent. Vodafone measured an 8% uplift in sales from a 31% improvement in LCP. Rakuten 24 saw a 33% increase in conversion rate after Core Web Vitals work. Those are e-commerce numbers, but the mechanism is general. People abandon slow things and mistrust things that jump.

For internal and B2B applications the costs show up differently:

  • Support load. A form that takes 600 ms to react to a click gets double-submitted. It is common for "duplicate order" tickets to fall by a large fraction after INP work alone, with no functional change at all.
  • Throughput. A claims handler processing 90 cases a day, losing three seconds per case to slow list rendering, loses 4.5 minutes a day. Across a team of 40 that is a part-time employee spent waiting for a spinner.
  • Adoption. The field-sales app that stutters on a mid-range phone is the one nobody opens. They phone the office instead, and the data never gets entered.
  • Trust in the numbers. A dashboard whose figures shift as widgets load teaches people to disbelieve the first thing they see.

None of this appears in a search console, which is why nobody tracks it. The cost turns up in the operating budget instead.

Rendering strategy is most of LCP

The single largest lever for LCP is where and when the HTML is produced. A client-rendered single-page application (an empty shell, then a bundle, then an API call, then content) front-loads three round trips before the user sees anything. On a fast connection that is a second. On a poor one it is five.

Server-side rendering with a framework such as Next.js sends usable HTML on the first response, so the largest element paints before any JavaScript runs. Streaming lets the page frame and the menu appear immediately while a slow query for the main table catches up. Static generation with revalidation is right for pages that change infrequently, and even a logged-in application has more of those than you would think: settings, help, reference data, reports that refresh hourly.

In practice that means rendering on the server by default and hydrating only the parts of the page that are interactive. "The whole app is client-side" is a decision that needs justifying. This is the reasoning behind how we build web applications, and it is the difference between an LCP of 1.2 seconds and 4 seconds on the same feature.

Images and fonts

Images are the usual LCP culprit on marketing pages and product catalogues. Fonts cause most of the layout shift, on every kind of page.

For images, serve them at the size they are displayed, in a modern format (AVIF or WebP), with width and height set so the browser reserves the space, and mark the LCP image as high priority so it is not queued behind icons. Lazy-load everything below the fold and nothing above it. Frameworks do most of this for you now if you use their image component rather than a bare img tag.

For fonts, self-host and preload the one or two weights you use. Set font-display: swap or optional, and set fallback metrics so the swap does not reflow the page. Every third-party font service is a DNS lookup and a connection you did not need. A business application generally needs one variable font, and for a lot of internal tools the system font stack is fine.

Third-party scripts

Analytics, chat widgets, session recording, tag managers, consent banners, A/B testing, the thing marketing added in 2023. Each one is JavaScript competing with your own code on the main thread, and it drags INP down. Third-party scripts commonly account for more than half of a page's total blocking time.

Audit them quarterly. For each one, ask who owns it and what decision it informs, then ask when that decision was last made. Remove what nobody can justify. Load the rest after the page is interactive, and consider moving tag management server-side. On authenticated applications be especially sceptical. You already know who your users are, so you may not need a fingerprinting library to find out.

Budgets in CI

Performance decays one pull request at a time, and the only defence that lasts is a budget that fails the build.

A minimal setup runs Lighthouse CI against three or four representative pages on every pull request, with assertions on LCP, INP (via total blocking time as a lab proxy), CLS and JavaScript bundle size. Set the thresholds a little tighter than your current numbers and ratchet them down over time.

{
  "ci": {
    "assert": {
      "assertions": {
        "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
        "total-blocking-time": ["error", { "maxNumericValue": 200 }],
        "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
        "resource-summary:script:size": ["error", { "maxNumericValue": 250000 }]
      }
    }
  }
}

Bundle analysis on every build is the companion check. The day someone imports a 300 KB date library to format one timestamp, the build should say so.

Real users versus the lab

Lab tools (Lighthouse, WebPageTest) run one page load on one simulated device. They are excellent for diagnosis and for CI gates, and poor at telling you what your users experience, because your users are on a spread of devices, networks and states of logged-in-ness that a lab does not reproduce. INP in particular is nearly impossible to judge in a lab, because it depends on what people do after the page loads.

Field data (real user monitoring, or RUM) is what your users are getting. Collect the three metrics from real sessions using the web-vitals library or your framework's built-in reporting, tag them with route, device class and user segment, and look at the 75th percentile weekly. Public sites get Chrome User Experience Report data for free. Authenticated applications do not, which is why so many business apps have never had their numbers looked at.

Use both. Field data points you at the page and the segment that are slow, and lab tools then tell you why.

Where to start

Measure before optimising. Add RUM collection this week, look at the 75th percentile per route after a fortnight, and pick the single worst page that matters to the business. It is almost always a list or a search screen, and the fix is usually to server-render it or cut the JavaScript it loads. Sometimes it is a third-party script nobody needed. Then put a budget in CI so it stays fixed. If your application is slow and you are not sure why, that is a conversation we have often. Tell us what you are seeing and we will help you find the bottleneck.

  • Performance
  • Web
  • Next.js
  • Core Web Vitals
  • Frontend