Fix Core Web Vitals on a Next.js + Sanity Site: Fix Order and Timeline

By Nayan Kyada · · 6 min read

Part of The Sanity + Next.js Guide

Your Search Console report says "Poor URLs" or "Needs improvement" and your Next.js + Sanity site is supposed to be fast. This post is for owners who need to fix Core Web Vitals on a Next.js Sanity site and want to know which metric is failing, what is usually behind it, what order to fix things in, and how long until the report goes green.

If you want the deeper theory, I cover thresholds in Core Web Vitals in 2026. This post is the triage version: what to do on Monday morning.

Read the Search Console report correctly

Three things trip owners up before any code is touched.

  1. Field data, not lab data. Search Console shows what real Chrome users experienced over a rolling 28-day window. A green Lighthouse score does not override it.
  2. URL groups. Google groups similar pages. If your 400 blog posts share a template, one bad template fails all 400. That is good news: one fix clears a whole group.
  3. Mobile first. Mobile and desktop are reported separately. Mobile usually fails first, so start there.

The thresholds at the 75th percentile are: LCP at or under 2.5 seconds, INP at or under 200 milliseconds, CLS at or under 0.1. Open the failing group, note which metric is flagged, and ignore the other two until that one is dealt with.

LCP failing: the hero image is almost always the cause

On Sanity sites, the Largest Contentful Paint element is nearly always a hero image or a large heading above a hero. The usual causes, in the order I check them:

  • The hero image is lazy-loaded. next/image lazy-loads by default, so an above-the-fold image needs the priority prop (or loading="eager" with fetchPriority="high").
  • The image is served at original size because sizes is missing or wrong, so a phone downloads a desktop-sized file.
  • The page itself is slow to respond, which is a TTFB problem rather than an image problem.
  • The image URL goes to Sanity's CDN with no width or format hints, so you ship a huge JPEG.

A broken hero looks like this:

// app/components/Hero.tsx (before)
import Image from 'next/image'
 
export function Hero({ src, alt }: { src: string; alt: string }) {
  return <Image src={src} alt={alt} width={2400} height={1200} />
}

And the fixed version:

// app/components/Hero.tsx (after)
import Image from 'next/image'
 
export function Hero({ src, alt }: { src: string; alt: string }) {
  return (
    <Image
      src={src}
      alt={alt}
      width={2400}
      height={1200}
      priority
      sizes="100vw"
      className="h-auto w-full"
    />
  )
}

If the LCP is still slow after that, the problem is upstream. I walk through the full pattern in How to fix LCP on image-heavy pages, and server response time is covered in the TTFB post.

CLS failing: images, fonts and late-loading blocks

Layout shift on a Sanity site comes from a short list of suspects:

  • Images rendered without reserved space. Sanity returns width and height inside the asset metadata, so there is no excuse to omit them. See Kill CLS on Sanity images.
  • Web fonts swapping in with different metrics. Use next/font, which self-hosts the font and adjusts fallback metrics, rather than a stylesheet link to a font provider.
  • Embeds, cookie banners and promo bars injected after load, pushing content down.
  • Animations that move layout properties instead of transforms. If you use Framer Motion, check this write-up.

A fast way to find the offender: in Chrome DevTools, open the Performance panel, record a page load, and look at the Layout Shifts track. Each shift names the element that moved.

INP failing: client JavaScript is the culprit

Interaction to Next Paint measures how long the page takes to respond after a tap or click. It fails when the main thread is busy. On Next.js sites that usually means:

  • Too much of the tree is marked use client, so a lot of JavaScript hydrates on every page.
  • Third-party scripts: chat widgets, tag managers, heatmaps, consent tools.
  • Heavy components such as a Portable Text renderer, carousel or search UI shipped to every visitor.
  • Click handlers doing synchronous work like filtering large lists.

The fix is to push work to the server and ship less. Move use client down to the smallest interactive leaf, defer third-party scripts, and render rich text on the server. Two related posts: cutting bundle size by analysing chunks and INP for React apps.

The fix order I use

Cost and impact differ, so I do things in this order:

StepFixTypical effortMetric helped
1Priority and sizes on the hero imageUnder an hourLCP
2Width and height on every image, next/fontHalf a dayCLS
3Reserve space for banners and embedsHalf a dayCLS
4Defer or remove third-party scripts1 dayINP, LCP
5Server-render rich text, shrink client components1 to 3 daysINP
6Caching and TTFB work1 to 2 daysLCP

The effort figures are rough ranges for a typical marketing site, not quotes. A site with a messy component tree takes longer.

Expected timeline to green

The timeline is set by Google, not by your developer:

  1. Days 1 to 5: fixes shipped to production. Check the lab results in PageSpeed Insights.
  2. Weeks 1 to 4: field data slowly improves as the 28-day window fills with fast visits. Vercel Analytics or a similar real-user tool shows progress much sooner than Search Console; here is how I set that up.
  3. Week 4 onward: click "Validate fix" in Search Console. Google then monitors the group and typically confirms or rejects over roughly another four weeks.

So plan for six to eight weeks from deploy to a clean report. If a promised fix claims green in a week, that is not how the data works.

What to ask a developer

  • Which metric fails, on which URL group, and what element is responsible?
  • How will you measure real-user data, not just Lighthouse?
  • Will you fix the shared template or patch individual pages?
  • What third-party scripts are on the site, and who approved each?
  • What is the plan if field data has not moved after four weeks?

If you want a developer to find the cause rather than guess, this is work I do. A Performance & Sanity audit starts from $800 and gives you a ranked fix list tied to your own Search Console groups.

Frequently asked questions

How long does it take for Core Web Vitals to turn green in Search Console?

Search Console uses a rolling 28-day window of real-user field data from Chrome. After you ship a fix, expect about four weeks before the report fully reflects it, and the validation process on a failing group can take a similar amount of time.

Why does my Next.js Sanity site pass Lighthouse but fail Core Web Vitals in Search Console?

Lighthouse is a single lab test on a fast machine, while Search Console reports field data from real visitors on real phones and networks. Third-party scripts, cookie banners, and heavy client JavaScript tend to hurt real users far more than they hurt a lab run.

Which Core Web Vital should I fix first on a Sanity site?

Fix whichever one Search Console flags as failing, and on most Sanity sites that is LCP caused by an unoptimised hero image. CLS from missing image dimensions and fonts is usually the next quickest win, and INP is typically the slowest to fix because it involves client JavaScript.