How to Improve Your Google PageSpeed Score & Core Web Vitals — Part 1

Blog / Django · August 2, 2021 · Updated June 10, 2026 · 6 min read
How to Improve Your Google PageSpeed Score & Core Web Vitals — Part 1

Google's PageSpeed Insights still grades a page from 0 to 100, but in 2026 that number is only a proxy. What actually moves rankings and conversions is Core Web Vitals — the real-user speed and stability metrics Google measures in the field. This guide (Part 1 of 2) explains what to measure in 2026 and how to fix the issues that drag a page down.

A high Lighthouse score is a lab estimate from one simulated load on one device. Core Web Vitals come from the Chrome User Experience Report (CrUX) — anonymized data from real Chrome users on real networks and devices. The two often disagree, and field data is what counts for Search.

Core Web Vitals in 2026

There are three Core Web Vitals. The biggest change since older guides: INP (Interaction to Next Paint) replaced FID (First Input Delay) as a Core Web Vital on 12 March 2024. FID only measured the delay before the first interaction; INP measures responsiveness across the whole visit, so it is far more representative of real UX and much harder to game.

Metric What it measures Good (75th pct) Needs work Top fixes
LCP — Largest Contentful Paint Loading: time to render the largest visible element ≤ 2.5 s 2.5–4.0 s Faster TTFB, preload + fetchpriority, modern image formats
INP — Interaction to Next Paint Responsiveness: latency of user interactions ≤ 200 ms 200–500 ms Break up long tasks, cut JS, reduce third-party scripts
CLS — Cumulative Layout Shift Visual stability: unexpected layout movement ≤ 0.1 0.1–0.25 Size images/embeds, reserve ad space, font-display: swap

"Good" means the 75th percentile of page loads meets the threshold — you need roughly 75% of real visits to pass, not just your own test run.

Lab data vs. field data — and the tools for each

  • Lab data is collected in a controlled environment (one device, one throttled connection). It is reproducible and great for debugging, but it is not what users experience.
  • Field data is real-user monitoring (RUM) aggregated in CrUX. It is what Google uses to assess Core Web Vitals for ranking.

Use the right tool for the job:

  • PageSpeed Insights — shows both lab (Lighthouse) and 28-day field (CrUX) data side by side for a URL.
  • Lighthouse — in Chrome DevTools or via the CLI (npx lighthouse <url>) for lab audits and CI gating.
  • Chrome DevTools Performance panel — record a trace to find the long tasks that hurt INP.
  • WebPageTest — multi-location, real-device testing with filmstrip and waterfall analysis.
  • Search Console → Core Web Vitals report — field data grouped by URL pattern across your whole site.
  • The web-vitals JS library — capture LCP/INP/CLS from your own users in production.

Improving LCP (Largest Contentful Paint)

LCP is usually a hero image, a large heading, or a big text block above the fold. The most effective levers:

  1. Cut server response time (TTFB). Cache rendered pages or fragments, add a CDN, and reduce N+1 database queries. On Django, watch for unused or duplicated ORM queries and add select_related / prefetch_related.
  2. Prioritize the LCP resource. Preload it and mark it high priority so the browser fetches it early.
  3. Serve modern, right-sized images. Use AVIF or WebP, srcset for responsive sizing, and never lazy-load the LCP image.
  4. Eliminate render-blocking CSS/JS. Inline critical CSS, defer the rest, and load non-critical JavaScript with defer / async.
<!-- Preload + prioritize the LCP image; serve modern formats responsively -->
<link rel="preload" as="image" href="/img/hero.avif" fetchpriority="high" />

<picture>
  <source type="image/avif"
          srcset="/img/hero-800.avif 800w, /img/hero-1600.avif 1600w" sizes="100vw" />
  <source type="image/webp"
          srcset="/img/hero-800.webp 800w, /img/hero-1600.webp 1600w" sizes="100vw" />
  <img src="/img/hero-1600.jpg" width="1600" height="900"
       alt="Product dashboard" fetchpriority="high" decoding="async" />
</picture>

<!-- Below-the-fold images: lazy-load AND keep dimensions to avoid layout shift -->
<img src="/img/feature.webp" width="640" height="360"
     loading="lazy" decoding="async" alt="Feature screenshot" />

Improving INP (Interaction to Next Paint)

INP is dominated by JavaScript running on the main thread. To keep interactions under 200 ms:

  • Break up long tasks. Split any work over 50 ms into smaller chunks and yield to the main thread with await scheduler.yield() (or setTimeout / requestIdleCallback) so input can be processed.
  • Ship less JavaScript. Code-split, tree-shake, and remove unused libraries — heavy hydration is a common INP killer.
  • Tame third-party scripts. Chat widgets, tag managers, and A/B tools run on your main thread; load them lazily or move them to a web worker.
  • Debounce expensive handlers (search-as-you-type, scroll, resize) and push heavy work off the critical path.
  • Use content-visibility: auto on off-screen sections so the browser can skip their rendering work until they are needed.

Improving CLS (Cumulative Layout Shift)

CLS happens when content moves after it first paints. Reserve space for everything that loads late:

  • Always set width / height (or aspect-ratio) on images, video, and iframes so the browser reserves the box before the asset arrives.
  • Reserve space for ads, embeds, and banners with a min-height container instead of letting them push content down on load.
  • Prevent font-swap shift with font-display: swap plus a preloaded, well-matched fallback so reflow on font load is minimal.
  • Never insert content above existing content (cookie bars, "you may also like" injections) unless the user explicitly triggered it.
/* Reserve the image box even before the file loads */
img, video { max-width: 100%; height: auto; }
.media { aspect-ratio: 16 / 9; width: 100%; }

/* Preload the font and swap so text is visible immediately */
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-display: swap;
}

Quick wins for every page

Beyond the three vitals, a few server- and asset-level changes help every metric:

  • Enable Brotli or gzip compression for text assets (HTML, CSS, JS, SVG).
  • Serve over HTTP/2 or HTTP/3 so many resources can download in parallel.
  • Set long-lived cache headers on fingerprinted static files, with a short TTL on HTML.
  • Minify CSS/JS/HTML and subset fonts to the glyphs you actually use.
  • Self-host or preconnect to critical third-party origins.
# Long cache for hashed/static assets, short cache for HTML
location ~* \.(?:css|js|woff2|avif|webp|jpg|png|svg)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}
location / {
    add_header Cache-Control "public, max-age=0, must-revalidate";
}

# Brotli + gzip for text assets
brotli on;
brotli_types text/css application/javascript image/svg+xml;
gzip on;
gzip_types text/css application/javascript image/svg+xml;

Where to go next

Page speed is never "done" — measure with field data, fix the worst-offending metric, then re-measure. In Part 2 of this series we continue with more advanced techniques for squeezing out the last seconds.

For related reading, see our guide to on-page SEO factors (speed is one ranking signal among many) and hosting Django on Nginx with uWSGI for high performance for server-side tuning. If you would rather hand it off, our team has spent 12+ years and 50+ projects shipping fast web applications and Django builds that pass Core Web Vitals.

Frequently Asked Questions

What replaced FID in Core Web Vitals?

INP (Interaction to Next Paint) replaced FID (First Input Delay) as a Core Web Vital on 12 March 2024. INP measures the latency of all interactions during a visit, not just the first one, so it reflects real responsiveness far better.

What are good LCP, INP, and CLS scores?

At the 75th percentile of real-user loads: LCP ≤ 2.5 s, INP ≤ 200 ms, and CLS ≤ 0.1. Roughly 75% of your visits need to meet each threshold for the page to be rated "good."

Why is my field score worse than my Lighthouse score?

Lighthouse is lab data — one simulated load on one device and connection. Field data (CrUX) aggregates real users on slower networks, older phones, and cold caches. Google ranks on field data, so trust CrUX and Search Console over a single lab run.

How do I improve LCP quickly?

Identify the LCP element in PageSpeed Insights, then preload it with fetchpriority="high", serve it as AVIF/WebP at the right size, never lazy-load it, and cut server response time with caching and a CDN.

Do images really cause layout shift?

Yes — images without width/height (or aspect-ratio) are a leading cause of CLS because the browser cannot reserve space until the file loads. Always set dimensions, and reserve space for ads, embeds, and late-loading widgets.

Do I need a perfect 100 PageSpeed score?

No. 100 is a lab vanity number. The goal is passing Core Web Vitals in the field (LCP/INP/CLS in the "good" range) for real users — a page can score 90 in Lighthouse and still pass, or score 100 and fail under real-world conditions.

Share this article