AldeaCode Logo
SEO Monitorización de usuarios reales con Core Web Vitals (2026)
SEO AldeaCode Architecture

Monitorización de usuarios reales con Core Web Vitals (2026)

Monta RUM para medir LCP, INP y CLS de usuarios reales. Explicación clara, umbrales y una configuración lista para copiar hoy.

Qué miden de verdad las Core Web Vitals

Las Core Web Vitals son tres números que Google usa para responder una pregunta: cuando una persona real abre tu página, ¿es agradable usarla? Las métricas no son abstractas. Cada una corresponde a algo que el usuario nota.

LCP (Largest Contentful Paint) responde: ¿cuándo aparece el contenido principal? No el spinner, no el esqueleto. La imagen del hero, el titular, la foto del producto. Lo que el usuario vino a ver.

INP (Interaction to Next Paint) responde: cuando toco o hago clic en algo, ¿la página reacciona? Mide el tiempo entre tu dedo y el siguiente repintado visual. Si va a tirones, el INP es malo.

CLS (Cumulative Layout Shift) responde: ¿se mueven las cosas mientras estoy leyendo? Empiezas a leer un párrafo, se carga un anuncio encima, el párrafo baja, pierdes el sitio. Eso es CLS.

Esa es toda la historia. Tres preguntas sobre lo que vive una persona. Lo demás es detalle de implementación.

Los umbrales, y por qué esos números concretos

Google publica valores objetivo para cada métrica. Si pasas las tres, estás en la zona “buena”.

MétricaBuenoMejorableMalo
LCP<2.5s2.5s a 4s>4s
INP<200ms200ms a 500ms>500ms
CLS<0.10.1 a 0.25>0.25

Los números no salen del aire. Vienen de estudios sobre qué perciben los usuarios como rápido, ágil y estable. 2.5 segundos en LCP es aproximadamente la frontera donde la gente empieza a notar la página lenta. 200 ms en INP está cerca del umbral donde la interacción se siente inmediata frente a retrasada. 0.1 de CLS es lo bastante pequeño para que la mayoría no note el desplazamiento de forma consciente.

Hay un segundo número que importa: el percentil 75. Google no mira a tu usuario medio. Mira al cuarto más lento. Si tu LCP en p75 es 2.5 segundos, significa que el 75% de tus visitas reales fue más rápido y el 25% peor fue más lento. La razón es sencilla. Las medias esconden el dolor. Una web puede tener una media estupenda y ser inusable para una cuarta parte de su público. El p75 te obliga a preocuparte por la gente con móviles lentos y conexiones flojas.

Los datos de laboratorio mienten. Los datos de campo dicen la verdad.

Hay dos formas de medir el rendimiento, y responden a preguntas diferentes.

Datos de laboratorio son los que da Lighthouse, PageSpeed Insights en modo lab o WebPageTest. Un entorno controlado ejecuta tu sitio en una máquina conocida, con un throttling de red conocido, en un estado conocido. Es reproducible, lo cual va genial para detectar regresiones en CI. Pero no son tus usuarios.

Datos de campo son los que viven los visitantes reales. Su móvil tiene tres años, su navegador tiene 40 pestañas, van en un tren con 4G regular y tienen un bloqueador de anuncios que rompió la mitad de tus scripts. Los datos de campo capturan todo eso.

Si solo miras los números de laboratorio, vas a optimizar para una máquina que no existe. El informe CrUX (Chrome User Experience Report) son datos de campo y es lo que Google usa para el ranking. Tu propio RUM son datos de campo y es lo que te dice qué página, en qué tipo de dispositivo, está haciendo daño a qué usuarios.

La regla práctica: laboratorio para detectar problemas rápido, campo para saber qué dolor estás enviando de verdad a la gente.

RUM en la práctica: capturar, enviar, mirar cada semana

Real User Monitoring suena pesado. No tiene por qué serlo. La configuración mínima viable son tres piezas:

  1. La librería web-vitals corriendo en el navegador.
  2. Un endpoint pequeño en tu backend que acepta los datos.
  3. Una consulta que ejecutas una vez por semana para ver qué empeora.

Así queda la parte del navegador:

import { onLCP, onINP, onCLS } from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    rating: metric.rating,
    id: metric.id,
    page: location.pathname,
    connection: navigator.connection?.effectiveType ?? 'unknown',
  });

  // sendBeacon sobrevive al cierre de página, fetch con keepalive es el plan B
  if (navigator.sendBeacon) {
    navigator.sendBeacon('/api/vitals', body);
  } else {
    fetch('/api/vitals', { body, method: 'POST', keepalive: true });
  }
}

onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);

Eso es todo del lado cliente. La librería se encarga de las partes complicadas: cuándo disparar LCP (puede cambiar conforme cargan elementos más grandes), cuándo el CLS se vuelve definitivo (al ocultarse la página), cómo registrar INP a lo largo de todas las interacciones de la visita.

En el backend, escribe los eventos en el almacén que ya tengas. Una tabla simple en Postgres con name, value, page, connection, created_at basta para empezar. Una vez por semana, lanza algo así:

SELECT
  page,
  PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY value) AS p75,
  COUNT(*) AS samples
FROM vitals
WHERE name = 'LCP'
  AND created_at > NOW() - INTERVAL '7 days'
GROUP BY page
HAVING COUNT(*) > 100
ORDER BY p75 DESC
LIMIT 20;

Las páginas más lentas por LCP en p75, con muestras suficientes para ser significativas. La misma consulta sirve para INP y CLS. Esa lista es tu lista de tareas.

El arreglo de LCP más común: la imagen del hero

En el campo, la mayor mejora de LCP en casi todas las webs está en la imagen grande de la parte superior. Suelen fallar dos cosas:

  1. El navegador no se entera a tiempo y la imagen carga después de las hojas de estilo y los scripts.
  2. No tiene width ni height, así que el layout se reordena cuando llega.

Antes:

<img src="/hero.jpg" alt="Foto de producto">

Y la versión que arregla los dos problemas:

<link rel="preload" as="image" href="/hero.avif" fetchpriority="high">

<img
  src="/hero.avif"
  alt="Foto de producto"
  width="1200"
  height="600"
  fetchpriority="high"
  decoding="async"
>

El preload le dice al navegador que empiece a descargar la imagen en cuanto vea el HTML, en lugar de esperar a que el CSS la referencie. El fetchpriority="high" en la propia etiqueta lo refuerza. El width y height permiten al navegador reservar el hueco antes de que llegue la imagen, lo que también ayuda al CLS. Los formatos modernos como AVIF o WebP hacen el archivo entre un 30 y un 70 por ciento más pequeño que JPEG, lo que se traduce directamente en mejor LCP. Lo cubrimos en nuestra comparativa de WebP y AVIF.

Si esta semana solo tocas una cosa, toca esto en tus tres páginas de aterrizaje principales.

El arreglo de CLS más común: reservar el espacio

El CLS aparece cuando algo entra en la página después de que el layout se haya asentado y empuja al contenido existente. Los dos culpables principales son las imágenes sin dimensiones y los anuncios o embeds sin un hueco reservado.

Para imágenes, define siempre width y height (o usa el aspect-ratio moderno en CSS):

<img src="/foto.jpg" alt="..." width="800" height="450">
.media {
  aspect-ratio: 16 / 9;
  width: 100%;
}

Para anuncios, embeds o cualquier widget de terceros, reserva la caja antes de que cargue:

.ad-slot {
  min-height: 250px;
  min-width: 300px;
}

El principio es el mismo en los dos casos. Dile al layout cuánto va a ocupar la cosa antes de que aparezca. El hueco se queda vacío un instante, luego se llena, pero nada más se mueve.

Una regla extra: nunca inyectes contenido por encima del fold a partir de datos asíncronos. Si tienes que mostrar un banner tras un fetch, píntalo debajo del contenido existente, o usa un contenedor con altura fija que anime la entrada del banner sin empujar.

El arreglo de INP más común: trocear las tareas largas

El INP suele ir alto porque algo corre demasiado tiempo en el hilo principal después de un clic o un toque. El navegador no puede pintar el siguiente frame hasta que el JavaScript termina. Si tu handler tarda 300 milisegundos, el INP es como mínimo 300 milisegundos.

La solución es trocear el trabajo y devolver el control al navegador entre trozos. Chrome moderno soporta scheduler.yield():

async function handleClick(items) {
  // Feedback inmediato
  showSpinner();

  for (const item of items) {
    processItem(item);

    // Deja que el navegador pinte y atienda otros inputs
    if (scheduler.yield) {
      await scheduler.yield();
    } else {
      // Plan B para navegadores antiguos
      await new Promise(resolve => setTimeout(resolve, 0));
    }
  }

  hideSpinner();
}

Cada await libera el hilo principal. El navegador puede pintar el spinner, responder a otros inputs y volver a tu bucle. Visualmente el trabajo total tarda lo mismo, pero la página se siente viva durante todo el proceso.

Otras mejoras habituales de INP:

  • Mueve el trabajo pesado (parsear, ordenar arrays grandes, procesar imágenes) a un Web Worker.
  • Aplaza tareas no críticas con requestIdleCallback.
  • Audita tus event listeners. Un handler de resize con debounce que dispara una función que provoca layout thrashing es un clásico asesino del INP.

Para más detalle sobre INP y qué corre en el hilo principal, mira nuestra guía sobre INP.

Un flujo de trabajo que sí funciona

No hace falta arreglarlo todo de golpe. El truco es convertirlo en hábito semanal en lugar de proyecto de pánico.

  1. Lunes por la mañana. Mira los p75 de la semana pasada, separados por página y métrica. Encuentra la peor regresión o el peor valor absoluto.
  2. Elige una cosa. No cinco. Una. La página con peor LCP, la interacción con peor INP o la sección con más CLS.
  3. Arréglalo. Despliega el arreglo. Si quieres, verifícalo antes en laboratorio, pero la verdad llega con la siguiente semana de datos de campo.
  4. Repite. El lunes siguiente vuelve a mirar. El arreglo funcionó o no. Los datos lo dicen.

Esto le gana a las auditorías puntuales todas las veces. Las webs están vivas. Aterriza código nuevo, se añaden imágenes, marketing añade un tag manager nuevo y el rendimiento se va. Media hora a la semana revisando datos reales detecta las regresiones antes de que se conviertan en emergencias.

Algunas notas extra

Los scripts de terceros son el asesino silencioso de las tres métricas. Cada etiqueta de analítica, widget de chat, framework de A/B testing y red de anuncios añade bytes, bloquea el hilo principal y a veces desplaza el layout. Audítalos una vez al año. Quita los que no se ganan su sitio.

La compresión importa. Brotli para texto, AVIF o WebP para imágenes, fuentes con cache bien configurado. Nada de esto es exótico en 2026, pero en cada auditoría que hacemos hay al menos un sitio donde no está pasando.

El tiempo de respuesta del servidor está debajo de todo. Si tu TTFB (Time To First Byte) es de 800 ms, ya te has comido un tercio del presupuesto de LCP antes de que el navegador haga nada. Cachea con ganas, usa una CDN, mantén el origen ligero.

Y por último, vigila lo básico. Un CSP mal configurado puede bloquear recursos de los que dependes. La falta de HSTS puede provocar redirecciones innecesarias. Código que no es eficiente en el hilo principal se nota como mal INP. El rendimiento es una propiedad del sistema, no un ajuste único.

Preguntas frecuentes

¿Necesito un servicio de RUM de pago?

No. La librería web-vitals más un endpoint sencillo en tu backend va bien para la mayoría de los sitios. Un servicio de pago vale la pena cuando quieres dashboards listos, alertas y segmentación detallada sin escribirla tú, o cuando tienes tanto tráfico que el almacenamiento y las consultas se convierten en trabajo de ingeniería de verdad.

Mi puntuación de Lighthouse es 95 pero mis números de CrUX son malos. ¿Qué pasa?

Lighthouse corre en una máquina simulada rápida y en un entorno tranquilo. Tus usuarios reales van con dispositivos más lentos y redes peores. La diferencia entre los dos es normal. Cuando tengas datos de campo, fíate de ellos.

¿Cuánto tarda un arreglo en aparecer en los datos de campo?

CrUX usa una ventana móvil de 28 días, así que ahí los cambios se ven despacio. Tu propio RUM se actualiza al instante y normalmente puedes ver el impacto de un arreglo en pocos días, en cuanto haya muestras suficientes.

¿Optimizo para CrUX o para mi propio RUM?

Para los dos. CrUX es lo que Google usa como señal de ranking. Tu propio RUM te da feedback más rápido y te permite segmentar por página, dispositivo y país. Deberían coincidir en la dirección. Si no lo hacen, investiga por qué.

Lo que hacemos

Webs honestas, sin atajos.

Ingeniería real y diseño cuidado. Si te ha gustado el post, hablemos del tuyo.

Hablemos →

Te puede interesar

Ver todos los artículos →