Ilustración de Core Web Vitals en Cloudflare Pages: tres medidores en verde para LCP, INP y CLS

Core Web Vitals en Cloudflare Pages: cómo optimizar en 2026

Core Web Vitals son las tres métricas de performance que Google usa como señal de ranking y que ChatGPT con browsing usa indirectamente para evaluar calidad de fuente. Cloudflare Pages ya da un suelo alto por su edge global, pero llegar a 90+ Lighthouse en mobile requiere atención al código, no solo al hosting.

Soy Ignacio y deployo todos mis sitios y los de mis clientes en Cloudflare Pages desde 2023. Lo que sigue está pensado para SvelteKit pero la mayoría aplica a Next.js, Astro o cualquier framework SSR en Cloudflare. Si todavía no configuraste el setup base, mirá Cloudflare Pages SEO.

¿Cuáles son los Core Web Vitals en 2026?

Tres métricas, todas medidas en datos de campo (CrUX, Chrome User Experience Report):

Métrica Significado Objetivo bueno Objetivo malo
LCP Largest Contentful Paint <2.5s >4s
INP Interaction to Next Paint <200ms >500ms
CLS Cumulative Layout Shift <0.1 >0.25

INP reemplazó a FID en marzo 2024 como métrica oficial. Es más estricta porque mide cada interacción, no solo la primera. Pasar las tres en p75 mobile (no en promedio) es lo que mueve ranking. Gráfico waterfall de performance mostrando tiempos de carga de requests para Core Web Vitals en edge

¿Por qué Cloudflare Pages da buenos defaults?

Hay tres ventajas estructurales sobre alternativas:

  1. Edge global con 300+ ubicaciones. TTFB <100ms en la mayoría de regiones, incluido LATAM y SE Asia (donde Vercel y Netlify tienen huecos).
  2. Zero cold start en assets estáticos. Imágenes, CSS, JS pre-renderizados se sirven desde el edge sin runtime overhead.
  3. HTTP/3 + QUIC por defecto. Conexiones más rápidas en redes móviles inestables.

Pero estos beneficios desaparecen si tu app sirve 500KB de JavaScript hidratado en home. El hosting da el suelo; el techo depende de lo que construyas.

¿Cómo optimizo LCP en SvelteKit + Cloudflare Pages?

LCP mide cuánto tarda en renderizarse el elemento más grande del viewport inicial. Típicamente es un hero image, un título, o un banner.

1. Imágenes en formato moderno

AVIF es 30% más chico que WebP, que es 30% más chico que JPEG. Ahora todos los navegadores modernos soportan AVIF y WebP. SvelteKit con @sveltejs/enhanced-img genera variantes automáticas:

<script>
  import heroImg from '$lib/assets/hero.jpg?enhanced';
</script>

<enhanced:img src={heroImg} alt="Hero" width="1200" height="600" />

Esto compila a <picture> con sources en AVIF, WebP, y JPEG fallback, todos en múltiples tamaños (srcset).

Alternativa: Cloudflare Images sirve transformaciones on-the-fly desde un solo origen.

2. Dimensiones explícitas

Cada imagen del above-the-fold debe tener width y height declaradas. Sin esto. El navegador hace reflow cuando carga la imagen → CLS alto + LCP demorado.

3. Preload del recurso LCP

En SvelteKit, en +layout.svelte o +page.svelte:

<svelte:head>
  <link rel="preload" as="image" 
        href={heroImgAvif.src} 
        type="image/avif"
        fetchpriority="high" />
</svelte:head>

fetchpriority="high" es una señal nueva (2024) que prioriza este recurso sobre otros. Combinado con preload, baja LCP en ~30% en sitios con hero image.

4. TTFB bajo con SSR en edge

SvelteKit deployado en Cloudflare Workers (adapter-cloudflare) tiene TTFB típico <100ms. Si usás un adapter Node tradicional. El TTFB puede subir a 300-800ms según región, y eso golpea LCP directo.

¿Cómo optimizo INP?

INP es la métrica más difícil porque mide latencia de interacciones reales, no de carga inicial. Los culpables típicos:

JavaScript bloqueante

Cada vez que el thread principal queda ocupado >50ms, las interacciones del usuario se demoran. Las causas:

  • Hidratación masiva del framework (Next.js con páginas client-rendered es el peor ofensor en 2026).
  • Librerías de analytics que se ejecutan en main thread (GA4, GTM, Hotjar).
  • Animaciones JavaScript que deberían ser CSS.

Solución SvelteKit: SvelteKit hidrata progresivamente y los componentes islas son livianos por default. La comparación frente a Next.js en métricas reales está en SvelteKit vs Next.js para SEO. Para sitios con mucho contenido estático + interactividad puntual, declarar <svelte:options runes={true} /> y usar $state solo donde hace falta.

Event handlers pesados

Si tu click handler hace un fetch sincrónico bloqueante, INP se va al techo. Patrón correcto:

<script lang="ts">
  let loading = $state(false);

  async function handleClick() {
    // UI feedback inmediato, bloquea <16ms
    loading = true;
    // Trabajo pesado en microtask
    await new Promise(r => setTimeout(r, 0));
    const result = await fetch('/api/heavy');
    loading = false;
  }
</script>

El setTimeout(0) libera el thread para que el navegador pinte el estado loading antes de bloquear con el fetch.

Analytics no-bloqueantes

Para Cloudflare Analytics, usá Web Analytics Beacon que se carga async y no bloquea. Si necesitás GA4, cargalo con loading="lazy" y delegado a un Web Worker via Partytown.

¿Cómo optimizo CLS?

CLS mide el shift visual acumulado: cuántos elementos saltan en el viewport durante la carga.

Fuentes web

Causa #1 de CLS mal. Tres reglas:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap;
  /* Ajustar para minimizar shift entre fallback y fuente final */
  size-adjust: 102%;
  ascent-override: 90%;
  descent-override: 22%;
}

Preload de la fuente crítica:

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

Imágenes sin dimensiones

Como en LCP: cada imagen debe tener width y height o estilo aspect-ratio declarado.

Contenido inyectado after-load

Banners de cookies, popups de newsletter, anuncios, todo lo que aparece después del paint inicial empuja el contenido y suma CLS. Solución: reservar espacio con min-height o cargar los elementos en posiciones fijas que no afecten el flow.

¿Qué stack uso para llegar a 95+ Lighthouse?

Mi setup default en Cloudflare Pages + SvelteKit:

  • SvelteKit con adapter-cloudflare. SSR en Workers.
  • @sveltejs/enhanced-img para imágenes (AVIF + WebP + responsive).
  • Tailwind con purge agresivo. CSS final típico: <15KB.
  • Inter o Geist via @fontsource con preload. Solo el weight del above-the-fold.
  • Sin librerías de analytics pesadas. Cloudflare Web Analytics (beacon liviano) y server-side via Cloudflare Logs.
  • Code splitting por ruta. SvelteKit lo hace automático.

Con este setup, ignax.dev pasa Core Web Vitals en mobile p75 y rinde 96+ en Lighthouse mobile.

¿Cómo mido lo real, no lo sintético?

Solo el campo cuenta. Tres fuentes:

  1. Google Search Console → Core Web Vitals. Datos CrUX (Chrome UX Report) de usuarios reales. Necesitás >28 días de datos.
  2. PageSpeed Insights ingresando tu URL. Combina campo (cuando hay datos) + lab.
  3. Librería web-vitals integrada en tu app. Reporta a Cloudflare Analytics o a tu propio endpoint.

Lighthouse local es útil para iterar (Chrome DevTools → Lighthouse), pero no es la métrica que Google usa para ranking.

¿Qué hacés si CrUX no tiene datos para tu sitio?

Sitio nuevo o de bajo tráfico no aparece en CrUX hasta acumular suficientes muestras (~28 días con tráfico mínimo). En esa fase:

  • Confiá en Lighthouse mobile + librería web-vitals integrada.
  • Una vez que CrUX tenga datos, compará contra Lighthouse para calibrar tus tests sintéticos.

¿Qué errores comunes evitar?

Estos son los cinco que más veo en auditorías:

  1. Imágenes JPEG en home cuando AVIF/WebP están disponibles. -30% LCP gratis.
  2. Sin font-display: swap. FOIT (flash of invisible text) → CLS alto + bad UX.
  3. Analytics cargadas síncronas. GA4 sin async puede sumar 200-500ms a INP.
  4. Hidratación masiva en frameworks pesados. Next.js con App Router sin optimizar usa más JS que la mayoría de sitios necesitan.
  5. Cache headers genéricos. Cloudflare Pages permite cache fino: usalo para assets estáticos (1 año) vs HTML (5 min).

¿Cómo arranco mañana?

Tres acciones de mayor ROI:

  1. Pasá imágenes del above-the-fold a AVIF + WebP con preload. 2 horas.
  2. Implementá font-display: swap + size-adjust en todas las @font-face. 30 minutos.
  3. Verificá Web Analytics liviano (Cloudflare beacon) y desactivá librerías pesadas innecesarias. 1 hora.

Si querés una auditoría completa con plan de acción priorizado, el servicio está como auditoría SEO técnica con detalle en qué incluye una auditoría SEO. El rango de precios para Paraguay está en precio de auditoría SEO en Paraguay. Referencia oficial: Core Web Vitals en web.dev.

Preguntas frecuentes

¿Qué son los Core Web Vitals en 2026?

Tres métricas que Google usa como señal de ranking: LCP (Largest Contentful Paint, debe ser <2.5s), INP (Interaction to Next Paint, debe ser <200ms, reemplazó a FID en 2024), y CLS (Cumulative Layout Shift, debe ser <0.1). Se miden en datos de campo reales (Chrome UX Report), no en tests sintéticos. Pasar las tres en mobile es lo que mueve la aguja. desktop es más fácil y pesa menos.

¿Cloudflare Pages da buena performance por defecto?

Sí, mejor que Vercel y Netlify en métricas de campo para sitios pequeños y medianos. Edge global con 300+ ubicaciones, zero cold start en assets estáticos, y HTTP/3 por default. Pero buenas defaults no garantizan 90+ Lighthouse; el código de la app importa. Si servís 500KB de JavaScript en home, ningún CDN te salva. Cloudflare Pages te da el suelo alto; el techo depende de cómo construyas la app.

¿Cómo optimizo LCP específicamente?

Tres palancas en orden de impacto: 1) Servir imágenes en formato moderno (AVIF o WebP) con dimensiones explícitas y srcset responsive, Cloudflare Images o el módulo de imágenes de SvelteKit lo automatizan; 2) Preload del recurso LCP en el HTML inicial (`<link rel='preload'>`); 3) Reducir el tiempo del server: SvelteKit con SSR en Cloudflare Workers da TTFB <100ms en la mayoría de regiones.

¿Y INP, que reemplazó a FID?

INP es la métrica más difícil en 2026 porque mide la latencia real de cada interacción del usuario, no solo la primera. Los culpables típicos: JavaScript bloqueante en el thread principal, hidratación masiva en frameworks como Next.js, y event handlers pesados. SvelteKit ayuda porque su hidratación es más liviana, pero igual hay que medir. Usá Chrome DevTools → Performance → INP debugger para encontrar las interacciones problemáticas.

¿Qué pasa con CLS y las fuentes?

Las fuentes web son la causa #1 de CLS mal. Tres reglas: 1) `font-display: swap` en cada @font-face (o `optional` si querés evitar el flash); 2) preload selectivo de la fuente crítica del above-the-fold: `<link rel='preload' as='font' crossorigin>`; 3) usar `size-adjust` y `ascent-override` en @font-face para minimizar el shift entre fuente fallback y fuente final. Verlo en acción con [Font Style Matcher](https://meowni.ca/font-style-matcher/).

¿Cómo mido Core Web Vitals reales y no sintéticos?

Tres fuentes: 1) Google Search Console → Core Web Vitals report (datos de campo CrUX); 2) PageSpeed Insights ingresando tu URL (combina campo + lab); 3) librería web-vitals integrada en tu app que reporta a tu analytics o a Cloudflare Analytics. Los tests sintéticos (Lighthouse local) son útiles para iterar, pero solo el campo cuenta para ranking. Sin >28 días de datos de campo, no sabés realmente.