SEO

Optimisation INP 2026 : corriger l'Interaction to Paint

Sur cette page
  1. Ce que l'INP mesure, en termes exacts
  2. Pourquoi le mobile est plus dur que le desktop
  3. Les plus gros tueurs d'INP en 2026
  4. Profiler l'INP avec les DevTools
  5. Les stratégies qui marchent vraiment en production
  6. Étude de cas, de 480 ms à 120 ms
  7. Checklist d'optimisation INP en 12 points
  8. Le HTTP/3 améliore-t-il l'INP ?
  9. Sources et lectures complémentaires

L'optimisation INP est le problème de Core Web Vitals qui fait encore trébucher la plupart des équipes avec qui je bosse. L'Interaction to Next Paint a pris la place du First Input Delay le 12 mars 2024, et le piège que personne ne lit attentivement, c'est que l'INP ne surveille pas la première interaction, il surveille la pire de toute la session. Ce changement de définition a tiré le rideau sur tout un tas de latences que le FID camouflait. Je vais t'expliquer d'où vient le chiffre, pourquoi ton téléphone a l'air pire que ton laptop, les douze patterns sur lesquels je tombe en audit, et les changements de code qui ont fait passer un site de 480 millisecondes à 120 au 75e percentile.

The short answer

L'INP note la pire interaction de la session, pas la première. Garde-le à 200 millisecondes ou moins pour le 75e percentile des visites, et traite le mobile comme la seule cible qui compte. Profile sous throttling CPU 4x, découpe les longs handlers avec scheduler.yield(), et pousse le travail CPU-bound hors du main thread.

200 msINP bon au 75e percentile
500 msdépasse ce seuil et tu échoues carrément
480 à 120un site en production, en millisecondes
Carte réponse montrant le seuil INP bon de 200 millisecondes au 75e percentile.
Deux cents millisecondes au 75e percentile, c'est la bande bonne. Dépasse cinq cents et tu rates l'INP carrément. PNG

L'INP a pris la place du First Input Delay parmi les Core Web Vitals le 12 mars 2024. Deux ans plus tard. Et c'est toujours celui qui fait trébucher la plupart des équipes avec qui je bosse. Le piège que personne ne lit attentivement : l'INP ne surveille pas la première interaction, il surveille la pire de toute la session. Ce simple changement de définition a tiré le rideau sur tout un tas de latences que le FID camouflait tranquillement. Les event handlers obèses. La longue tâche JavaScript qui ne se déclenche qu'au troisième clic. Les re-renders React et Vue qui coûtent plus cher que ce que personne n'avait budgété, plus le web worker occasionnel qui bloque par accident le main thread. Je vais t'expliquer d'où vient le chiffre, pourquoi ton téléphone a toujours l'air pire que ton laptop, les douze patterns sur lesquels je tombe sans arrêt en audit, et les vrais changements de code qui ont fait passer un de nos sites en production de 480 millisecondes à 120 au 75e percentile.

Ce que l'INP mesure, en termes exacts

Quelqu'un touche la page. Un clic, un tap, une touche, peu importe. Le navigateur déclenche un chronomètre pile à ce moment et le laisse tourner jusqu'à ce que la prochaine mise à jour visuelle arrive à l'écran. Cette fenêtre couvre l'exécution de l'event handler, plus tout le style et le layout que le navigateur doit refaire ensuite avant de pouvoir peindre la frame suivante. L'INP, c'est la plus haute de toutes ces fenêtres sur la session, moins une poignée de valeurs extrêmes et un petit lissage. La barre que fixe Google : 200 millisecondes ou moins au 75e percentile des visites de page. Dépasse 500 et tu as raté l'INP carrément.

Et oui, la définition est volontairement vache. Le FID te tapait gentiment sur l'épaule dès que le premier clic filait, même si le dixième se traînait. L'INP, lui, refuse. Il part à la chasse de ce dixième clic lent, parce que c'est celui-là que tes utilisateurs retiennent vraiment. Imagine un formulaire de login qui répond en 30 millisecondes posé juste à côté d'un bouton « charger plus » qui mouline pendant 700. L'INP classe toute la page à 700, ce qui, honnêtement, est exactement ce que la personne assise là a ressenti.

Pourquoi le mobile est plus dur que le desktop

Ton chiffre sur téléphone sera pire que ton chiffre sur laptop. Quasiment toujours, même site. Et ce n'est pas de la malchance, c'est de la physique. Un Android milieu de gamme en 2026 tourne encore avec un CPU quatre à six fois plus lent qu'un laptop correct. Ajoute deux à trois fois moins de bande passante mémoire et un réseau cellulaire dont le jitter étire au hasard même les plus petites tâches JavaScript, et l'arbre React qui se rend en 80 millisecondes sur ta machine ? Il peut en bouffer 350 sur un téléphone. Ça suffit à lui seul pour pousser un clic juste au-delà de la ligne.

Ce qui m'amène quelque part que beaucoup de gens rechignent à entendre : le mobile est la seule cible qui compte. Le mobile-first indexing veut dire que Google te classe sur l'expérience mobile. Les données terrain CrUX penchent fortement vers le trafic mobile pour la plupart des sites grand public. Et les interactions les plus moches que tu shipperas jamais viennent de smartphones Android pas chers que personne dans l'équipe ne possède. Donc profile avec le CPU throttlé (4x est le preset par défaut des Chrome DevTools, et en 2026 ça correspond à peu près à un Android milieu de gamme de 2022) et laisse les gains desktop tomber gratuitement. Ils tomberont.

Les plus gros tueurs d'INP en 2026

Après des dizaines de ces audits, ce sont les mêmes coupables qui montrent leur tête. À peu près dans l'ordre où je les rencontre :

  1. Les event handlers lourds. Un click handler qui brûle 300 millisecondes de travail synchrone te file un INP de 300 millisecondes, et il se fiche complètement de la vitesse du reste de la page. Les récidivistes que je revois sans cesse, c'est l'analytics qui se déclenche en synchrone, la désérialisation JSON, les grosses mises à jour de state React qui se propagent à travers des dizaines de composants, plus les exports CSV qui se contentent de squatter le main thread et de mâcher.
  2. Les scripts tiers qui se déclenchent pendant l'interaction. Tag managers, librairies A/B, session recorders, frameworks publicitaires. Ils adorent lancer une longue tâche à la seconde où l'utilisateur fait quoi que ce soit. La page paraît réactive jusqu'au moment où ce premier clic déclenche le chemin de code tiers et fige le main thread pendant quelques centaines de millisecondes. Classique.
  3. Le layout thrashing synchrone. Lis une propriété de layout comme offsetHeight ou getBoundingClientRect à l'intérieur d'une boucle qui écrit aussi dans le DOM, et tu forces le navigateur à recalculer le layout à chaque passage. Ça fait boule de neige à toute vitesse. J'ai vu une boucle de 200 éléments se transformer en stall de 200 millisecondes exactement comme ça.
  4. Les arbres DOM volumineux. Shippe 5000 nœuds DOM et chaque interaction paie une taxe de base, parce que le navigateur doit parcourir une bonne partie de cet arbre rien que pour comprendre ce qui a changé. Rends en lazy les panneaux que personne ne peut voir et en général ça passe. Rends tout d'entrée et tu continueras à payer cette taxe pour toute la vie de la page.
  5. Les swaps de web fonts qui déclenchent un layout shift en pleine interaction. Une font qui arrive après le clic et déclenche un reflow tire ton INP vers le haut, parce que la peinture qui devrait suivre le clic se retrouve coincée à attendre le reflow. font-display: swap cache le jank visuel mais ne fait absolument rien pour le coût INP. size-adjust sur la font face, voilà le fix qui bouge réellement le chiffre.
  6. Les callbacks setTimeout qui tournent longtemps. Tout ce que ton appli planifie et qui tourne au-delà de 50 millisecondes est marqué comme une longue tâche. Et si ça atterrit par-dessus une interaction, cette interaction hérite de tout le délai. Vicieux quand c'est intermittent, parce que tu ne peux pas le reproduire à la demande.
  7. Un fetch ou un XHR synchrone dans un handler. Attends une requête réseau à l'intérieur d'un event handler et tu as bloqué la prochaine peinture, point final. Traite le handler comme un chemin critique synchrone et dégage l'aller-retour du passage. UI optimiste, ou au minimum un état de chargement que tu peins immédiatement.
  8. L'hydratation de gros composants rendus côté serveur. React 18, Vue 3 et SvelteKit shippent tous des astuces d'hydratation partielle qui nettoient l'essentiel de ça. Mais hydrate un arbre de 200 composants au premier clic et tu le sentiras quand même atterrir. Passe aux islands ou à l'hydratation sélective partout où l'architecture le permet.

Profiler l'INP avec les DevTools

Pour moi, rien ne bat le panneau Performance des Chrome DevTools pour épingler l'INP en 2026. La piste « Interactions » étale chaque event d'input de l'enregistrement avec son score INP en millisecondes, et toute longue tâche qui rentre en collision avec une interaction s'allume en rouge pour que tu ne puisses pas la louper. Voilà comment je le pilote :

  1. Ouvre les DevTools, bascule sur l'onglet Performance, et active le CPU throttling à 4x (la valeur par défaut).
  2. Règle le network throttling sur Fast 3G ou Slow 4G pour tester quelque chose de proche d'un vrai téléphone, et pas la fibre de ton bureau.
  3. Lance l'enregistrement, puis fais les interactions qui t'intéressent. Choisis celles qui te semblent poussives. Arrête l'enregistrement.
  4. Trie la piste Interactions par INP, en ordre décroissant. Le top trois te pointe presque toujours directement vers la longue tâche coupable posée dans la piste Main juste en dessous.
  5. Zoome sur cette première longue tâche rouge. Le flame chart te donne le nom de la fonction qui tournait. Voilà ta cible. Va corriger celle-là et ré-enregistre.

Pour les données terrain, branche la Loop API du Chrome User Experience Report ou pointe simplement notre sonde Core Web Vitals INP sur l'URL. CrUX te donne le 75e percentile sur les vrais utilisateurs Chrome des 28 derniers jours, et c'est le chiffre sur lequel Google te classe. Les données de labo sont nettes, d'accord, mais c'est un seul lancer de dés. Les données terrain sont bruitées. Elles disent aussi la vérité sur tes vrais visiteurs, alors fie-toi à celles-là quand les deux ne sont pas d'accord.

Les stratégies qui marchent vraiment en production

Si tu ne fais qu'une seule chose, fais celle-ci : découpe les longs event handlers en plus petits morceaux avec scheduler.yield() ou setTimeout(fn, 0). C'est le changement qui me rapporte le plus, à peu près à chaque fois. La forme ressemble à ça :

async function handleClick() {
  await heavyTask1();
  await scheduler.yield(); // returns to the browser for input checks
  await heavyTask2();
  await scheduler.yield();
  await heavyTask3();
}

Chaque scheduler.yield() rend au navigateur un instant pour traiter les inputs en attente et peindre la frame suivante. Tu n'as supprimé aucun travail. Le total est identique. Mais ta pire latence chute de la somme de toutes les tâches à juste la plus longue d'entre elles, et c'est le chiffre sur lequel l'INP te note.

Ensuite : sors le travail CPU-bound du main thread avec des Web Workers. Si ça ne touche pas le DOM, c'est bon. Parsing JSON, filtrage de recherche, chiffrement, traitement d'images, ce que tu veux. Tout ça tourne là-bas dans le worker, le main thread reste dégagé, et j'ai vu l'INP rester sous les 100 millisecondes même sur le genre de téléphone que tu hésiterais à acheter d'occasion.

Retiens tes scripts tiers jusqu'à ce que le navigateur soit en idle avec requestIdleCallback ou un worker proxy façon Partytown. La page démarre sur le code first-party seul. Les trackers se glissent dedans seulement après que ce premier clic a déjà été traité, et l'INP s'améliore énormément, parce que ton clic pire-cas ne traîne plus un script analytics derrière lui.

À ajouter aussi : le CSS containment (contain: layout style) sur les composants qui tiennent debout tout seuls, pour qu'un changement dans l'un ne force pas le navigateur à recalculer le layout sur toute la page. Une ligne par composant. Tu ne verras rien en tests de labo. Sur le terrain, par contre, ça s'additionne.

Et pour finir, précharge les assets dont dépend ta première interaction avec <link rel="preload" as="script"> pour les scripts dont tu sais déjà qu'ils tourneront sur ce premier clic. Le temps que l'utilisateur clique, le handler est posé en mémoire, et tu as retiré le coût de parse-et-compile bien à l'écart du chemin critique.

Étude de cas, de 480 ms à 120 ms

Ces chiffres sont réels. Ils viennent d'un site e-commerce en production qu'on a audité début 2026. L'INP mobile était à 480 millisecondes au 75e percentile, en gros à frôler la ligne d'échec des 500 millisecondes, donc le site échouait carrément. Trois semaines de travail ciblé plus tard, il était redescendu à 120, confortablement installé dans la bande « bonne » des 200 millisecondes. Le truc qui a attiré l'attention du client ? La conversion mobile-vers-panier a grimpé de 12 pour cent le mois suivant. Bon, je ne jurerai pas que c'était de la causalité, la corrélation et cent autres choses font bouger un taux de conversion, mais ça avait quand même tout l'air d'un ressenti plus réactif qui se montre sur le bilan.

ÉtapeINP mobile (75e percentile)Source
Avant480 msDonnées terrain CrUX sur 28 jours
Après120 msDonnées terrain CrUX sur 28 jours

Trois changements ont fait presque tout le gros du boulot. Le plus gros gain d'abord :

  • Bascule le « ajouter au panier » du synchrone vers une UI optimiste. Avant, cliquer sur le bouton lançait un fetch synchrone vers /api/cart/add et restait planté là à attendre la réponse avant de toucher à l'UI. Après : l'UI se met à jour à l'instant où tu cliques (l'article apparaît dans le tiroir du panier), le fetch tourne en arrière-plan, et on annule l'UI si ça part en erreur. Impact INP : -180 millisecondes sur le pire cas. C'était le gros morceau.
  • Pousse le tag manager au-delà de la première interaction. Ils chargeaient Google Tag Manager en synchrone, en plein dans le head. Après : GTM se charge avec defer, enveloppé dans un requestIdleCallback pour qu'il arrête de jouer des coudes au premier clic. Impact INP : -130 millisecondes.
  • Envoie le filtrage de la liste produits sur un Web Worker. L'ancien filtre était une boucle synchrone sur 1200 produits qui re-rendait entièrement à chaque frappe au clavier. Brutal. Après : le worker fait le filtrage, renvoie le résultat, et le main thread ne re-rend que les 20 éléments que tu peux voir. Impact INP : -50 millisecondes sur l'interaction de filtre.
Comparaison des bandes de notation INP en millisecondes : bon à 200 ou moins, à améliorer de 200 à 500, mauvais au-delà de 500.
Les trois bandes d'INP. Bon se pose à 200 millisecondes ou moins, mauvais commence dès que tu dépasses 500. PNG

Checklist d'optimisation INP en 12 points

Voilà la liste que je déroule sur chaque audit front-end. Chaque ligne pointe vers un tueur que tu as déjà rencontré plus haut, plus le fix qui le tue en retour.

  1. Profile d'abord le mobile sous CPU throttling à 4x, et ne jette même pas un œil au chiffre desktop tant que le mobile n'est pas passé au vert.
  2. Tout ce qui dépasse 50 millisecondes dans un event handler se fait découper avec scheduler.yield().
  3. Balance le travail CPU-bound et sans DOM dans des Web Workers.
  4. Retiens les scripts tiers jusqu'à requestIdleCallback, ou au minimum jusqu'après la première interaction.
  5. Remplace le fetch synchrone dans les handlers par une UI optimiste plus une réconciliation en arrière-plan.
  6. Pose contain: layout style sur les composants qui tiennent debout tout seuls.
  7. Précharge les scripts dont ta première interaction a besoin avec <link rel="preload" as="script">.
  8. Ne lis jamais une propriété de layout à l'intérieur d'une boucle qui écrit aussi dans le DOM. Tout simplement.
  9. Configure les web fonts avec font-display: swap et size-adjust pour qu'un swap de font ne puisse pas provoquer de reflow en pleine interaction.
  10. Si tu désérialises de gros payloads JSON en synchrone, passe au streaming ou à un worker.
  11. Vérifie la taille de ton DOM. Au-delà de 1500 nœuds au premier chargement, rends en lazy tout ce qui est hors écran.
  12. Re-mesure avec les données terrain CrUX après chaque changement. Un seul run Lighthouse te mentira.

Le HTTP/3 améliore-t-il l'INP ?

Seulement à la marge. Le HTTP/3 raccourcit le handshake TLS et tue le head-of-line blocking, donc ton réseau mobile se comporte de façon plus prévisible. L'INP est massivement une affaire de travail sur le main thread, pas de réseau. Mais une connexion plus calme, moins sujette au jitter, génère moins de longues tâches à partir des chunks de réponse en streaming, et c'est dans cet endroit étroit que ça aide.

Sources et lectures complémentaires

Questions fréquentes

Pourquoi Google a-t-il remplacé le FID par l'INP ?

Le FID n'a jamais chronométré que la toute première interaction. Du coup les gens optimisaient ce clic-là et laissaient tout ce qui venait après pourrir tranquillement. L'INP surveille à la place la pire interaction de toute la session, et honnêtement c'est un bien meilleur substitut pour la façon dont l'appli est réellement ressentie par quelqu'un qui l'utilise pour de vrai.

Quelle est la différence entre le TBT et l'INP ?

Vois le TBT (Total Blocking Time) comme le cousin de labo de l'INP : il additionne le temps passé dans les longues tâches entre le FCP et le TTI pendant un chargement simulé. L'INP est la version terrain, droit sorti des vrais utilisateurs Chrome. Ils se suivent d'assez près. Mais le TBT peut te flatter si tes interactions lourdes arrivent tard dans la vie de la page, après que le run de labo a déjà arrêté de regarder.

En combien de temps devrais-je voir une amélioration des données terrain CrUX après un déploiement ?

Patience. CrUX roule sur une fenêtre de 28 jours, donc un déploiement fait avancer le score terrain lentement sur le mois qui suit plutôt que de le retourner du jour au lendemain. Je vois en général le premier vrai mouvement autour de sept à dix jours après, et la nouvelle baseline complète se stabilise quelque part autour des 35 jours.

Les single-page apps ont-elles un désavantage structurel d'INP ?

Pas de base, non. Mais elles te donnent beaucoup plus de façons de le saboter. Routing client lourd, hydratation, un re-render à chaque changement de state : tout ça s'empile sur ton INP. Les SPAs que je vois s'en sortir très bien s'appuient sur l'architecture islands, la réactivité à base de signaux (Solid, Svelte 5, Vue 3.4+) et le moins de state client possible, et elles tiennent parfaitement la cadence des multi-page apps.

Le seuil INP des Core Web Vitals va-t-il probablement se durcir en 2027 ?

Mon pari, c'est que oui, même si je peux me tromper sur le timing. Google a déjà laissé filtrer des indices sur un resserrement de la barre bonne une fois que l'INP médian du web aura baissé. Donc si tu te faufiles tout juste à 200 millisecondes aujourd'hui, je viserais plutôt 100-150 dès maintenant pour me garder de la marge avant la prochaine révision.