INP en Core Web Vitals: qué es y cómo mejorarlo
Qué mide el INP, en qué se diferencia del FID y cuál de las tres fases corregir primero.
- Bueno ≤ 200 ms
- Necesita mejorar ≤ 500 ms
- Malo > 500 ms
Compartir
¿Qué es Interaction to Next Paint (INP)?
Interaction to Next Paint (INP) es el Core Web Vital (CWV) de capacidad de respuesta: el tiempo transcurrido desde un clic, tap o pulsación de tecla hasta el siguiente fotograma en pantalla, medido en la interacción más lenta de una visita a la página. Un buen INP es de 200 milisegundos o menos en el percentil 75.
El visitante percibe un mal INP como un botón que no reacciona por un momento: toca el menú, no cambia nada y vuelve a tocar. El INP es uno de los tres Core Web Vitals, junto con el LCP y el CLS, y Google los utiliza como señal de posicionamiento.
En una página donde se hace mucho clic, el INP descarta un valor atípico por cada 50 interacciones. Una visita sin un solo clic, tap o pulsación de tecla no tiene INP.
INP vs. FID: ¿qué cambió en marzo de 2024?
El INP sustituyó a First Input Delay (FID) como Core Web Vital el 12 de marzo de 2024. El FID solo medía la espera antes de que el navegador empezara a procesar la primera interacción de una visita. El INP mide cada interacción, desde el input hasta el siguiente fotograma en pantalla.
Por tanto, el INP también contabiliza el trabajo que el FID nunca vio: los event handlers que se ejecutan tras la espera, y el cálculo de estilo, layout y paint antes de que la pantalla cambie. Un clic cuyo handler empieza tras 10 ms y luego se ejecuta durante 300 ms pasaba el FID y suspende el INP.
| First Input Delay (FID) | Interaction to Next Paint (INP) | |
|---|---|---|
| Interacciones | La primera | Cada clic, tap y pulsación de tecla |
| Qué se mide | Input delay | Input delay, processing duration y presentation delay |
| Bueno | 100 ms o menos | 200 ms o menos |
| Valor por visita a la página | El retraso del primer input | La interacción más lenta |
¿Qué interacciones mide el INP?
El INP mide clics, taps y pulsaciones de tecla, incluidos los teclados en pantalla. Cada pulsación al escribir en el campo de un formulario es una interacción independiente. El scroll, el hover y el zoom no cuentan como interacciones.
Aun así, el código de scroll puede ralentizar un clic. Un clic en un enlace ancla que inicia una animación de scroll con JavaScript es una interacción, y el código de scroll se ejecuta dentro de ella. Un handler que se ejecuta en cada evento de scroll mantiene ocupado el main thread, por lo que un tap que entra mientras el visitante hace scroll tiene que esperar. scroll-behavior: smooth en CSS proporciona scroll suave sin ningún script.
Las tres fases de una interacción de INP (subpartes)
Cada interacción que mide el INP tiene tres subpartes sucesivas: input delay, processing duration y presentation delay. El INP de una interacción es la suma de las tres, y la subparte más larga marca por dónde empezar el fix. Chrome DevTools muestra las tres en el desglose de INP (INP breakdown) de una traza.

Un tap en el filtro «All» de una página de prueba montada como portal de alquiler vacacional, registrado en el panel Performance: 369 de los 379 ms corresponden a processing duration, en su mayor parte layout que el click handler fuerza una y otra vez. Sin la grabación, ese mismo tap tarda 320 ms: la propia traza ralentiza el tap.
- Input delay: el input espera a que termine la tarea que ya se está ejecutando en el main thread. Normalmente esa tarea es un script que corre durante la carga: un tag manager, un widget de chat o un framework que todavía se está hidratando.
- Processing duration (también llamado processing time): se ejecutan los event handlers de la interacción. Un handler es lento cuando hace demasiado a la vez: por ejemplo, un tag de analítica que se dispara con el clic, o un script que lee las dimensiones de los elementos tras cada cambio y fuerza el layout una y otra vez.
- Presentation delay: tras los handlers, el navegador recalcula estilos y layout, y luego pinta el siguiente fotograma. Un DOM grande ralentiza esta fase, igual que un re-render que modifica gran parte de la página. Otras tareas que se ejecuten antes de ese fotograma también cuentan aquí.

Un tap mientras la página aún cargaba, en el Core Web Vitals Visualizer. El handler tardó 0 ms; el siguiente fotograma esperó 478 ms por el trabajo de carga de la página, y cualquier espera tras el handler cuenta como presentation delay.
¿Qué es una buena puntuación de INP?
Un buen INP es de 200 milisegundos o menos. Entre 200 y 500 milisegundos necesita mejorar, y más de 500 milisegundos es deficiente. Google toma el percentil 75 (p75) de las cargas de página, por separado para móviles y desktop.

En el p75, tres de cada cuatro cargas de página deben tener un INP de 200 ms o menos, incluidas las de móviles lentos. Los móviles fallan primero: un procesador más lento ejecuta el mismo JavaScript durante más tiempo, por lo que el main thread está ocupado con más frecuencia cuando el visitante hace tap.
En CoreDash, el INP en móviles fue aproximadamente el doble que en desktop. La tabla agrupa las cargas de página de 149 proyectos entre el 11 de octubre y el 7 de noviembre de 2026:
| INP en p75 | Móviles | Desktop |
|---|---|---|
| Todas las interacciones | 170 ms | 89 ms |
| Durante la carga de la página | 285 ms | 125 ms |
| Después de la carga | 158 ms | 84 ms |
En esos mismos datos, las pulsaciones de tecla en desktop fueron más lentas que los clics y taps: 121 frente a 85 ms.
Según el State of Web Vitals, el 91,8% de los sitios tiene un buen INP en móviles.
Cómo medir Interaction to Next Paint (INP)
El INP que utiliza Google procede de visitantes reales en Chrome: el Chrome UX Report (CrUX), que muestran PageSpeed Insights y Search Console. Una herramienta de real user monitoring (RUM) te indica qué clic y en qué página es lento, y Chrome DevTools muestra el porqué.
Search Console y PageSpeed Insights
El informe de Core Web Vitals en Search Console agrupa por problema las URL que suspenden el INP, con URL de ejemplo para cada grupo. "INP issue: longer than 200ms (mobile)" significa que las visitas desde móviles a ese grupo de URL similares tienen un INP superior a 200 ms en el percentil 75; "INP issue: longer than 500ms (mobile)" significa más de 500 ms. El sitio puede parecerte rápido aunque el informe diga que suspende: muchos visitantes usan móviles más lentos que el tuyo y también hacen tap mientras la página todavía está cargando. PageSpeed Insights muestra el INP en p75 durante los últimos 28 días para una URL concreta, o para todo el sitio cuando esa URL tiene muy pocas visitas en Chrome. Cualquier fix tarda en reflejarse en ambos: Search Console tarda hasta 28 días.

URL afectadas por día para un problema de INP en Search Console.
Real user monitoring
CrUX ofrece un único número por URL o grupo de URL. Un script de RUM en tu propio sitio mide cada visita. En CoreDash miro primero el INP en p75 para móviles, desglosado por el elemento clicado y por el estado de carga.
Las herramientas de RUM ahora también miden el INP en Safari y Firefox. CrUX, y con él Google, solo contabiliza Chrome, por lo que las cifras pueden diferir.
Tus propios clics en Chrome DevTools
Abre el panel Performance en Chrome DevTools. Sus métricas en directo muestran el INP de tu sesión a medida que haces clic, con un registro de cada interacción y sus tres subpartes. Aplica una ralentización de CPU de 4x para que el portátil se comporte más como un móvil, y haz clic también mientras la página todavía cargue. Para ver qué se ejecutó, graba una traza mientras haces clic: el track Interactions marca la interacción y el track Main muestra las tareas que tiene debajo. La extensión Core Web Vitals Visualizer muestra este mismo desglose directamente en la página.
La librería web-vitals registra en la consola cada interacción que eleva el INP, junto con el elemento y las subpartes:
<script type="module">
import {onINP} from 'https://unpkg.com/web-vitals@6/dist/web-vitals.attribution.js?module';
onINP(console.log, {reportAllChanges: true});
</script> Lighthouse
Una ejecución normal de Lighthouse no tiene INP: carga la página y nunca hace clic. La métrica de lab data más cercana es el Total Blocking Time (TBT), el tiempo que el main thread estuvo bloqueado durante la carga. El INP suele ser mucho más bajo que el TBT, pero mejorar el TBT también mejorará el INP. Por qué Lighthouse y las field data muestran cifras distintas: Lighthouse frente a field data.
Cómo mejorar el INP
Las interacciones más lentas en móviles determinan el INP. Búscalas en tus field data (Search Console o una herramienta de RUM), revisa su subparte más larga y redúcela: menos JavaScript durante la carga para el input delay, menos trabajo en el event handler para la processing duration y menos que renderizar para el presentation delay. La guía paso a paso de INP va desde el informe de Search Console hasta la línea de código.
WordPress
En un sitio WordPress, empieza por los scripts de plugins que carga cada página, porque cada uno puede hacer esperar a un tap. El Script Manager de Perfmatters y Asset CleanUp descargan los scripts de un plugin en las páginas que no los usan, como los de un plugin de formularios en las páginas de producto. Para lo que siga siendo lento después de eso, pide a un desarrollador una traza: una grabación del tap lento con la CPU ralentizada a 4x y el nombre del script que se ejecuta en él.
Los ajustes para retrasar JavaScript (Delay JavaScript execution en WP Rocket, Delay JavaScript en Perfmatters, Load JS Deferred configurado como Delayed en LiteSpeed Cache) retienen los scripts hasta la primera interacción y luego los ejecutan todos de golpe. Esto mejora la puntuación en Lighthouse porque Lighthouse nunca interactúa con la página. Un visitante real toca el menú y espera mientras el navegador descarga y ejecuta todo, y el INP registra el tap más lento de la visita. Deja esos ajustes desactivados para el INP.
WP Core Web Vitals, el plugin de corewebvitals.io, difiere los scripts en su orden original y ejecuta analítica, píxeles y widgets de chat tras la carga de la página, sin esperar a un tap.
Shopify
Cada app de Shopify suma tiempo a cada clic: la instalas por una sola funcionalidad y su script se carga en páginas y clics que no tienen nada que ver con ella. En el editor del tema, dentro de App embeds, desactiva las apps una a una y vuelve a medir el tap lento tras cada una. Los app blocks colocados en una sección siguen activos aunque desactives el embed de la app: elimínalos en esa sección. Una app eliminada puede dejar código en los snippets del tema, así que busca su nombre en el tema.
Los ajustes de las apps rara vez cambian lo que se ejecuta durante un clic. Eso lo decide el código del tema: qué hace el botón de añadir al carrito, cuándo se renderiza el drawer del carrito y qué scripts de apps se cargan. Esa parte es trabajo para un desarrollador: el handler de añadir al carrito actualiza primero la pantalla y hace el resto después, y el drawer del carrito solo renderiza lo que ha cambiado.
Input delay: menos JavaScript durante la carga
Un tap durante la carga espera al script que se esté ejecutando en ese momento. El panel Coverage de DevTools muestra qué código se ha ejecutado hasta el momento: un script que sigue prácticamente sin usarse tras hacer clics por la página puede eliminarse, y gran parte de lo que queda puede esperar a que la página haya cargado. ¿De verdad necesitas un widget de chat durante los primeros 500 ms de la carga? Inícialo tras el evento load, cuando el navegador esté inactivo:
window.addEventListener('load', () => {
const whenIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
whenIdle(() => {
const script = document.createElement('script');
script.src = '/js/chat-widget.js';
document.head.appendChild(script);
});
}); async y defer evitan que un script bloquee el parser de HTML, pero el script sigue ejecutándose durante la carga, por lo que ayudan más al LCP que al INP. Encontrarás otras formas de ejecutar scripts más tarde en 16 métodos para diferir o programar JavaScript.
El navegador espera por los listeners de touchstart o wheel que no sean pasivos antes de hacer scroll en la página. Añadir { passive: true } elimina esa espera, pero como el INP no mide el scroll, no reducirá el INP.
Divide tus propios long tasks (cualquier tarea de más de 50 ms en el main thread) para que el navegador pueda atender un tap en espera entre medias. Devuelve el control al main thread (yield) tras unos 50 ms de trabajo, sin importar cuánto tarde un elemento individual:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function processItems(items) {
let lastYield = performance.now();
for (const item of items) {
processItem(item);
if (performance.now() - lastYield > 50) {
await yieldToMain();
lastYield = performance.now();
}
}
}
scheduler.yield() funciona en Chrome y Firefox; Safari se queda con el fallback de setTimeout. Más información en yield al main thread.
Processing duration: actualiza la pantalla primero
A fast event handler does what the visitor sees first and leaves everything else until after the next paint. A tag in the click handler runs before the screen can change. Moved after the update, the visitor sees the result first and the tag still runs:
button.addEventListener('click', () => {
showConfirmation(); // lo que ve el visitante
requestAnimationFrame(() => {
setTimeout(() => {
// se ejecuta tras pintar el siguiente fotograma
dataLayer.push({ event: 'cta_click' });
}, 0);
});
});
Un requestIdleCallback() en este punto falla en todos los iPhone: Safari no lo admite, por lo que el handler lanza un error después de ejecutar showConfirmation(); el clic parece haber funcionado, pero el evento se pierde. La versión para Tag Manager está en programación de eventos en dataLayer; en el sitio de un cliente, mover dataLayer.push() para después del paint redujo el INP en 100 ms.
En un formulario o un botón de añadir al carrito que espera al servidor, muestra de inmediato en pantalla que el tap funcionó («Añadiendo al carrito...») y deja que la petición termine después.
El clic lento que veo más a menudo es el filtro de productos: el handler actualiza la lista, lee su nueva altura, cambia algo en función de esa altura y vuelve a leerla. Cada lectura tras un cambio obliga al navegador a recalcular el layout dentro del handler. En una página de prueba montada como portal de alquiler vacacional en WordPress, un tap en el filtro «All» tardó 320 ms; 298 ms correspondieron a layout forzado por el script del tema. Haciendo que el script lea todas las alturas primero, o dejando que CSS haga el trabajo del script, ese mismo tap tardó 16 ms, un solo fotograma. Ambos se midieron en Chrome con ancho de móvil y CPU ralentizada a 4x. En Forced reflow tienes el fix para temas, plugins, apps y tu propio código.
Presentation delay: un DOM más pequeño, menos re-renders
Un DOM grande ralentiza cada fotograma posterior a los handlers. Lighthouse lo recoge en «Optimize DOM size»: cómo reducir el tamaño del DOM.
En páginas largas, content-visibility: auto permite al navegador omitir el renderizado de secciones fuera del viewport hasta que el visitante hace scroll cerca de ellas:
.product-reviews,
.site-footer {
content-visibility: auto;
contain-intrinsic-size: auto 600px;
}
Asigna a cada una de esas secciones un contain-intrinsic-size cercano a su altura real. Sin él, la sección omitida mide cero píxeles de alto y la barra de scroll pega saltos a medida que las secciones se renderizan.
Algunas single page applications vuelven a renderizar demasiado contenido tras cada interacción: un clic modifica un solo contador y se re-renderiza media página. En React DevTools, «Highlight updates when components render» muestra qué componentes renderiza un clic.
Cómo depurar el INP con la API Long Animation Frames (LoAF)
La API Long Animation Frames (LoAF) reporta cada fotograma que tardó más de 50 ms, junto con los scripts que se ejecutaron en él: el archivo, la función y cuánto tiempo corrió cada uno. Con ella, una interacción lenta en las field data pasa a tener el nombre del script. LoAF funciona en navegadores basados en Chromium (Chrome 123 y posteriores).
new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
if (frame.duration < 100) continue; // solo los fotogramas más lentos
for (const script of frame.scripts) {
console.log(script.sourceURL, script.sourceFunctionName,
Math.round(script.duration) + ' ms');
}
}
}).observe({ type: 'long-animation-frame', buffered: true }); Una herramienta de RUM recopila estas entradas en cada visita. En CoreDash, abre INP, Breakdown y agrupa por LOAF: cada fila es un script, con el INP de las interacciones en las que se ejecutó, desglosado en sus tres subpartes. Empieza por el script cuya barra sea más larga en móviles. La guía de la API Long Animation Frames explica cada campo de una entrada.

CoreDash, agrupado por LOAF (desktop): el verde es input delay, el morado processing duration y el azul presentation delay.
¿El tap lento proviene de un script que no has escrito tú, como una app, un tag o un banner de consentimiento, y no sabes cuál eliminar? En una Core Web Vitals power hour revisamos juntos tus field data y una traza de ese tap, y te llevas el fix por escrito.

¿Necesitas una web más rápida?
Soy Arjen y llevo 17 años arreglando webs lentas. Si te encuentras con problemas que no puedes resolver por tu cuenta, envíame tu URL y hablamos.
Envíame tu URL
¿Por qué no funciona nuestro fix?
A veces la CDN sigue sirviendo el HTML antiguo, o el fix se metió en la plantilla de desktop y el móvil usa otra. Envíame tu URL y el problema, y te respondo con varias opciones. Primero reviso tus field data, luego dedicamos una hora a tu web, y en menos de un día tienes mis notas por escrito. 350 € sin IVA.
Envíame tu URL¿No tienes desarrollador para hacer el fix? Hago el trabajo yo mismo, en una copia de tu web.