Fix Core Web Vitals on any Webflow site in under an hour
Most Webflow sites fail Core Web Vitals for the same three reasons. This guide walks each one in the order you should attack them, with real Webflow UI paths and the diagnostic tools in Site Health that tell you exactly which DOM element is to blame. Do all three and most sites jump 15-25 Performance points.
LCP (Largest Contentful Paint) — usually a hero image
Target: < 2.5s. Most failing Webflow sites land between 3-5s.
Diagnose which element is LCP
Open the site detail page and find any page where LCP > 2.5s. You need to know which DOM element Lighthouse flagged as LCP before you can fix it.
Two ways:
- Via Claude MCP (fastest): ask Claude, connected to Site Health, "What's the LCP element on the homepage of [site]?" It calls
get_lcp_elementsand tells you exactly which selector (e.g.,img.hero-imageorh1.hero-heading). - Via the dashboard: expand Element details on the page's diagnostics tab. Shows the selector, snippet, and size.
90% of the time it's one of:
- A hero image (usually an oversized PNG)
- A webfont that's blocking text render
- A CMS-bound feature image above the fold
Fix: hero image
In the Webflow Designer:
- Select the image element
- Right panel → Settings (gear icon)
- Enable Use Webflow responsive images (generates
srcsetwith 480w, 768w, 1080w, 1440w, 1920w variants automatically) - Replace the source with a
<200KBoptimized file. Use Squoosh or similar — export AVIF if the design allows, WebP otherwise, JPEG as fallback - Add
loading="eager"andfetchpriority="high"via the Custom attributes field if the image is above the fold — Webflow defaults to lazy loading, which hurts LCP
Publish and re-scan. You'll typically see LCP drop by 1-2 seconds from this fix alone.
Fix: webfont blocking
If the LCP element is text (h1, .hero-heading), the font is the bottleneck, not the image.
In Webflow Project Settings → Custom Code → Head, add:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com">
For uploaded custom fonts (not Google Fonts), add this CSS to Site Settings → Custom Code → Head:
<style>
@font-face {
font-family: 'YourFont';
font-display: swap;
}
</style>
Webflow doesn't set font-display: swap by default on uploaded fonts. Without it, text is invisible until the font downloads — which Lighthouse counts as LCP time.
CLS (Cumulative Layout Shift) — usually late-loading content
Target: < 0.1. Failing sites usually sit between 0.15-0.35.
Diagnose
On the site detail page, CLS element details show which elements are shifting. Common offenders on Webflow sites:
- Images without explicit dimensions in custom embeds
- Navbars that switch from static to
position: fixedafter JS runs - Intercom / Drift / chat widget launchers that inject late
- Banner ad slots or cookie banners
Fix 1: explicit dimensions on media
Webflow's native Image element sets width/height automatically. But custom HTML Embeds, Rich Text embedded images, and third-party widgets often don't.
For any <img> in a Custom Code Embed, always set both:
<img src="..." width="800" height="600" alt="...">
For videos and iframes, wrap in an aspect-ratio container:
<div style="aspect-ratio: 16/9; width: 100%;">
<iframe src="..." style="width: 100%; height: 100%;"></iframe>
</div>
Fix 2: fixed navbar placeholder
A navbar with position: fixed shifts everything below it when JS activates. Solution: reserve the space with a placeholder div matching the nav height.
In Webflow, wrap the page body in a parent section with padding-top: 80px (or your nav height). This keeps the viewport layout identical before and after JS runs.
Alternatively, use position: sticky instead of position: fixed — sticky participates in layout flow, so there's nothing to shift around.
Fix 3: reserve space for late-loading widgets
Intercom's launcher is 60×60px in the bottom-right. If it injects after scroll, it can trigger a CLS measurement on interaction. Pre-reserve the space:
<style>
/* Reserve Intercom launcher space */
body::before {
content: '';
position: fixed;
bottom: 20px;
right: 20px;
width: 60px;
height: 60px;
pointer-events: none;
}
</style>
Same pattern for cookie banners, promotional bars, and ad slots — reserve the space in the initial render.
INP (Interaction to Next Paint) — usually heavy JavaScript
Target: < 200ms. This replaced FID as a Core Web Vital in March 2024 and it's much harder to pass.
Diagnose
Open the Third-Party Scripts dashboard (/sites/[siteId]/scripts) and sort by blocking time. Any script over 300ms is a suspect. See the Scripts feature docs for full detail.
Also: check IX2 interaction count on CMS template pages. Webflow's native interaction system runs interactions per-element, so a list of 50 CMS items with hover effects compounds into thousands of event listeners on initial load.
Fix: defer non-critical scripts
In Webflow Project Settings → Custom Code → Footer, wrap non-critical scripts in requestIdleCallback:
<script>
requestIdleCallback(() => {
const s = document.createElement('script');
s.src = 'https://example.com/analytics.js';
s.async = true;
document.body.appendChild(s);
}, { timeout: 3000 });
</script>
For scripts you must load but don't need immediately (chat widgets, email capture popups), use setTimeout:
<script>
setTimeout(() => {
// Inject Intercom, Drift, etc. here
}, 4000);
</script>
Never put third-party scripts in the Head section unless they absolutely must run there (e.g., GTM). The Webflow Integrations panel (Google Analytics, Facebook Pixel, etc.) loads these synchronously and blocks render. Move them to the Footer as custom code instead.
Fix: reduce IX2 on CMS pages
IX2 (Webflow's interaction system) creates one listener per triggering element. On a CMS Collection List with 50 items and hover interactions on each, that's 50 individual event handlers attached on page load.
Fix: limit complex interactions to elements users actually interact with. Avoid "on scroll into view" animations for items below the fold — use content-visibility: auto CSS instead to defer rendering.
Fix: audit third-party scripts ruthlessly
If the Scripts dashboard shows 8+ third-party origins, half of them are probably dead weight. For each one, ask: does this script directly drive revenue or product? If no, remove it. Marketers accumulate pixels; your job is to prune them.
Summary checklist
Do these three and most Webflow sites jump 15-25 Performance points:
- Hero image optimized (
<200KB, AVIF/WebP, responsive srcset enabled,fetchpriority="high") -
font-display: swapset on all custom fonts - Webfont preconnect added to
<head> - Explicit width/height on all custom embed images, iframes, videos
- Navbar has layout-reserved placeholder (or is sticky, not fixed)
- Late-loading widgets (chat, cookie banner) have reserved space
- Non-critical scripts moved from Integrations panel / Head to deferred Footer embeds
- IX2 interactions audited on CMS pages — nothing below-the-fold animated
- Third-party script count in Scripts dashboard reduced to essentials only
Re-run the scan. Screenshot the before/after for your client report. Done in under an hour.