A SaaS landing page fails Core Web Vitals differently from a blog post, because it carries things a blog post never does. A hero video. An embedded product demo. A chat widget. A consent banner. Analytics from three vendors, because marketing, product and sales each picked their own.
This is a checklist for that page specifically.
Before you change anything, measure the right thing
There are two kinds of data and they disagree constantly.
Lab data is what Lighthouse gives you: one simulated load, on a simulated device, on a simulated network. It is repeatable, which makes it good for comparing a change against a baseline.
Field data is what the Chrome User Experience Report collects from real visitors on real devices. It is what Google actually uses.
A green Lighthouse score next to failing field data is the normal case, not a contradiction. Lighthouse loads your page once, cold, with no chat widget session, no returning-visitor cache and no third party consent state. Your visitors have all of those.
Use field data to decide what is broken. Use lab data to check whether your fix worked.
LCP: it is almost always the hero
Largest Contentful Paint measures when the biggest element in the viewport finishes rendering. On a SaaS landing page that is the hero image, the hero video poster, or the headline if the hero is plain text.
Find out which it is rather than guessing. In Chrome DevTools, open the Performance panel, record a reload, and look for the LCP marker on the timeline. It names the element.
Four things commonly delay it:
The image is discovered late. If the hero is a CSS background, or is inserted by JavaScript, the browser cannot start downloading it until it has parsed the CSS or run the script. Put it in the HTML as an img tag and add fetchpriority="high".
The image is lazy loaded. Lazy loading the hero delays the exact element you are being measured on. It should be eager. Everything below the fold should not.
A render blocking stylesheet is in front of it. Any stylesheet in the head blocks painting. Inline the small amount of CSS needed for the hero and load the rest asynchronously.
The server was slow to respond. LCP includes TTFB. If the document takes 800ms to arrive, LCP cannot be under 2.5 seconds no matter what you do to the image.
Target: 2.5 seconds at the 75th percentile of your field data.
INP: the scripts you did not choose
Interaction to Next Paint measures the delay between a visitor interacting and the page visibly responding. It replaced First Input Delay, and it is stricter, because it measures every interaction rather than only the first.
On a landing page the offenders are predictable, and almost none of them are your code:
- The chat widget, which loads a large bundle and attaches listeners.
- The consent banner, which often blocks rendering by design.
- Analytics and tag managers, which can end up loading several more scripts each.
- Heatmap and session recording tools, which listen to every scroll and click by definition.
Measure what each one costs before arguing about it. In DevTools, use the Performance panel to record an interaction, then look at the long tasks. Attribute them to a script. Then disable one tool at a time and record again. A number per vendor makes the conversation about removing one much easier.
Then, in order:
- Delete what nobody reads. Most sites carry at least one analytics tool that no one has opened in a year.
- Load the chat widget on interaction, not on page load. A button that loads the widget when clicked costs nothing until someone wants it.
- Defer everything that is not needed for first render. Tag managers almost never are.
- Break up your own long tasks if any survive, by yielding to the main thread between chunks of work.
Target: 200ms at the 75th percentile.
CLS: the things that arrive late
Cumulative Layout Shift measures how much content jumps around while loading. Every cause is something that takes up space after the page has already laid out without it.
- Images with no dimensions. Always set
widthandheight, even when CSS resizes the image. The browser uses them to reserve the space. - Web fonts. A fallback font with different metrics reflows the text when the real font swaps in. Use
size-adjuston the fallback, or pick a fallback with similar metrics. - Consent banners and announcement bars injected at the top of the page, pushing everything down.
- Embedded demos and iframes with no reserved height.
- Anything that appears on a timer, which is worse, because it can shift the page after someone has started reading.
The fix is the same every time: reserve the space in advance. If you do not know the height, give the container a minimum height that matches the common case.
Target: 0.1 at the 75th percentile.
The checklist
Work through it in this order.
Measure
- Pull field data for the page, not just the origin.
- Record a Lighthouse run as your before baseline.
- Identify the LCP element by name.
LCP
- Hero image is an
imgin the HTML, not a CSS background or JavaScript insertion. - Hero image has
fetchpriority="high"and is not lazy loaded. - Hero image is served as WebP or AVIF at display size.
- Critical CSS is inline, the rest loads asynchronously.
- Fonts are self hosted, subset, preloaded for above the fold weights only, with
font-display: swap. - TTFB is under 600ms with cache warm.
INP
- Every third party script has a named owner and a reason to exist.
- Chat widget loads on interaction.
- Tag manager and analytics are deferred.
- No long task over 200ms on the common interactions.
CLS
- Every image and iframe has explicit dimensions.
- Banners and consent UI reserve their space.
- No content inserted on a timer above existing content.
Verify
- Re-run Lighthouse and compare against your baseline.
- Wait 28 days and check field data, which is the window CrUX reports on.
Where to stop
A landing page does not need a perfect score. It needs to be in the green band on all three metrics at the 75th percentile, and then you should go and work on the copy, which will do more for your conversion rate than shaving another 200ms.
The point of diminishing returns arrives early. Recognising it is part of the job.
Work with me
Want me to check your site? Get a free 5-minute teardown.
I build and fix websites for SaaS and AI companies. Reply within 24 hours.
Get my free teardown