Optimising a Next.js Website for a High Google PageSpeed Insights Score

Why Core Web Vitals matter for SEO, conversions, and ROI — and how to get to 90+

If you’ve ever shipped a beautiful website only to see a PageSpeed Insights score in the 30s, you’ll know the feeling: everything looks great, but performance (and sometimes search visibility) tells a different story.

The good news is that a low score is rarely “because Next.js is slow”. In practice, poor PageSpeed scores come from a handful of predictable causes: oversized images, too much JavaScript during the critical load, render-blocking resources, layout shift (CLS), and third-party scripts behaving badly. And the great part is that Next.js gives you excellent tools to fix all of them—if you use them deliberately.

This article is a practical, detailed guide to getting your Next.js website into the 90+ territory in Google PageSpeed Insights (and Lighthouse), and why it matters for search performance and ROI.

Why PageSpeed is more than a vanity metric

Google PageSpeed Insights is largely a proxy for Core Web Vitals and real user experience. That matters because:

1) Performance influences rankings (especially on mobile)

Google has confirmed Core Web Vitals are part of the “page experience” signals. They’re not the only ranking factor—content and relevance still win—but when two results are otherwise similar, user experience signals can absolutely become a tie-breaker.

2) Performance affects conversion rate

Every extra second of delay increases friction. Slow pages lead to:

  • higher bounce rates
  • lower time on site
  • fewer page views
  • lower lead completion and checkout completion

3) Performance reduces acquisition costs and improves ROI

Paid traffic is expensive. If your landing page loads slowly, you pay for clicks that never get a chance to convert. The ROI impact is direct:

  • same ad spend
  • same audience
  • more conversions

The “high score” isn’t the goal in itself—a faster, more stable, more responsive site is the goal. A 90+ score simply indicates you’re doing most of the fundamentals correctly.

What PageSpeed is actually measuring

PageSpeed Insights reports on a few headline metrics. The ones that most often tank scores are:

  • LCP (Largest Contentful Paint): How fast the main content becomes visible (usually the hero image/heading).
  • CLS (Cumulative Layout Shift): How stable the layout is during load (things jumping around).
  • TBT (Total Blocking Time): How much time the main thread is blocked by JavaScript (can’t scroll/click).
  • FCP (First Contentful Paint): When the first pixels appear (often okay even when LCP is bad).
  • Speed Index: How quickly content appears visually overall.

If you want 90+, you usually win by:

  1. making LCP fast
  2. killing CLS
  3. reducing main-thread JS work (TBT)

Step 1: Fix your LCP first (the biggest lever)

On most sites, the LCP element is one of:

  • a hero image
  • a banner background
  • a large heading text block

In Next.js, the most common LCP mistake is using CSS background images for heros instead of <Image />.

Why CSS backgrounds hurt LCP

Background images:

  • don’t get Next’s image optimisations
  • often load later than you think
  • are harder to preload and size properly
  • can cause CLS if the container size depends on late-loading content

The Next.js way: use next/image for LCP elements

If your hero is an image, use:

  • priority
  • sizes
  • fill (if it’s a full-bleed background)
  • a predictable container aspect ratio

Example pattern:

<div className="relative h-[80vh] min-h-[520px]">
<Image
src={heroUrl}
alt={heroAlt}
fill
priority
sizes="100vw"
className="object-cover"
/>
</div>

Key point: sizes tells the browser which image candidate to choose. Without it, browsers often download unnecessarily large images.

If you’re using a CMS like Prismic

CMS images are typically huge (4K+), so if you don’t give sizes, you’ll see audits like:

“This image is larger than it needs to be”

Fix that by setting sizes based on layout. For example:

  • full width mobile, half width desktop:
sizes="(min-width: 1024px) 50vw, 100vw"

Also: compress what users actually receive

Even if the CDN serves big originals, you want the client to receive appropriately compressed variants.

Many CMS/CDN setups support automatic params (e.g. auto=format,compress and q=70). If you can influence those via your component (or wrapper like PrismicNextImage), do it.

Step 2: Eliminate CLS (layout shift) aggressively

CLS is a silent killer. A site can feel fast but still score badly because elements move after initial render.

Typical CLS culprits:

  • late-loading fonts
  • cookie banners that push content down
  • images without fixed dimensions
  • dynamically injected content (often from third parties)
  • accordions/overlays affecting layout unexpectedly

Fix fonts without tanking CLS

Remote font services (like Adobe Fonts/Typekit) introduce dependency chains:
HTML → kit CSS → font CSS → font files

You can’t remove the chain unless you self-host, but you can reduce the damage:

  • preconnect to the right domains early
  • load the stylesheet normally (avoid “media=print” hacks if CLS is a priority)
  • ensure fallback fonts match metrics as closely as possible

The goal is to avoid large reflows when the font swaps.

Reserve space for images and embeds

Always render images with known width/height or use fill within a container that has defined size.

For iframes (Vimeo/YouTube), wrap in an aspect-ratio box:

<div className="relative aspect-video">
<iframe className="absolute inset-0 w-full h-full" ... />
</div>

Cookie banners and overlays

If your cookie banner pushes content down after load, you’ll get CLS.

Two strategies:

  • render it as an overlay (positioned fixed) instead of document flow
  • ensure it loads after the initial paint, and doesn’t shift the page

If you’re using a CMP via third-party scripts, test it in Lighthouse. Many CMPs load additional scripts that cause layout changes.

Step 3: Reduce JavaScript execution time (TBT) by cutting early JS

This is the most common reason Next.js sites score poorly on desktop Lighthouse: too much JS runs during the critical window.

Where the JS usually comes from

  • heavy UI libraries mounted on homepage unnecessarily
  • global providers wrapped around the entire app
  • animations (Framer Motion), carousels, map libraries
  • third-party tags (GTM, ads, trackers, CMPs)
  • video embeds (Vimeo player bundles are big)

The golden rule

Do not ship JavaScript you don’t need for the first screen.

Next.js gives you great tools here:

  • Server Components by default
  • dynamic() imports with `sUSPense boundaries
  • splitting route-level functionality
  • isolating client components

Don’t mount heavy components “hidden”

A classic pattern is toggling opacity to hide a component, but still mounting it. If the component runs effects and logic at mount, you still pay the cost.

Instead of:

  • render always
  • hide with CSS

Do:

  • conditionally render only when needed
  • or dynamic import the component only when interacted with

Lazy-load third parties

A high PageSpeed score usually requires that you treat third parties as optional:

  • Load GTM after interactive
  • Load ads only after consent
  • Remove legacy tags that rely on jQuery or document.write
  • Don’t load multiple CMPs

In the real world, a huge percentage of “bad scores” are caused by scripts that:

  • throw console errors
  • run expensive JS
  • inject DOM before hydration (causing React hydration errors)

Lighthouse flags those errors for a reason: they hurt performance and stability.

Step 4: Treat video as a performance feature, not a design layer

Background video is an LCP/TBT trap.

If your homepage loads a Vimeo player immediately, you’re almost guaranteed:

  • higher JS execution
  • worse TBT
  • delayed LCP (because main thread and network are busy)

The best approach: poster-first, video-later

Serve an image poster as the initial hero background (fast LCP), then mount video after the critical window (idle callback, timeout, or user interaction).

This often drops hundreds of milliseconds of JS CPU time.

Even better: if it’s a true background video, use a native <video> tag with an MP4 rather than loading the Vimeo runtime.

Step 5: Keep the homepage lean (it’s your most important PageSpeed page)

If you’re chasing 90+, the homepage should be:

  • mostly server-rendered
  • minimal client JS
  • no heavy map libraries
  • no carousels that mount immediately
  • no large forms that initialise on load if they aren’t used instantly

If you need a complex search experience, consider:

  • a simple CTA on homepage
  • route to a dedicated search page
  • load the complex search UI there

This is both better UX and better performance: you load complexity only when the user wants it.

Step 6: Use measurements, not guesses

PageSpeed is helpful, but it’s not the only tool you should use.

Use:

  • Chrome DevTools Performance panel
  • Lighthouse in DevTools (same engine)
  • Coverage tab (unused JS/CSS)
  • Network waterfall and Initiators

Focus on:

  • what your LCP element actually is
  • which scripts are executing on load
  • which third parties are injecting errors or blocking main thread
  • what causes CLS (Lighthouse has “layout shift culprits”)

Once you fix the top 2–3 offenders, your score usually jumps quickly.

Step 7: The ROI case for doing this properly

Let’s connect this back to business outcomes.

A faster site:

  • improves organic search visibility via better user experience signals
  • reduces bounce rate
  • increases page views per session
  • increases lead form completion
  • improves conversion rate on paid campaigns
  • reduces support burden (fewer “it’s slow” complaints)
  • builds brand trust (slow feels cheap)

For a housebuilder, real estate site, or e-commerce store, performance is not cosmetic: it influences whether users explore developments, enquire, shortlist, or move on.

A “90+ PageSpeed” site typically indicates you’ve built a platform that:

  • loads quickly
  • behaves predictably
  • remains stable across devices
  • doesn’t overwhelm the browser with unnecessary JS

That’s exactly what users want—and exactly what search engines and conversion funnels reward.

A practical checklist to reach 90+

Here’s the order I’d recommend for almost any Next.js site:

  1. Identify LCP element → convert it to next/image with priority + sizes
  2. Fix CLS → reserve space for images/iframes, fix font loading, overlay cookie banners
  3. Cut early JS → remove heavy providers from root, stop mounting hidden components
  4. Defer third parties → GTM after interactive, ads after consent, remove legacy scripts
  5. Fix console errors → errors often correlate with performance regressions
  6. Lazy video → poster-first, video-later
  7. Re-run Lighthouse → repeat

Final thought: performance is a product feature

Next.js makes it possible to build beautiful, content-rich, CMS-driven websites that still score 90+. But it takes intention. Treat performance as a first-class requirement, not a finishing touch.

When you build with performance in mind, you don’t just get a better score—you get better search visibility, better conversion rate, and better ROI from every marketing channel that lands users on your site.

Tell us about your project

Contact us

Phone
01872 306121
  • Truro
    The Barn Cottage Studio
    Perranwell Station
    Truro
    Cornwall
    TR3 7NB