
Core Web Vitals on Cloudflare Pages: How to Hit Green
Core Web Vitals are a Google ranking signal, they affect AI engine citation indirectly (faster sites get crawled more often and quoted more often), and they affect conversion measurably. The fixes below are what move a SvelteKit + Cloudflare Pages site from yellow to green.
I am Ignacio (IGNAX), Spain-born and Paraguay-based, a solo full-stack developer and SEO/AEO specialist. The companion deployment-side article is Cloudflare Pages SEO setup; the audit-service that covers CWV as a section is technical SEO audit.
What are the current CWV targets?
The 2026 thresholds in PageSpeed Insights:
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤ 2.5s | 2.5–4.0s | > 4.0s |
| INP (Interaction to Next Paint) | ≤ 200ms | 200–500ms | > 500ms |
| CLS (Cumulative Layout Shift) | ≤ 0.1 | 0.1–0.25 | > 0.25 |
INP replaced FID in March 2024 and is the most commonly missed metric on JavaScript-heavy sites. The fix is almost always reducing main-thread blocking on user interactions, not optimizing rendering.
The targets are 75th percentile of real-user data from CRUX (Chrome User Experience Report). Hitting green on synthetic Lighthouse is necessary but not sufficient, you also need real-user data to confirm.

What does Cloudflare Pages give you for free?
Out of the box, Cloudflare Pages handles a lot:
- Edge-served HTML with sub-50ms TTFB globally. Eliminates a class of LCP issues where the server is the bottleneck.
- Brotli compression by default on all text responses. Smaller payloads, faster first paint.
- HTTP/3 by default. Multiplexed, lower latency, especially on mobile.
- Free SSL via Cloudflare's CA. No TLS negotiation surprises.
- Smart Tiered Cache routes upstream requests through the closest cache, reducing variance on cache misses.
- Polish (paid): automatic image format negotiation. Drops PNG to WebP/AVIF on the fly for browsers that support them.
The wins compound. A SvelteKit site prerendered to Cloudflare Pages with no special optimization typically hits LCP 1.5–2.0s, INP under 100ms, CLS under 0.05, green across the board, on a marketing page with a single hero image and minimal JavaScript.
The losses, when they happen, come from heavy client-side JavaScript or unoptimized hero images. Both are application-level, not Cloudflare-level.
How do I fix LCP on Cloudflare Pages?
LCP is dominated by two things: the size of the LCP element and how quickly the browser knows to fetch it.
Image LCP elements (the most common case):
<img
src="/portrait-480.webp"
srcset="/portrait-240.webp 240w, /portrait-480.webp 480w"
sizes="(max-width: 640px) 240px, 480px"
width="480"
height="640"
alt="Ignacio (IGNAX), Paraguay-based full-stack developer"
fetchpriority="high"
decoding="async"
/>
Five things doing real work in that tag:
- WebP format: 25–35% smaller than the equivalent JPEG.
- Responsive srcset: the browser picks the right resolution for the viewport.
- Explicit width and height: prevents CLS during load.
- fetchpriority="high": tells the browser to prioritize this resource over scripts and other images.
- decoding="async": allows the browser to decode off the main thread.
Pair that with a preload hint in <head>:
<link
rel="preload"
as="image"
href="/portrait-480.webp"
imagesrcset="/portrait-240.webp 240w, /portrait-480.webp 480w"
imagesizes="(max-width: 640px) 240px, 480px"
fetchpriority="high"
/>
That combination drops LCP from 3–4s to under 2s on a typical hero-image page. The Cloudflare Pages docs include guidance on serving images, but the core work happens in your HTML.
Text LCP elements (less common, easier to fix):
- Inline critical font CSS or use
font-display: swap. - Preload the LCP font with
<link rel="preload" as="font" crossorigin>. - Avoid
@font-facewith web fonts that delay first paint.
For background reading the web.dev LCP guide is the canonical resource.
How do I fix INP?
INP measures the latency of user interactions, clicks, taps, key presses, to the next paint. The metric is the worst case across all interactions, not the average.
In order of impact:
- Cut client-side JavaScript. SvelteKit's
csr={false}for purely static pages eliminates the entire hydration pass. Each route should opt in to client-side JS only when interactive. - Defer non-critical scripts. Analytics, chat widgets, and tracking pixels go on
deferor load viarequestIdleCallback. - Break up long tasks. Anything taking >50ms on the main thread should be split. The scheduler.yield API in Chrome is the modern way.
- Audit third-party scripts. Hotjar, Intercom, Drift, and Google Tag Manager are the usual INP killers. Replace with privacy-respecting alternatives or load on user interaction.
- Reduce hydration cost. Svelte hydrates per-component; minimize the components that need it.
A SvelteKit site with no third-party scripts and selective CSR typically hits INP under 100ms. Sites with Hotjar, Intercom, and full GTM frequently sit at 300–500ms. The third-party scripts are usually the entire problem.
How do I fix CLS?
CLS is the easiest CWV to fix:
- Images without dimensions. Always set
widthandheightattributes (or use CSSaspect-ratio). Browsers reserve the layout space before the image loads. - Late-injected ads or banners. Reserve the space with a min-height container. If the banner is 60px tall. The container is 60px tall before the banner loads.
- Web fonts causing layout shift on swap. Use
font-display: optionalfor non-critical fonts, or preload the critical font and usefont-display: blockwith a short block period.
CLS under 0.05 is achievable on every SvelteKit site I have shipped. The trick is being disciplined about dimensions on every image and every dynamic element.
What about Cloudflare-specific optimizations?
Beyond the freebies, two paid-tier features move the needle:
- Cloudflare Polish ($5/month for Pro+): automatic WebP/AVIF conversion for legacy image formats. Useful if you cannot pre-generate optimized variants.
- Cloudflare Argo Smart Routing ($5/month + traffic): routes traffic over Cloudflare's private backbone. Reduces variance on cache misses, especially for international users. Most marketing sites do not need this.
For most SvelteKit + Cloudflare Pages sites the free tier is sufficient. The optimizations are in your HTML, not in the Cloudflare dashboard.
How do I measure CWV in production?
Three tools, three jobs:
- PageSpeed Insights: synthetic Lighthouse + 28-day CRUX data for the URL. Use this for benchmarking and reporting.
- Chrome DevTools Performance Insights panel: synthetic on your local machine. Use this for debugging specific issues.
- CRUX Dashboard (Looker Studio template): real-user trends over time. Use this for monitoring after deployment.
I baseline all three on Day 1 of a CWV engagement, share the dashboard, and check weekly during the loop. Lighthouse score is a leading indicator; CRUX is the truth.
For the broader Cloudflare Pages setup see Cloudflare Pages SEO setup and the technical SEO audit service page.
What does the SvelteKit config look like?
The relevant settings in svelte.config.js:
import adapter from '@sveltejs/adapter-cloudflare';
export default {
kit: {
adapter: adapter(),
prerender: {
handleHttpError: 'warn',
crawl: true,
},
},
};
And per-route in +page.ts:
export const prerender = true;
export const csr = false; // disable client-side JS on purely static pages
The csr = false is the highest-leverage setting on a content-heavy site. It eliminates the entire SvelteKit hydration pass on pages that have no interactivity. LCP, INP, and bundle size all improve.
How do I avoid third-party-script regressions?
The fastest CWV regressions come from adding tracking and chat tools:
- Cloudflare Web Analytics instead of Google Analytics. No script needed; the beacon is fired by Cloudflare's edge.
- No chat widget until you have a user actually asking for one. Intercom, Drift, and Crisp all weigh 200–500 KB.
- Defer all analytics scripts to
idleevents. UserequestIdleCallbackordeferattributes. - Self-host fonts rather than loading from Google Fonts. Eliminates the third-party DNS lookup and connection cost.
Each third-party script is a CWV tax. Pay it only when the business value justifies it.
What external references should I read?
- web.dev, Core Web Vitals overview: canonical reference for thresholds and patterns.
- Cloudflare Pages documentation: official Pages reference including caching and image handling.
- SvelteKit adapter-cloudflare documentation: adapter-specific config.
- Google Search Central, page experience: how CWV affects ranking.
A SvelteKit + Cloudflare Pages site, prerendered, with optimized images and minimal third-party JavaScript, hits green CWV without heroics. The work is application-level discipline, not infrastructure magic.
Ready to fix CWV on your site? Email hello@ignax.dev with your URL. I baseline before the call.
Frequently asked questions
What are the current Core Web Vitals targets?
LCP (Largest Contentful Paint) under 2.5 seconds, INP (Interaction to Next Paint) under 200 milliseconds, CLS (Cumulative Layout Shift) under 0.1. These are the 'Good' thresholds in PageSpeed Insights as of 2026. The 'Needs Improvement' range is LCP 2.5–4s, INP 200–500ms, CLS 0.1–0.25. Above those is 'Poor' and Google treats it as a ranking demerit.
Does Cloudflare Pages help Core Web Vitals out of the box?
Yes, mostly. Cloudflare serves prerendered HTML from the edge with sub-50ms TTFB globally, automatic Brotli compression, HTTP/3 by default, and free SSL. The CWV wins come from the edge being close to the user. The losses, when they happen, come from heavy client-side JavaScript or unoptimized images that Cloudflare cannot fix for you, those are application-level issues.
What is the single biggest LCP killer in SvelteKit apps?
Unoptimized hero images. A 1.5 MB JPEG hero ships in 3+ seconds even on fast connections. Convert to WebP or AVIF, serve responsive variants, set explicit width and height attributes, and add fetchpriority='high' on the LCP element. That single change typically drops LCP from 3.5s to under 2s on Cloudflare Pages.
How do I measure CWV correctly?
Three tools, three different jobs. PageSpeed Insights runs synthetic Lighthouse and pulls real-user CRUX data, use it for benchmarking. Chrome DevTools Performance Insights runs synthetic on your machine, use it for debugging. The CRUX Dashboard (BigQuery or Looker Studio) shows 28-day real-user trends, use it for monitoring after deployment.
Does Cloudflare's Auto Minify still exist?
Cloudflare deprecated standalone Auto Minify in 2024 in favor of Speed Brain and Smart Tiered Cache. SvelteKit handles minification at build time via Vite, so the loss is irrelevant for SvelteKit sites. The Cloudflare optimizations that still matter are Brotli, HTTP/3, Polish for images, and edge caching tuned via the Pages prerender settings.
When should I use Cloudflare Images?
When you need on-demand resizing and format negotiation for user-uploaded content. For static marketing assets (your hero, your portrait, your case study images), shipping pre-built WebP and AVIF variants from the SvelteKit static folder is cheaper and faster than Cloudflare Images. The fee on Cloudflare Images is $5/month plus per-thousand-transformations; not worth it for a marketing site under 1000 images.