El 12 de Marzo como bien sabéis, Interaction to Next Paint (INP) se convirtió en un Core Web Vital más. Básicamente nos mide cómo de rápido responde nuestra página a las interacciones del usuario: clicks de ratón, el touch de presionar la pantalla táctil o pulsar una tecla del teclado (obviamente hacer hover o scroll no cuenta como INP).
Un INP igual o inferior a 200 milisegundos significa que la página tiene buena capacidad de respuesta
¿Qué consideramos una interacción?
Una interacción es un grupo de event handlers que se disparan durante la acción de un usuario, por ejemplo hacer un tap en una pantalla táctil incluye los eventos pointerup, pointerdown y click o pulsar una tecla del teclado consta de los eventos keydown, keypress y keyup
La latencia de una interacción consiste en la duración individual más larga dentro del grupo de events handlers que dirigen la interacción, que va desde el momento en que el usuario comienza la interacción hasta el momento en que se presenta el siguiente frame con respuesta visual.
Así pues dividimos el INP en tres subpartes:
- Input Delay: Cuánto tiempo tiene que esperar la interacción ANTES de ejecutarse.
- Processing Time: Cuánto tarda en ejecutarse la interacción.
- Presentation Delay: Cuánto tarda el navegador en ejecutar las tareas que necesite para pintar las actualizaciones provocadas por la interacción.
Las páginas pueden tener múltiples interacciones, por lo que el tiempo INP que verás informado por los productos RUM y otras herramientas, como Google Search Console y Chrome’s UX Report (CrUX), será generalmente el INP peor/más alto dentro del percentil 75.
Debuggeando un INP con Performance
En esta academy vamos a ver:
- Cómo identificar las causas de malos tiempos en el INP
- Ejemplos con los problemas más comunes
- Enfoques que podemos utilizar para mejorar en los clientes su INP
1. Abre un perfil de invitado
Primero recomendamos abrir un perfil de invitado de Chrome, así evitamos el ruido que generan las extensiones y además empezamos con cookies, cachés, etc vacías.

2. Abre Devtools y cambia al tab de Performance
También activamos el Device toolbar, ya que la mayoría de visitantes de las webs vienen de móvil.

3. Cargamos la página que queremos analizar
Primero esperamos a que cargue totalmente, en nuestro caso analizamos la de H&M
4. Pulsa ‘Grabar’ e interactúa con la página
Una vez cargada la web, pulsamos el icono de grabación en la barra de herramientas de DevTools, veremos que el profiler empieza a grabar.
El Profiler registra actividades como las tareas de la CPU, las solicitudes de red y las actualizaciones de la interfaz.
Al iniciar la grabación, el propio proceso de arranque del profiler puede introducir una carga adicional en la CPU, generando una long task / tarea larga.
Por eso lo suyo es esperar un segundo o más antes de interactuar con la página para evitar que esta tarea inicial distorsione los resultados del análisis.
5. Paramos la grabación
Después de haber registrado datos sobre las interacciones que te interesan, detén la grabación. Deberías ver algo similar a la vista de abajo.
En esta vista, he desplegado las filas para Frames, Interactions, and Main Thread para poder ver lo que está visible en la página cuando interactué con ella, así como la actividad que ocurrió en el hilo principal.

En la fila Main Thread podemos ver la tarea Profiling Overhead justo al comienzo del timeline y, a continuación, una segunda pila de llamadas en respuesta a la interacción.
Una guía rápida para interpretar este panel:
- La anchura de cada celda de la pila de llamadas (call stack) representa el tiempo transcurrido de ejecución de la misma (y de sus hijos).
- Las celdas de color amarillo oscuro, magenta y verde representan el trabajo interno del navegador: renderizado de la página, calcular los estilos css, etc.
- Las celdas de color pastel representan los scripts incluidos en la página. (Cada script tiene su propio color).

Al hacer clic en una celda individual se mostrarán más detalles en el tab Summary situado en la parte inferior de la pestaña. Podemos acercar/alejar y desplazarnos usando el ratón o las teclas W A S D.
Analizando las interacciones
Una vez capturados los perfiles, podemos empezar a analizarlos para entender por qué se producen tiempos de INP tan largos y, lo que es más importante, qué podemos hacer para reducirlos.
Ejemplo – Abriendo el menu de H&M
He abierto el menú de la versión móvil de H&M haciendo clic en el icono de la parte superior derecha.
Aunque sólo hice clic una vez en la página, se llamaron varios events handles. El del menú fue el más largo y tuvo un tiempo INP de 350 ms, es decir, 150 ms más que el límite de 200 ms que Google considera «Bueno».

En este caso, la mayor parte del tiempo se invierte en el propio event handler (Processing Time) del menú, pero hay un ligero retraso antes de que el controlador de eventos pueda ejecutarse.
Al examinar el gráfico, vemos varios grupos que ocurren en respuesta a la interacción:
- Vemos que se se ejecutan antes que el menú un par de eventos, antes he visto que viene de Akamais bot manager que te comprueba todo el rato que tus movimientos de ratón no son de un bot, creando así el input delay para la interacción con el menú.
- Dentro de la columna más larga vemos que se crea un evento de análisis para registrar la apertura del menú por parte del usuario.
- El último grupo es un componente javascript que construye el menú y luego lo añade al DOM, desencadenando recalculaciones de estilo y layout.

Aquí yo empezaría por centrarme en cuál es el origen del largo Processing time de 303ms, haciendo preguntas como:
- ¿Se puede renderizar el menú sin usar React?
- ¿Es necesario inyectar/cargar dinámicamente los estilos?
- ¿Podría enviarse el evento de análisis después de la interacción?
Corrigiendo las interacciones
Una vez que hemos identificado por qué una interacción tiene un tiempo de Interaction to Next Paint elevado, nuestro siguiente objetivo es reducirlo.
Creo si separamos el Input Delay versus el Processing Time y el Presentation Delay que nombré al principio, puede ser más fácil.
- El Input Delay se debe a que otras tareas bloquean el hilo principal y, por tanto, retrasan el momento en que puede ejecutarse el gestor/handler de la interacción. Como tal, el Input Delay está fuera del control del interaction handler.
- Processing Time and Presentation Delay son el tiempo que tarda el handler de interacción en ejecutarse, y luego el tiempo que tarda el navegador en completar el diseño, estilizado, pintado y otras tareas creadas por el event handler.

Como el Processing Time y el Presentation Delay son más fáciles de identificar y solucionar, voy a arreglarlos primero antes de pasar al Input Delay.
Cómo mejorar Processing Time y el Presentation Delay
Para mejorar el Processing Time y el Presentation Delay, muchos artículos se centran en dividir Long Tasks o «delegar al hilo principal» con funciones como setTimeout, scheduler.yield o requestIdleCallback.
scheduler.yield se usa para hacer una breve pausa y comprobar si hay otras tareas pendientes en la cola.
requestIdleCallback se usa para programar tareas no esenciales para ejecutarse durante los periodos en los que el hilo principal del navegador está inactivo
Aunque ese es un punto de partida, no es el único enfoque. Mi opinión es que reducir el tiempo que tardan en ejecutarse las Long Tasks es tan importante como dividirlas.
Otro enfoque es centrarnos en lo más relevante para el usuario y optimizarlo.
Por ejemplo, si el usuario está abriendo un menú, mostrar ese menú rápidamente debe ser la actividad principal. Cualquier otra cosa que se active por la misma acción debe ser secundaria.
1. Aplazamos las actividades (task, acciones) menos importantes
El menú H&M registra un evento de analítica cuando alguien abre el menú. Estas llamadas se producen antes de que se muestre realmente el menú.
Aunque los eventos de analítica son útiles para ayudarnos a entender el comportamiento los usuarios, son secundarios y no deberían retrasar el objetivo principal de los visitantes, en este caso abrir el menú.
Planificar la ejecución de estos eventos en una nueva tarea a través de setTimeout (por ejemplo, setTimeout(analytics_fn, 0) o scheduler.postTask para los navegadores que lo soportan) mueve el trabajo fuera del interaction handler para ser ejecutado más tarde y permite que el interaction handler se complete antes.
scheduler.postTask es una forma más granular y flexible de programar tareas en comparación con técnicas tradicionales como setTimeout() y requestAnimationFrame(). Proporciona la capacidad de categorizar las tareas en niveles de prioridad como ‘user-blocking’, ‘user-visible’ y ‘background’
Otro ejemplo de uso: el típico Consent Manager
Después de que el usuario haya hecho clic en «aceptar» o «rechazar» las cookies, querrá seguir leyendo las noticias en lugar de esperar a que se autorice (o no) la carga de varios anuncios. Programar setConsentInfo en una tarea independiente permite al navegador pintar antes el siguiente fotograma, mientras que los anuncios pueden seguir cargándose en segundo plano:

2. Quitar trabajo
En el evento performance.now() se dio una charla sobre El insoportable peso del JavaScript masivo . Se vio un caso práctico en el que sustituyeron más de 50.000 líneas de JavaScript por funciones nativas de HTML y CSS. El resultado fue una experiencia de usuario más rápida con una base de código más fácil de mantener.
H&M depende de componentes JavaScript para crear los elementos del menú, añadirlos al DOM y aplicar estilos. El resultado: un Processing time de 303ms.

Comparemos esto con otro ecommerce, French Connection. En esta web se crea directamente los elementos del menú cuando genera la página en el servidor, server side rendering, y, a continuación, sólo cambia los estilos de los elementos para mostrar el menú. Esto ilustra la gran diferencia en el tiempo de procesamiento entre los dos enfoques:
- Tiempo de procesamiento de H&M 303 ms
- Tiempo de procesamiento de French Connection: 22 ms

Por supuesto, la página de French Connection tendrá más elementos DOM. Cuando herramientas como Lighthouse te advierten de que «evites un tamaño excesivo del DOM», es tentador optar por otros enfoques sin quizá considerar plenamente los pro y los contras. Los menús suelen contener un gran número de elementos DOM. La elección es si se crean cuando la página se genera inicialmente o en tiempo de ejecución mediante JavaScript cuando se solicita el menú.
Lighthouse advierte sobre el tamaño del DOM porque «aumentará el uso de memoria, provocará cálculos de estulos más largos y producirá los design reflows». Pero si se utilizan con cuidado, las propiedades CSS como content-visibility, isolation y will-change pueden ayudar a reducir el coste de un gran número de nodos DOM.
|
1 2 3 4 5 6 7 8 9 10 11 |
.articulo-importante { content-visibility: auto; /* Mejora el rendimiento al solo renderizar elementos visibles en la ventana gráfica */ } .menu { isolation: isolate; /* Crea un nuevo contexto de apilamiento para evitar efectos visuales no deseados de elementos cercanos */ } .animacion-botón { will-change: transform, opacity; /* Optimiza los cambios en transformación y opacidad para animaciones fluidas */ } |
Hablando de CSS, en el ejemplo anterior INP se vio afectado por cálculos costosos de style y layout. Éstos se debían a que los interaction handlers inyectaban estilos que afectaban a todo el DOM, o a que los interaction handlers consultaban propiedades de style o size mediante métodos como getComputedStyle o getBoundingClientRect, forzando así los recálculos. (Paul Irish mantiene una lista de métodos JavaScript que suelen desencadenar cálculos de estilo y diseño).
Piensa en el trabajo que le estás pidiendo al navegador que haga y si hay formas más eficientes de conseguir el resultado final.
3. Ceder temporalmente el control del hilo principal
Hay casos en los que un proceso/work no podemos lanzarlo en diferido/deffer, o que no podemos mejorar la eficiencia de los interaction handlers. En esos casos, sólo necesitamos devolver el control al hilo principal para que pueda seguir pintando el siguiente fotograma:
Un enfoque es utilizar setTimeout envuelto en una Promise:
function yieldToMain() {
return new Promise(resolver => {
setTimeout(resolve,0);
});
}
Y luego lugares estratégicos del código poner:
// Yield to the main thread:
await yieldToMain();
setTimeout crea una nueva task, permitiendo así al planificador del navegador(browser’s scheduler) tomar el relevo y procesar otras tareas.
Cómo mejorar el Input Delay
Diagnosticar las causas de un Input Delay lento no siempre es fácil con las DevTools. Esto se debe a que la duración del delay depende del momento en que el visitante interactuó con la página y de las tareas que se estaban ejecutando cuando el visitante interactuó.
La API Long Animations Frame (LoAF), que se lanzará en Chrome 123, ayudará a las herramientas RUM a identificar las tareas que causaron el Input Delay.Una vez identificadas, podremos perfilar las tareas en DevTools.
Hasta que esta api tenga soporte total, existen otros enfoques en DevTools que pueden ayudar a identificar algunos de los scripts problemáticos.
1. Investigar otras interacciones
En el ejemplo de H&M, otros controladores de eventos táctiles, de ratón y de teclado también se activan con las interacciones y pueden ejecutarse antes que nuestro event handler de la interacción principal.
Afortunadamente, estos controladores de eventos se capturan en el perfil de DevTools.
También podemos inspeccionar qué controladores de eventos están activos utilizando el panel Event Listeners en la barra lateral derecha del panel Elements en DevTools.
Por ejemplo vemos que el script de Akamai https://s.go-mpulse.net/boomerang/EPMEN-VPFQ4-GM3WK-22BJD-TU9B7 lanza sus propios eventos

Podemos optar por bloquearlo desde network y ver qué tal le sienta a la web:
- Abre la pestaña «Red» (Network) de DevTools.
- Carga la página.
- Haz clic derecho sobre el script que deseas bloquear.
- Selecciona «Bloquear URL de solicitud» (Block Request URL).
- Recarga la página para ver el efecto del bloqueo.
Preguntas y respuestas sobre el INP
- INP sustituye al FID (First Input Delay), FID sólo medía el delay de la primera interacción de la página mientras que INP tiene en cuenta todas las interacciones de la página.
- Si hacemos scroll con el teclado sí se considera interacción
- «RUM» significa Real User Monitoring son herramientas que dan datos de usuarios reales como Google Search Console y Chrome’s UX Report (CrUX).
Summary de un Event:
Ejemplo: Total Time 19.91 ms | Self Time66 μs | Type: click
- Total Time: El tiempo total que tomó el manejo de este evento, incluyendo cualquier proceso relacionado que haya sido desencadenado por el evento. En este caso, es 19.91 milisegundos. Esto significa que desde que se inició el evento de click hasta que todas las operaciones relacionadas con ese click se completaron, pasaron casi 20 milisegundos.
- Self Time: Es el tiempo que se empleó/gastó específicamente en el manejo directo del evento, excluyendo el tiempo utilizado en las funciones llamadas o tareas desencadenadas por el evento. Aquí, es 66 microsegundos, lo que indica que el procesamiento directo del evento de click fue bastante rápido.
Concepto de Task (celda color gris):
Internal browser work
En el contexto del análisis de rendimiento en Chrome DevTools, el término «internal browser work» (trabajo interno del navegador) se refiere a las operaciones y procesos que el navegador realiza por sí mismo, sin contar el código de JavaScript u otros recursos proporcionados por la página web en sí.
Estas operaciones incluyen, pero no se limitan a:
- Renderizado de la página: El proceso de convertir el código HTML, CSS y JavaScript en una página visualmente presentable.
- Estilo y layout: Calculando estilos CSS y determinando la disposición de los elementos en la página.
- Garbage collection: La gestión automática de la memoria por parte del navegador, eliminando los objetos que ya no se utilizan para liberar recursos.
- Decodificación de imágenes y vídeos: Procesar archivos multimedia para que puedan ser mostrados al usuario.
- Actividades relacionadas con el navegador: Como manejar pestañas, extensiones del navegador, etc.

