DEV Community

Cover image for How We Improved Core Web Vitals on Client Projects
Pixel Mosaic
Pixel Mosaic

Posted on

How We Improved Core Web Vitals on Client Projects

Real-world techniques that helped us improve LCP, INP, and CLS across multiple production websites.

Performance isn't just a Lighthouse score anymore. Core Web Vitals directly affect user experience, search visibility, and conversion rates. Over the past year, we worked on several client projects where performance had become a serious issue.

The interesting part? None of these projects required a complete rewrite.

Instead, we focused on identifying the biggest bottlenecks and fixing them one by one.

Here's what worked.


The Initial Problems

Most projects had similar issues:

  • Large hero images delaying page rendering
  • Render-blocking CSS and JavaScript
  • Third-party scripts loading before important content
  • Layout shifts caused by images, fonts, and ads
  • Excessive client-side JavaScript
  • Slow API responses affecting initial page load

Typical Lighthouse scores ranged from 40–65 on mobile.

Core Web Vitals were often failing:

  • Largest Contentful Paint (LCP): 4–7 seconds
  • Interaction to Next Paint (INP): 300–600ms
  • Cumulative Layout Shift (CLS): 0.2–0.4

1. Optimizing Images First

This delivered the biggest improvements.

We replaced oversized JPEGs with modern formats like WebP and AVIF, resized images appropriately, and lazy-loaded everything below the fold.

Before:

<img src="/hero.jpg">
Enter fullscreen mode Exit fullscreen mode

After:

<img
  src="/hero.avif"
  width="1200"
  height="700"
  loading="eager"
  decoding="async"
  fetchpriority="high"
  alt="Hero image"
/>
Enter fullscreen mode Exit fullscreen mode

Key improvements:

  • Explicit width and height eliminated layout shifts
  • Smaller image formats reduced download size
  • High fetch priority improved LCP

Result:

  • LCP improved by nearly 1.5 seconds on several projects.

2. Reducing Render-Blocking Resources

Many sites loaded dozens of CSS and JavaScript files before displaying anything.

We:

  • Removed unused CSS
  • Deferred non-critical JavaScript
  • Split bundles using dynamic imports
  • Inlined critical CSS

Instead of:

<script src="app.js"></script>
Enter fullscreen mode Exit fullscreen mode

We used:

<script src="app.js" defer></script>
Enter fullscreen mode Exit fullscreen mode

And lazy-loaded components:

const Dashboard = lazy(() => import("./Dashboard"));
Enter fullscreen mode Exit fullscreen mode

This allowed browsers to render meaningful content much sooner.


3. Prioritizing the Hero Section

The largest content element usually determines LCP.

We made sure the browser prioritized it.

Examples:

<link
  rel="preload"
  as="image"
  href="/hero.avif"
>
Enter fullscreen mode Exit fullscreen mode

We also:

  • Reduced hero animations
  • Simplified above-the-fold layouts
  • Avoided unnecessary sliders

A static hero almost always outperformed complex carousels.


4. Fixing Layout Shifts

CLS issues were everywhere.

Common causes:

  • Images without dimensions
  • Ads injected after load
  • Web fonts swapping late
  • Dynamic banners

We fixed them by reserving space.

Example:

.hero-image {
    aspect-ratio: 16 / 9;
}
Enter fullscreen mode Exit fullscreen mode

Font loading:

font-display: swap;
Enter fullscreen mode Exit fullscreen mode

Result:

CLS often dropped from 0.28 to 0.02.


5. Optimizing Fonts

Several websites loaded 10–15 font files.

Instead:

  • Used only required font weights
  • Self-hosted fonts
  • Preloaded critical fonts
  • Used system fonts where possible

Example:

<link
  rel="preload"
  href="/fonts/inter.woff2"
  as="font"
  type="font/woff2"
  crossorigin
>
Enter fullscreen mode Exit fullscreen mode

Small changes, noticeable impact.


6. Reducing JavaScript Execution

Large JavaScript bundles often hurt INP more than network speed.

We removed:

  • Unused libraries
  • Duplicate plugins
  • Heavy UI frameworks where unnecessary

Instead of loading everything on page load:

button.addEventListener("click", async () => {
    const module = await import("./checkout.js");
    module.start();
});
Enter fullscreen mode Exit fullscreen mode

Users only downloaded code when needed.


7. Delaying Third-Party Scripts

Analytics, chat widgets, A/B testing tools, and marketing scripts often slowed down pages.

We delayed them until after initial rendering.

Instead of loading immediately:

<script src="analytics.js"></script>
Enter fullscreen mode Exit fullscreen mode

We loaded them later:

window.addEventListener("load", () => {
    const script = document.createElement("script");
    script.src = "/analytics.js";
    document.body.appendChild(script);
});
Enter fullscreen mode Exit fullscreen mode

Users saw content sooner without losing analytics.


8. Improving Server Response Times

Frontend optimization only goes so far.

Backend improvements included:

  • Better database indexing
  • API response caching
  • CDN integration
  • HTTP compression
  • Long-lived cache headers

Reducing Time to First Byte (TTFB) had a noticeable effect on LCP.


9. Measuring Real User Performance

Lighthouse is useful, but synthetic tests don't tell the full story.

We tracked:

  • Real-user Core Web Vitals
  • Chrome User Experience Report (CrUX)
  • PageSpeed Insights
  • Web Vitals library

Monitoring actual user metrics helped prioritize fixes that mattered most.


Results

Across multiple client projects, we commonly observed:

Metric Before After
LCP 4.8s 2.1s
INP 420ms 145ms
CLS 0.27 0.03
Mobile Lighthouse 58 94
JavaScript Bundle 1.3MB 470KB

While every project was different, the pattern remained consistent: addressing the biggest bottlenecks first produced the most meaningful gains.


Lessons Learned

The biggest improvements rarely came from chasing perfect Lighthouse scores. Instead, they came from focusing on the user's experience:

  • Optimize the content users see first.
  • Keep JavaScript lean and load only what's needed.
  • Reserve layout space to avoid visual shifts.
  • Treat third-party scripts with caution.
  • Measure performance using real user data, not just lab tests.
  • Make performance part of your development workflow rather than a one-time optimization task.

Final Thoughts

Improving Core Web Vitals doesn't require rebuilding an application from scratch. In many cases, a series of targeted optimizations—better image delivery, smarter resource loading, leaner JavaScript, and faster server responses—can dramatically improve both user experience and search performance.

If you're tackling a slow website, start by identifying the largest bottlenecks instead of optimizing everything at once. Incremental improvements compound quickly, and your users will notice the difference long before they see your Lighthouse score.

Top comments (0)