Pulsas en «Añadir al carrito», abres el menú en el móvil o eliges un filtro, y durante un instante la página no reacciona. No hay error ni pantalla en blanco: simplemente tarda en responder. Esa sensación de web «pegajosa» es justo lo que mide INP (Interaction to Next Paint), una de las tres métricas de Core Web Vitals.
Vemos qué mide de verdad, cómo se interpreta en los informes de Google, cómo localizar el origen del problema con herramientas gratuitas y qué cambios suelen funcionar. Empezamos por el porqué.
Qué es INP y qué umbrales tiene
INP mide la latencia de las interacciones de una persona con tu página a lo largo de toda la visita. Cuenta los clics con ratón, los toques en pantallas táctiles y las pulsaciones de teclado. No cuenta el desplazamiento (scroll) ni pasar el cursor por encima. Para cada interacción mide el tiempo que pasa desde que la persona actúa hasta que el navegador pinta el siguiente fotograma con el resultado (de ahí el nombre, «interacción hasta el siguiente pintado»). Después se queda con un valor representativo de la visita: en general, el de la interacción más lenta, aunque en páginas con muchísimas interacciones se descartan algunos valores extremos para no penalizar un tropiezo aislado.
INP sustituyó a FID (First Input Delay) como Core Web Vital en marzo de 2024. FID tenía dos limitaciones importantes: solo medía la primera interacción y solo la espera previa a empezar a procesarla, no lo que tardaba la página en reaccionar. Una web podía aprobar FID con nota y sentirse lenta al tercer clic. INP cubre todas las interacciones y el recorrido completo hasta que se ve el resultado, así que se parece mucho más a lo que percibe quien usa la web.
Los umbrales oficiales son estos:
- Bueno: hasta 200 ms.
- Mejorable: entre 200 y 500 ms.
- Malo: más de 500 ms.
El criterio se aplica al percentil 75 de las visitas reales, por separado en móvil y en escritorio. Dicho de otro modo: para que una URL (o un grupo de URLs) se considere buena, al menos tres de cada cuatro visitas deben quedar en 200 ms o menos. Los umbrales y las métricas que componen Core Web Vitals pueden revisarse con el tiempo, así que confirma los valores vigentes en la documentación oficial de web.dev y de Google Search Central.
Las tres fases de una interacción
Una interacción no es un bloque único, y entenderlo es clave porque cada fase tiene causas y soluciones distintas:
- Retardo de entrada (input delay): desde que la persona actúa hasta que el navegador puede empezar a ejecutar tus manejadores de eventos. Se alarga cuando el hilo principal está ocupado con otra cosa: una tarea larga de un script, una carga de terceros, la hidratación del framework.
- Tiempo de procesamiento: lo que tardan en ejecutarse tus manejadores (
click,keydown,pointerup...) y el trabajo que desencadenan. Aquí pesan los cálculos costosos y las actualizaciones grandes del DOM. - Retardo de presentación: desde que terminan los manejadores hasta que el navegador pinta el fotograma siguiente. Incluye recalcular estilos, calcular el diseño (layout) y pintar. Crece con DOM enormes, CSS costoso y cambios que afectan a media página.
Un ejemplo con cifras inventadas solo para ilustrar: un filtro tarda 60 ms en empezar a atenderse, 90 ms en ejecutar su código y 110 ms en pintarse, 260 ms en total. Saber que la mayor parte está en la presentación te lleva a mirar el DOM y el CSS, no a optimizar el manejador.
Datos de laboratorio y datos de campo
INP es, por naturaleza, una métrica de campo: depende de qué pulsa cada persona, en qué dispositivo y en qué momento. Una prueba de laboratorio no sabe qué vas a tocar, así que no puede calcularla igual.
Los datos de campo proceden de CrUX (Chrome User Experience Report), que recoge de forma anónima la experiencia de usuarios reales de Chrome que han aceptado compartirla, agregada en una ventana móvil de 28 días. Esos datos alimentan:
- El informe Core Web Vitals de Search Console, que agrupa URLs similares y separa móvil y escritorio.
- PageSpeed Insights, en su sección de experiencia de usuarios reales, que puede mostrar datos de la URL concreta y del origen completo si hay tráfico suficiente.
Dos consecuencias prácticas. Como la ventana es de 28 días, una mejora tarda semanas en reflejarse del todo. Y si tu web tiene poco tráfico, puede que CrUX no tenga datos suficientes y el informe aparezca vacío.
Los datos de laboratorio se obtienen en un entorno controlado, como Lighthouse (dentro de PageSpeed Insights y de DevTools). Lighthouse en modo navegación no mide INP, porque no simula interacciones; para aproximarse a la capacidad de respuesta suele mirarse el Total Blocking Time, que es solo un indicador indirecto. La regla útil: el campo te dice si hay un problema y el laboratorio te ayuda a averiguar dónde está. Los nombres de informes y secciones cambian de vez en cuando: ante dudas, consulta la documentación.
Cómo diagnosticarlo paso a paso
- Confirma el problema en campo. Entra en Search Console, en el informe Core Web Vitals, y mira si hay URLs con INP en «Mejorable» o «Malo», en móvil o escritorio. Cruza el dato con PageSpeed Insights para las páginas más importantes. Si no hay datos suficientes, tendrás que apoyarte en medición propia (paso 4).
- Reproduce la lentitud en Chrome DevTools. Abre una ventana de incógnito (sin extensiones que añadan ruido), abre el panel Rendimiento (Performance) y activa la ralentización de CPU, por ejemplo 4x, porque tu ordenador es mucho más rápido que un móvil de gama media. Graba, haz la interacción que sospechas (abrir el menú, aplicar el filtro, pulsar el botón) y detén la grabación. En la pista de interacciones verás cada una con su duración desglosada en las tres fases. Las versiones recientes de DevTools incluyen además una vista de métricas en vivo con el INP local.
- Busca las tareas largas. Una tarea larga es cualquier tarea que bloquea el hilo principal más de 50 ms, y DevTools las marca visualmente. Amplía la que coincida con tu interacción, abre el árbol de llamadas (Call Tree o Bottom-Up) y mira qué archivo y qué función acumulan más tiempo. Distingue si es código propio, del tema o plugin, o de un tercero.
- Mide en visitas reales con la librería web-vitals. Es la librería de Google para recoger Core Web Vitals en el navegador. Su versión con atribución te dice qué elemento provocó la interacción lenta y cuánto duró cada fase:
import {onINP} from 'web-vitals/attribution';
onINP(({value, attribution}) => {
console.log('INP', value);
console.log('Elemento', attribution.interactionTarget);
console.log('Entrada', attribution.inputDelay);
console.log('Procesamiento', attribution.processingDuration);
console.log('Presentación', attribution.presentationDelay);
});
Los nombres de las propiedades han cambiado entre versiones de la librería, así que comprueba su documentación antes de copiarlo. En producción, en vez de console.log, envía el resultado a tu analítica (por ejemplo con navigator.sendBeacon o como evento de GA4). Tras unos días tendrás un ranking de qué páginas y elementos dan peor INP.
Un apunte con cautela: la API Long Animation Frames (LoAF) describe, para cada fotograma lento, qué scripts contribuyeron y cuánto tardaron. Sirve para señalar a un script concreto, sobre todo de terceros, pero su soporte se limita a navegadores basados en Chromium y puede evolucionar. Comprueba la compatibilidad antes de depender de ella.
Causas más habituales
- JavaScript pesado en el hilo principal. Bundles enormes, mucho código que se ejecuta nada más cargar, librerías completas para usar una sola función.
- Scripts de terceros. Gestores de etiquetas con muchas etiquetas, chats, píxeles, pruebas A/B, mapas, vídeos incrustados, banners de cookies. Comparten el mismo hilo que tu código y no controlas lo que hacen.
- Hidratación. En frameworks que renderizan en servidor (React, Vue y similares), la página se ve enseguida, pero no responde del todo hasta que el JavaScript «hidrata» los componentes. Un clic en esa ventana sufre un retardo de entrada alto.
- DOM enorme. Miles de nodos encarecen cada recálculo de estilos y de diseño, y eso alarga el retardo de presentación.
- Manejadores lentos. Filtrar cientos de elementos dentro del
click, procesar un JSON gigante, escribir enlocalStoragede forma síncrona o lanzar analítica pesada antes de actualizar la pantalla. - Layout thrashing. Alternar lecturas de medidas (
offsetHeight,getBoundingClientRect()) con escrituras de estilo dentro de un bucle obliga al navegador a recalcular el diseño una y otra vez. - WordPress: plugins y constructores visuales. Es habitual que plugins carguen su JavaScript en todas las páginas aunque solo se usen en una, y que los constructores visuales y los temas multipropósito generen un DOM muy anidado, con sliders, efectos de animación y ventanas emergentes. No todos son culpables, así que mide antes de señalar: en un entorno de pruebas, desactiva uno a uno y compara.
Soluciones concretas
Divide las tareas largas y cede el hilo
El navegador solo puede pintar y atender entradas entre tareas. Si una tarea dura 400 ms, todo lo que ocurra en ese tiempo espera. La solución es trocear el trabajo y «ceder» el hilo entre trozos para que el navegador respire. La opción moderna es scheduler.yield(), que mantiene la prioridad de lo que viene después, pero no está disponible en todos los navegadores, así que se usa con un plan B basado en setTimeout:
function cederHilo() {
if ('scheduler' in globalThis && 'yield' in scheduler) {
return scheduler.yield();
}
return new Promise(resolve => setTimeout(resolve, 0));
}
async function procesarLista(items) {
let ultimaCesion = performance.now();
for (const item of items) {
procesar(item);
if (performance.now() - ultimaCesion > 40) {
await cederHilo();
ultimaCesion = performance.now();
}
}
}
La idea es no pasar mucho más de unas decenas de milisegundos sin ceder el control. Verifica la compatibilidad actual de scheduler.yield() en MDN o en caniuse antes de decidir si el plan B es necesario en tu caso.
Haz menos trabajo por interacción
Lo primero que debe ocurrir al pulsar es el feedback visual: un estado de carga, un botón que cambia, un panel que se abre. El resto puede esperar un fotograma:
boton.addEventListener('click', async () => {
boton.classList.add('cargando');
await cederHilo();
aplicarFiltros();
});
Otras formas de reducir el trabajo: aplicar debounce a los campos de búsqueda que filtran mientras escribes, mover cálculos pesados a un Web Worker, no volver a renderizar todo cuando cambia una parte, virtualizar listas muy largas y, en React, marcar las actualizaciones no urgentes con startTransition.
Controla los scripts de terceros
Haz inventario de lo que se carga (pestaña Red de DevTools) y pregúntate de cada script si sigue aportando algo. Elimina lo que no se use, carga con async o defer lo que pueda esperar y retrasa lo no crítico (un chat, un mapa) hasta que haya interacción o hasta pasado el arranque. En vídeos incrustados, una imagen de marcador que carga el reproductor solo al pulsar evita su código en cada visita. Con lo que afecta a obligaciones legales, como el consentimiento de cookies, no se trata de quitarlo, sino de elegir una solución ligera. Mide antes y después de cada cambio para saber qué ha servido de verdad.
Reduce el coste de renderizar
Si el cuello de botella está en la presentación, ataca el tamaño del DOM y el trabajo de pintado. En secciones largas que quedan fuera de pantalla, content-visibility permite al navegador saltarse su renderizado hasta que se necesite:
.seccion-larga {
content-visibility: auto;
contain-intrinsic-size: auto 800px;
}
El segundo valor es una estimación de altura para que la barra de desplazamiento no dé saltos; pruébalo bien, porque una estimación muy errónea puede notarse. Y si tienes layout thrashing, agrupa primero todas las lecturas de medidas en una pasada y después todas las escrituras de estilo en otra, en lugar de alternarlas dentro del mismo bucle.
Anima con CSS y usa listeners pasivos
Las animaciones con transform y opacity definidas en CSS suelen resolverse sin tocar el hilo principal en cada fotograma, mientras que una animación en JavaScript que cambia top o left en cada vuelta lo satura. Para eventos de scroll, toque o rueda, registra los listeners como pasivos, con { passive: true }, cuando no necesites cancelar el comportamiento por defecto. El scroll no cuenta en INP, pero un manejador pesado de scroll puede bloquear el hilo justo cuando alguien intenta pulsar algo.
Qué esperar en SEO y checklist final
INP forma parte de la experiencia de página. Google ha indicado que Core Web Vitals son una de las señales que consideran sus sistemas de clasificación, pero también que la relevancia del contenido pesa mucho más. Piensa en INP como una señal ligera: mejorarlo no te hará subir posiciones por sí solo, y no podemos prometer resultados concretos. Lo que sí suele notarse es la experiencia: menos frustración, formularios y carritos que responden mejor y, en consecuencia, menos abandonos. Y como los datos de campo se calculan sobre 28 días, espera ver el efecto en Search Console tras varias semanas.
Checklist para repasar:
- Has mirado el INP en Search Console y PageSpeed Insights, en móvil y en escritorio.
- Has reproducido la interacción lenta en DevTools con la CPU ralentizada.
- Sabes en qué fase se va el tiempo: entrada, procesamiento o presentación.
- Has localizado las tareas largas y el script responsable, y mides con usuarios reales.
- Has troceado las tareas largas y cedes el hilo cuando hace falta.
- El manejador da feedback visual primero y deja lo pesado para después.
- Has revisado cada script de terceros y has eliminado o retrasado los prescindibles.
- En WordPress, has comprobado qué plugins y constructores cargan JavaScript donde no hace falta.
- Has reducido el DOM o aplicado
content-visibilitydonde procede. - Las animaciones usan CSS (
transform,opacity) y los listeners de scroll son pasivos. - Has anotado la fecha del cambio y revisarás los datos dentro de 28 días.
Preguntas frecuentes
¿Por qué mi puntuación de PageSpeed es alta y aun así mi INP sale mal?
Porque la puntuación de rendimiento de Lighthouse es una prueba de laboratorio que no simula tus interacciones reales, mientras que el INP de campo viene de visitas reales, con dispositivos más lentos y usos que no has previsto. Fíate del dato de campo para saber si hay problema y usa el laboratorio para investigar la causa.
¿Qué hago si no aparecen datos de INP para mi web?
Suele significar que no hay tráfico suficiente en Chrome para que CrUX publique datos de esa URL. Puedes mirar los datos del origen completo si están disponibles, o medir tú mismo con la librería web-vitals y enviar los valores a tu analítica.
¿Cuánto tarda en notarse una mejora de INP?
En tus pruebas con DevTools o en tu medición propia la mejora se ve de inmediato. En Search Console y en los datos de CrUX tarda más, porque se calculan sobre una ventana móvil de 28 días: los datos antiguos se van sustituyendo poco a poco por los nuevos. Lo razonable es esperar varias semanas antes de sacar conclusiones.