Votre site répond vite au clic, mais l’interface reste figée une fraction de seconde de trop ? Bienvenue dans le monde de l’INP, le Core Web Vital qui a définitivement enterré le FID en mars 2024. jQuery capricieux, page builders trop lourds, scripts de tracking envahissants : on va décortiquer ensemble les vrais coupables et surtout comment les neutraliser avec DevTools et un peu de JS bien placé.
FID vs INP : ce qui change concrètement pour votre site
Avant de plonger dans le diagnostic technique, il faut comprendre ce qui différencie vraiment ces deux métriques. Parce qu’on peut avoir l’impression que l’INP n’est qu’une nouvelle version du FID avec un nom différent. Ce n’est pas le cas : le mode de calcul change en profondeur, et ça a des conséquences directes sur la façon dont vous devez auditer votre site WordPress.
La mesure d’un seul événement contre la réactivité globale
Le FID (First Input Delay) ne mesurait qu’une seule chose : le délai entre le premier clic (ou tap) de l’utilisateur et le moment où le navigateur commence à traiter cet événement. Une seule interaction, un seul chiffre. Le problème ? Un site pouvait avoir un FID excellent tout en devenant totalement injouable après les premières secondes (menu qui freeze, formulaire qui ne répond plus, etc.).
L’INP (Interaction to Next Paint) change complètement l’approche : il mesure la latence de toutes les interactions qui se produisent pendant toute la session de navigation (clics, taps, appuis clavier), du début jusqu’à la fermeture de la page. Et surtout, il retient le pire percentile observé (généralement le 98e percentile pour les sessions avec beaucoup d’interactions). Autrement dit : un seul mauvais moment peut plomber votre score, même si 99% de vos interactions sont fluides.
Les seuils Google à respecter en 2026
Concrètement, voici les paliers officiels fixés par Google pour évaluer votre INP :
- Bon : en dessous de 200 ms
- À améliorer : entre 200 ms et 500 ms
- Mauvais : au delà de 500 ms
Ces seuils s’appliquent au 75e percentile des sessions mesurées sur mobile et desktop confondus. Contrairement au FID (dont les seuils étaient plus permissifs, 100 ms pour « bon »), l’INP est nettement plus exigeant. Néanmoins, ça reflète mieux la réalité perçue par l’utilisateur : une interaction qui prend plus d’une demi-seconde à répondre, ça se sent vraiment, surtout sur un site WordPress chargé en plugins.
Pourquoi Google a remplacé le FID par l’INP
L’INP est devenu un Core Web Vital officiel en mars 2024, après plusieurs mois en tant que métrique expérimentale. La raison principale de ce remplacement : le FID donnait une vision tronquée de l’expérience utilisateur. Il ne couvrait que le délai d’input (le temps avant que le navigateur commence à traiter l’événement), sans jamais tenir compte du temps de traitement JavaScript qui suit, ni du temps de rendu (paint) nécessaire pour afficher visuellement le résultat à l’écran.
L’INP, lui, couvre l’intégralité de ce parcours : délai d’input, exécution du JS déclenché par l’interaction, puis rendu jusqu’au prochain affichage visuel perceptible. C’est cette vision complète qui en fait un indicateur bien plus fiable de la réactivité réelle de votre site. Sur WordPress, où le JavaScript s’accumule vite (plugins, thème, scripts tiers), cette différence est loin d’être anecdotique.
Pourquoi WordPress obtient souvent un mauvais score INP
WordPress traîne une réputation de CMS un peu lourd côté JavaScript, et honnêtement, ce n’est pas totalement usurpé. Entre l’héritage historique de la plateforme, l’empilement de plugins et les thèmes premium bourrés de fonctionnalités, on se retrouve vite avec des pages qui exécutent du JS dans tous les sens. Conséquence directe : des long tasks (des tâches JS qui bloquent le thread principal plus de 50 ms) qui plombent l’INP. Voyons les causes les plus fréquentes.
jQuery et le poids du legacy JavaScript
WordPress charge jQuery par défaut depuis toujours (compatibilité oblige), et la plupart des plugins s’appuient dessus pour ajouter leurs propres listeners d’événements. Le souci ? Chaque plugin actif ajoute sa couche de handlers, ses propres écouteurs de clic, de scroll ou de focus. Sur un site avec 20 ou 30 extensions actives, ça fait vite beaucoup de code exécuté à chaque interaction utilisateur.
Et le pire, c’est que jQuery lui-même n’est pas ultra performant comparé au JS natif moderne. On se retrouve donc avec une double peine : un framework legacy, plus une accumulation de listeners qui se marchent parfois dessus. Le thread principal sature, et l’INP grimpe en flèche.
Les plugins de tracking et de tag management
Google Analytics, Facebook Pixel, Hotjar, Matomo… tous ces scripts de tracking sont indispensables pour le marketing, mais ils ont un coût réel en performance. Installés via des plugins comme MonsterInsights ou Google Site Kit, ils injectent souvent plusieurs scripts tiers qui s’exécutent au chargement ET à chaque interaction (clic sur un lien, soumission de formulaire, etc.).
Ces scripts tournent sur le thread principal, en concurrence directe avec le rendu de l’interface. Du coup, quand l’utilisateur clique sur un bouton, le navigateur doit d’abord terminer d’exécuter le code de tracking avant de répondre visuellement. Ça se traduit par un délai perceptible, et donc un mauvais score INP.
Animations et transitions CSS/JS mal optimisées
Les animations, c’est joli, mais ça peut coûter cher en performance si c’est mal implémenté. Les effets parallax, les sliders type Revolution Slider ou les animations au scroll déclenchent souvent des reflows et des repaints (le navigateur recalcule la mise en page et redessine l’écran) à chaque frame.
Ces recalculs sont coûteux en ressources CPU. Si une animation se déclenche pile au moment où l’utilisateur clique quelque part, le navigateur est occupé à gérer le rendu visuel au lieu de traiter l’interaction. La latence qui en résulte pénalise directement l’INP, surtout sur mobile où la puissance de calcul est plus limitée.
Le rôle des thèmes lourds et des builders visuels
Les thèmes premium et les page builders comme Elementor ou Divi sont pratiques pour construire des sites rapidement, mais ils génèrent souvent énormément de JS inutilisé. Chaque module, chaque widget, chaque fonctionnalité embarque son propre script, même si vous n’utilisez qu’une petite partie des options disponibles.
Le navigateur doit donc parser et exécuter tout ce code sur chaque page, même si 80% n’est jamais réellement utilisé. C’est typiquement le genre de situation qui crée des long tasks à répétition, et qui plombe l’INP de manière chronique. Un site conçu avec un builder mal optimisé peut facilement dépasser les 500 ms d’INP, même sur un hébergement performant.
Profiler l’INP pas à pas avec les outils du navigateur
On est d’accord : connaître les causes théoriques d’un mauvais INP, c’est bien. Mais sans méthode pour repérer concrètement quel script pose problème sur votre site, ça reste abstrait. Voici la méthodologie que j’utilise systématiquement pour diagnostiquer un INP dégradé, étape par étape. Rien de sorcier, juste de la rigueur et les bons outils (tous gratuits, tous déjà dans votre navigateur ou presque).
Utiliser le panneau Performance de Chrome DevTools
Ouvrez Chrome DevTools (touche F12 ou clic droit > Inspecter), puis direction l’onglet « Performance ». C’est le cœur du diagnostic INP.
Cliquez sur le bouton d’enregistrement (le rond rouge), puis interagissez avec votre site comme le ferait un vrai visiteur : ouvrez un menu de navigation, cliquez sur un accordéon, remplissez un champ de formulaire. Arrêtez l’enregistrement après quelques secondes.
DevTools génère alors une timeline détaillée de tout ce qui s’est passé : scripts exécutés, temps de rendu, interactions utilisateur. C’est cette timeline qu’on va analyser dans les étapes suivantes.
Identifier les long tasks et leur origine (fichier/plugin)
Dans la timeline générée, repérez les blocs marqués en rouge : ce sont les Long Tasks, ces tâches JavaScript qui bloquent le thread principal pendant plus de 50 ms. Plus ils sont larges, plus l’impact sur l’INP est important.
Cliquez sur un de ces blocs rouges. DevTools affiche alors un panneau détaillé avec plusieurs onglets, dont « Bottom-Up » et « Call Tree ». Ces vues permettent de remonter la pile d’appels (stack trace) jusqu’au fichier JavaScript responsable.
Vous verrez généralement apparaître un nom de fichier explicite : elementor-frontend.min.js, jquery.min.js, ou parfois un script de tracking tiers comme Google Analytics ou un pixel Facebook. C’est exactement l’information qu’on cherche : savoir qui est coupable, sans se perdre en conjectures.
Analyser l’INP en conditions réelles avec le Web Vitals extension et CrUX
DevTools, c’est excellent pour du diagnostic ponctuel, mais ça reste du « lab data » (données de laboratoire, mesurées sur votre poste). Pour avoir une vision plus fidèle de l’expérience réelle des visiteurs, deux outils complémentaires s’imposent.
Installez l’extension Chrome « Web Vitals » : elle affiche l’INP en temps réel pendant votre navigation, directement dans un badge sur la barre d’outils. Pratique pour tester rapidement plusieurs pages sans repasser par DevTools à chaque fois.
Ensuite, consultez le rapport CrUX (Chrome UX Report) via PageSpeed Insights. Contrairement au lab data, le CrUX agrège les données terrain collectées auprès de millions d’utilisateurs Chrome réels. Vous verrez ainsi si votre INP problématique touche uniquement votre configuration de développement, ou bien l’ensemble de vos visiteurs.
Reproduire le problème avec le throttling CPU
Dernier point, et pas des moindres : votre machine de développement est probablement bien plus puissante qu’un smartphone milieu de gamme utilisé par une bonne partie de vos visiteurs. Résultat, certains problèmes d’INP restent invisibles en conditions normales de test.
La solution ? Activer le CPU throttling dans DevTools. Dans l’onglet Performance, avant l’enregistrement, sélectionnez « 4x slowdown » ou « 6x slowdown » dans les options de simulation CPU. Cela ralentit artificiellement l’exécution du JavaScript pour mimer un appareil bas de gamme.
Relancez alors votre enregistrement en reproduisant les mêmes interactions. Vous constaterez souvent que des Long Tasks jusque-là négligeables deviennent soudainement critiques. C’est cette version dégradée qui reflète le mieux l’expérience réelle d’une bonne partie de vos utilisateurs mobiles.
Corriger le JavaScript : différer, découper et déplacer les traitements
Une fois le diagnostic posé (vous savez quels scripts bloquent le thread principal), il faut passer à l’action. Et là, trois leviers principaux : différer ce qui n’est pas urgent, découper ce qui est trop long, et déplacer ce qui peut vivre ailleurs. Voyons ça concrètement, avec du code que vous pouvez copier-coller dans votre thème ou plugin.
Charger les scripts non critiques en defer ou async avec wp_enqueue_script
Par défaut, WordPress charge tous les scripts de façon synchrone : le navigateur doit les télécharger et les exécuter avant de continuer le rendu. Résultat : ça bloque, et l’INP en prend un coup. La solution consiste à ajouter les attributs defer ou async selon le rôle du script.
Depuis WordPress 6.3, on peut le faire nativement via le paramètre strategy de wp_enqueue_script() :
wp_enqueue_script(
'mon-script',
get_template_directory_uri() . '/js/mon-script.js',
array(),
'1.0',
array( 'strategy' => 'defer', 'in_footer' => true )
);
Pour les versions antérieures (ou pour un contrôle plus fin sur des scripts tiers), on passe par le filtre script_loader_tag :
function dev_wp_defer_scripts( $tag, $handle, $src ) {
$scripts_a_differer = array( 'mon-script', 'plugin-carousel' );
if ( in_array( $handle, $scripts_a_differer, true ) ) {
return str_replace( ' src', ' defer src', $tag );
}
return $tag;
}
add_filter( 'script_loader_tag', 'dev_wp_defer_scripts', 10, 3 );
Attention néanmoins : ne différez pas n’importe quel script. Ceux qui manipulent le DOM au chargement initial (menu mobile, slider above the fold) doivent parfois rester synchrones, sinon vous créez un flash de contenu non stylé ou des sauts de mise en page.
Découper les longues tâches avec setTimeout, requestIdleCallback ou scheduler.yield
Une Long Task, c’est une tâche JS qui monopolise le thread principal plus de 50 ms. Le navigateur ne peut alors traiter aucune interaction utilisateur pendant ce laps de temps. Donc si votre fonction de tracking ou de calcul fait 300 ms d’un bloc, autant dire que le clic de l’utilisateur va attendre.
La technique classique : découper le traitement en plusieurs micro-tâches avec setTimeout(fn, 0). Ça relâche la main au navigateur entre chaque étape :
function traiterParLots(items, index = 0) {
const lot = items.slice(index, index + 50);
lot.forEach(item => traiterItem(item));
if (index + 50 < items.length) {
setTimeout(() => traiterParLots(items, index + 50), 0);
}
}
Plus élégant : window.requestIdleCallback(), qui exécute le code uniquement quand le navigateur a du temps libre (donc sans retarder une interaction en cours) :
function traiterQuandLibre(items) {
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0 && items.length) {
traiterItem(items.pop());
}
if (items.length) traiterQuandLibre(items);
});
}
Et depuis peu, une API native pensée exactement pour ce problème : scheduler.yield(). Elle permet de rendre la main au thread principal entre chaque étape, tout en gardant la priorité de la tâche (contrairement à setTimeout qui repasse en fin de file) :
async function traiterAvecYield(items) {
for (const item of items) {
traiterItem(item);
await scheduler.yield();
}
}
Le support navigateur reste encore limité (Chrome principalement), donc prévoyez un fallback vers setTimeout pour les autres navigateurs.
Débrancher les listeners inutiles et déplacer la logique hors du thread principal (Web Worker)
Autre source fréquente de mauvais INP : trop de listeners actifs. Un thème mal codé attache parfois un click sur chaque élément d’une liste, alors qu’un seul suffirait. C’est là qu’intervient la délégation d’événements : on place le listener sur un parent commun, et on identifie l’élément cliqué via event.target.
// Au lieu de : document.querySelectorAll('.item').forEach(el => el.addEventListener('click', handler));
document.querySelector('.liste-items').addEventListener('click', function(e) {
if (e.target.matches('.item')) {
handler(e.target);
}
});
Moins de listeners, moins de mémoire consommée, et surtout moins de surcharge au moment de l’interaction.
Pour les calculs vraiment lourds (traitement d’image, parsing de gros JSON, calculs statistiques), la meilleure solution reste de sortir complètement du thread principal grâce à un Web Worker :
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: grosTableauDeDonnees });
worker.onmessage = function(e) {
afficherResultat(e.data);
};
// worker.js
self.onmessage = function(e) {
const resultat = calculLourd(e.data.data);
self.postMessage(resultat);
};
Ainsi, le calcul tourne dans un thread séparé : l’utilisateur peut continuer à cliquer, scroller, taper, sans aucun blocage perceptible.
Checklist avant mise en production :
- Vérifier qu’aucun script non critique ne charge de façon synchrone (
defer/asyncpar défaut) - Traquer les Long Tasks restantes dans DevTools et les découper si besoin
- Auditer les listeners avec l’onglet Elements > Event Listeners (fuir les doublons)
- Envisager un Web Worker dès qu’un calcul dépasse 50 à 100 ms
- Retester l’INP avec CPU throttling après chaque correctif, pas seulement en conditions idéales
