Core Web Vitals : comprendre LCP, INP et CLS pour le SEO

SEO & Performances

Table des matières :

  1. Core Web Vitals et SEO : oui, c’est un signal… non, ça ne remplace pas le contenu
  2. LCP : comprendre le plus gros rendu (et arrêter d’accuser le CDN par réflexe)
  3. INP : la réactivité, ou comment votre JavaScript vous sabote en production
  4. CLS : stabilité visuelle, ou l’art d’éviter que le bouton “Payer” se téléporte
  5. Mesurer “sur le terrain” : RUM, CrUX, SLO et observabilité (sinon vous pilotez à l’intuition)
  6. Un playbook pragmatique (et un peu impitoyable) pour améliorer LCP, INP et CLS

Core Web Vitals et SEO : oui, c’est un signal… non, ça ne remplace pas le contenu

Les Core Web Vitals (CWV) sont des métriques centrées utilisateur, mesurées sur le terrain (données réelles Chrome) et destinées à quantifier la qualité d’expérience : vitesse de rendu, réactivité, stabilité visuelle. Google les a formalisées parce qu’« on a l’impression que ça charge vite » est une unité de mesure aussi fiable que « mon Kubernetes marche chez moi ». Sur web.dev — Web Vitals, Google résume très bien le principe :

“Core Web Vitals are a set of real-world, user-centered metrics that quantify key aspects of the user experience.” — Google, web.dev, Web Vitals (https://web.dev/vitals/)

Deux points que beaucoup d’équipes « SEO » ratent (souvent avec enthousiasme) :

1) Google évalue les CWV principalement via des données terrain (CrUX / Search Console), typiquement au 75e percentile des visites. Concrètement : si 25% de vos sessions mobiles ont une expérience “mauvaise”, vous ne “passez” pas, même si le reste est excellent.

2) Les CWV ne sont pas “un score”, ce sont trois familles de problèmes très concrets. D’où l’absurdité de “viser 100/100” sans regarder les causes (au passage, si vous aimez les check-lists, il y a déjà un article maison : Sortir un site 100/100 au Page Speed Insights Desktop de Google : 20 recommandations à suivre).

Ajoutez un troisième point, plus “terrain” : CrUX est une moyenne glissante sur 28 jours. Donc si vous déployez un correctif lundi, Search Console ne devient pas soudainement verte mardi. À l’inverse, une régression qui dure une semaine peut vous polluer le graphe pendant un moment. C’est frustrant, mais c’est précisément ce qui rend la donnée robuste (et moins manipulable).

Côté SEO, la page experience est bien un signal, mais elle agit surtout comme un tie-breaker ou un handicap : à pertinence comparable, un site plus rapide/plus stable a tendance à mieux s’en sortir, et surtout à mieux convertir. Google le rappelle dans sa documentation “Page experience” : l’expérience compte, sans supplanter la pertinence du contenu (documentation Page Experience). Traduction opérationnelle : la performance ne “sauve” pas une page hors-sujet, mais une page utile peut perdre des positions (ou de la traction) si l’expérience est franchement dégradée.

Enfin, gardez en tête que CWV = données utilisateur, donc sensibles au contexte :

  • mobile vs desktop (en France, une part significative du trafic e-commerce et local reste très mobile) ;

  • réseau réel (métro, zone périurbaine, 4G/5G fluctuante) ;

  • géographie (un serveur en région parisienne ne donne pas la même latence perçue à Lille, Toulouse… ou depuis la Belgique/Suisse si vous captez du trafic transfrontalier) ;

  • couches “compliance” (bannières consentement RGPD/CNIL, CMP, tags) qui influencent souvent CLS et INP.

LCP : comprendre le plus gros rendu (et arrêter d’accuser le CDN par réflexe)

Le Largest Contentful Paint (LCP) mesure le temps nécessaire pour afficher l’élément de contenu principal visible dans le viewport (souvent une image “hero”, un H1, un bloc produit). Les seuils (Google) restent une référence opérationnelle : Bon ≤ 2,5 s, À améliorer 2,5–4 s, Mauvais > 4 s. Important : le LCP n’est pas “le chargement complet de la page”, c’est le moment où l’utilisateur a enfin quelque chose d’utile à regarder (et pas juste un squelette qui clignote).

Techniquement, diagnostiquer un LCP, c’est décomposer une chaîne : TTFB (serveur), load delay (ressources bloquantes/priority), load time (téléchargement), render delay (main thread occupé, CSS/JS, rendu). Les outils modernes (Chrome DevTools, Lighthouse, PageSpeed Insights, WebPageTest) permettent d’identifier l’élément LCP et de voir s’il souffre de priorisation (fetchpriority), de CSS bloquant, ou d’un rendu retardé par l’hydratation d’un framework. Et oui, une page peut avoir un bon TTFB et un LCP catastrophique si le rendu est retenu en otage par 800 kB de JavaScript.

Une lecture simple (et efficace) consiste à se poser 4 questions, dans cet ordre :

Segment LCP Symptôme typique Causes fréquentes Fix “qui marche souvent”
TTFB HTML arrive tard backend lent, cache absent, DB/CRM, TLS/redirects cache HTTP + CDN, warmup, réduire redirects, optimiser pages dynamiques
Load delay l’élément LCP est “découvert” tard CSS/JS bloquants, priorité faible, lazy-load au-dessus de la ligne de flottaison preload / fetchpriority="high" pour l’asset LCP, réduire CSS bloquant
Load time asset LCP long à télécharger image trop lourde, mauvais format, pas de responsive AVIF/WebP, srcset/sizes, compression, dimensionnement réel
Render delay asset téléchargé mais pas affiché main thread saturé, hydration, fonts, styles tardifs réduire JS, différer le non critique, CSS critique, SSR/streaming

Deux mini-scénarios très courants (et très “SEO”) :

  • Hero image en lazy-load par défaut : certains thèmes mettent loading="lazy" partout, y compris sur l’image au-dessus de la ligne de flottaison. Résultat : le navigateur attend, découvre l’image plus tard, et votre LCP explose. Le correctif est bêtement de ne pas lazy-loader l’asset LCP (et de réserver les lazy-load pour le dessous de la ligne de flottaison).

  • Titre LCP rendu côté client : si votre H1 (ou le bloc produit principal) n’existe qu’après hydratation React/Vue, le navigateur “voit” un DOM vide utilement, puis attend du JS, puis calcule, puis rend. Le CDN n’a rien à voir là-dedans : c’est un choix d’architecture de rendu.

Les optimisations LCP réellement efficaces sont rarement “magiques” : elles sont ennuyeuses, donc elles marchent. Typiquement : cache HTTP agressif (avec invalidation propre), compression Brotli, images responsives (srcset + sizes), formats modernes (AVIF/WebP), préchargement de l’asset LCP (<link rel="preload" as="image">), réduction du CSS critique, et suppression des scripts inutiles sur le chemin critique. Sur l’infra, optimiser le delivery aide (HTTP/2/HTTP/3, TLS 1.3, CDN, reverse proxy), mais ça ne compensera pas un front qui fait du cosplay d’IDE.

Pour creuser la partie réseau et reverse-proxy : NGINX : maîtriser HTTP/2, HTTP/3 QUIC et TLS 1.3, Varnish Cache : optimiser le cache HTTP et réduire la charge serveur et HAProxy : déployer un reverse proxy et load balancer sécurisé. Et si vous cherchez des optimisations plus généralistes : Optimisation performance web : 5 astuces pour réduire le temps de chargement.

Pour garder un ancrage “réalité du web”, un bon complément (non Google) est l’HTTP Archive Web Almanac, qui documente chaque année le poids des pages, l’usage du JS, les tiers, etc. C’est utile pour recadrer les débats du type “on a juste ajouté un petit script” (https://almanac.httparchive.org/).

INP : la réactivité, ou comment votre JavaScript vous sabote en production

Depuis 2024, INP (Interaction to Next Paint) a remplacé FID comme métrique de réactivité dans les CWV (et non, ce n’était pas une lubie : FID ne mesurait pas la latence totale ressentie, juste un délai partiel). INP évalue la latence d’une interaction (clic, tap, clavier) jusqu’au prochain rendu visible.

Deux subtilités à connaître (sinon on optimise à côté) :

  • Au niveau “page”, INP se base généralement sur la pire interaction représentative, souvent modélisée via le 98e percentile des interactions observées (donc pas juste “le premier clic”).

  • Au niveau “Core Web Vitals” (pass/fail), Google regarde ensuite la distribution terrain, typiquement au p75.

Seuils recommandés : Bon ≤ 200 ms, À améliorer 200–500 ms, Mauvais > 500 ms. En clair : si une interaction “réelle” met une demi-seconde à produire un feedback visuel, l’utilisateur ne pense pas “INP”, il pense “site cassé”.

INP se décompose en trois segments : input delay (l’événement attend parce que le main thread est occupé), processing time (vos handlers font trop de boulot), presentation delay (le rendu/paint arrive tard). Les causes classiques (et pas du tout exotiques) : bundles trop gros, trop d’hydratation côté client, handlers synchrones qui déclenchent des recalculs de layout, et “petites” librairies tierces qui font des “petits” travaux… sur le thread principal.

Petit cas concret (vu 100 fois) : sur mobile, un clic “Ajouter au panier” déclenche à la fois :

  • un fetch,

  • une animation,

  • un recalcul de mini-panier,

  • un tracking (analytics + ads),

  • un test A/B,

  • et parfois une modale.

Pris séparément, tout est “raisonnable”. Ensemble, vous obtenez une long task > 200 ms et un INP médiocre, surtout sur des appareils milieu de gamme (ceux qui font une grosse part du trafic réel).

Les correctifs INP, c’est une hygiène de runtime :

  • casser les long tasks (chunking via requestAnimationFrame / setTimeout(0) ; requestIdleCallback uniquement si vous acceptez que la tâche puisse ne jamais passer en cas de charge) ;

  • déporter du CPU dans des Web Workers quand c’est pertinent (par exemple : parsing, tri, gros calcul) ;

  • réduire le travail dans les handlers (pré-calcul, mémoïsation, virtualisation, debouncing/throttling sur scroll/resize) ;

  • éviter les patterns qui forcent le layout synchronement (offsetHeight/getBoundingClientRect en boucle).

Sur les frameworks, l’approche qui marche est souvent impopulaire mais rationnelle : rendre moins de JS (SSR/streaming, “islands architecture”, partial hydration), et charger le code par intention (route-based + interaction-based code splitting). Et côté tags : la meilleure optimisation INP est parfois… de supprimer un tiers inutile, ou de le retarder hors du chemin critique (après consentement, après interaction, après load, etc.). “On a besoin de tout mesurer” est rarement vrai ; “on a besoin de mesurer mieux” l’est plus souvent.

Pour la mesure, arrêtez de “sentir” la perf : instrumentez et corrélez avec les Performance Long Tasks, le Event Timing API, et des traces front/back (on y revient).

CLS : stabilité visuelle, ou l’art d’éviter que le bouton “Payer” se téléporte

Le Cumulative Layout Shift (CLS) mesure la somme des “sauts” de mise en page inattendus durant la vie de la page, selon une formule basée sur impact fraction × distance fraction, agrégée dans des fenêtres de session. Seuils : Bon ≤ 0,1, À améliorer 0,1–0,25, Mauvais > 0,25. Le CLS, c’est le genre de métrique qui semble “cosmétique” jusqu’au jour où votre CTA se décale sous le doigt de l’utilisateur. Là, bizarrement, tout le monde devient passionné.

La plupart des CLS proviennent de trois catégories : médias sans dimensions (images/iframes/vidéos), contenus injectés au-dessus de la ligne de flottaison (bannières, consentement, promo), et polices qui reflow (FOIT/FOUT). Et non, “mais chez moi ça ne bouge pas” n’est pas un argument : le CLS varie selon viewport, device, réseau, et surtout selon ce qui charge avant quoi. Les CMS et thèmes “riches” (lire : surchargés) ont un talent particulier pour empiler sliders, blocs dynamiques et pubs responsives sans réserver d’espace.

En France/UE, un piège récurrent est la bannière de consentement qui s’affiche en haut et pousse tout le contenu vers le bas (ou qui apparaît après 1–2 secondes, quand l’utilisateur a déjà commencé à lire). Si votre CMP ne permet pas de réserver un espace stable, vous pouvez souvent limiter la casse en :

  • positionnant la bannière en position: fixed (sans déplacer le flux) ;

  • évitant d’injecter au-dessus du header ;

  • prévoyant un placeholder (même minimal) si vous devez réserver de la place.

Les remèdes CLS sont basiques, donc souvent oubliés : toujours définir width/height ou aspect-ratio pour les médias, réserver des slots pour les composants asynchrones (ads/embeds), éviter d’insérer du contenu au-dessus sans placeholder, et préférer des animations transform/opacity (qui n’impactent pas le layout) à des modifications de propriétés déclenchant reflow.

Pour les polices : font-display: swap (ou mieux, stratégie ajustée), préchargement des fichiers WOFF2 critiques, et éventuellement size-adjust (quand vous savez ce que vous faites). Google résume l’objectif sans détour :

“CLS measures visual stability by quantifying how often users experience unexpected layout shifts.” — Google, web.dev, CLS (https://web.dev/cls/)

Un détail qui évite de faux débats : un CLS “volontaire” n’est pas forcément un CLS pénalisant. Les shifts causés par une interaction utilisateur (ouvrir un accordéon, afficher un panier) sont traités différemment des shifts inattendus. Donc le sujet n’est pas “plus aucune animation”, c’est “pas de surprise visuelle”.

Mesurer “sur le terrain” : RUM, CrUX, SLO et observabilité (sinon vous pilotez à l’intuition)

Si vous prenez une seule décision intelligente sur les CWV : priorisez les données terrain. CrUX (Chrome UX Report) et le rapport Core Web Vitals de Search Console donnent une vision agrégée, utile pour orienter (avec, encore une fois, une logique p75 et une fenêtre temporelle glissante). Mais pour débugger et arbitrer, il faut du Real User Monitoring (RUM) : capturer LCP/INP/CLS par page template, segmenter par device, réseau, pays, authentifié vs anonyme, etc. On a déjà un article qui pose bien les bases et les pièges : Real User Monitoring : RUM vs monitoring synthétique pour la performance web. Spoiler : le synthétique seul vous rassure, le RUM vous réveille.

Un point “gouvernance data” souvent négligé : un RUM utile n’est pas un espion. Vous voulez des métriques de perf, pas des données personnelles. Typiquement :

  • anonymiser / agréger,

  • éviter les URL contenant des identifiants,

  • respecter le consentement si votre cadre légal l’exige,

  • et surtout : se focaliser sur des segments actionnables (template, device class, réseau, pays).

Pour des équipes dev/devops, le niveau au-dessus consiste à intégrer la perf au même titre que la dispo : SLO (Service Level Objectives) et alerting. Exemple : “LCP p75 ≤ 2,5 s sur les pages produit mobile 4G” et “INP p75 ≤ 200 ms sur panier/checkout”. Pour instrumenter proprement, un pattern solide : capter les Web Vitals côté navigateur, les envoyer vers un collector, corréler avec traces backend et métriques infra. Si vous avez déjà une démarche d’observabilité, OpenTelemetry : unifier métriques, traces et logs pour l’observabilité s’intègre bien à ce modèle.

Exemple minimal (volontairement simple) d’envoi RUM avec la librairie web-vitals (utile pour démarrer un POC, puis à adapter : batching, retry, sampling, etc.) :

import {onLCP, onINP, onCLS} from 'web-vitals';

function sendToAnalytics(metric) {
  // Envoyer côté backend (éviter d’envoyer des données perso)
  navigator.sendBeacon('/rum', JSON.stringify({
    name: metric.name,
    value: metric.value,
    id: metric.id,
    rating: metric.rating,
    page: location.pathname
  }));
}

onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);

Côté run, vous voulez des dashboards et des alertes actionnables. Une stack classique : export vers Prometheus, visualisation Grafana, alerting via Alertmanager. Pour la partie monitoring “sérieux”, voir : Prometheus : architecture monitoring, PromQL, Alertmanager et Grafana.

Et comme tout ce qui compte finit par devenir un budget, formalisez des performance budgets (JS/CSS, poids image, nombre de requêtes, TTFB cible) et bloquez les régressions en CI. Vous avez déjà la tuyauterie CI/CD ? Tant mieux. Sinon, vous allez aimer apprendre “par incident”.

Un playbook pragmatique (et un peu impitoyable) pour améliorer LCP, INP et CLS

Commencez par trier le travail, sinon vous allez “optimiser” des pages que personne ne visite. La méthode rentable :

1) identifier les templates à fort trafic et fort enjeu (landing SEA, catégorie, produit, panier)
2) mesurer p75 LCP/INP/CLS sur ces templates en RUM
3) classer les causes par famille (réseau/serveur, rendu, JS, médias, tiers)

Un bon audit technique évite de bricoler à l’aveugle : Audit de site web : technique, SEO, UX et sécurité pour une roadmap et, pour la partie purement SEO, SEO technique, on-page et off-page : guide pour entreprises.

Ensuite, adaptez selon votre stack (oui, le contexte compte, désolé pour les recettes universelles).

Sur WordPress/WooCommerce, les gains LCP viennent souvent :

  • du cache (page + objet) et de la stratégie d’invalidation (éviter “purge all” à chaque action),

  • du nettoyage des plugins (le plugin “utile” qui injecte 4 scripts sur toutes les pages),

  • de la base de données (requêtes lentes, autoload gonflé, tables options qui deviennent un dépotoir).

Ressources : Optimisation base de données WordPress : diagnostic et réparation MySQL et la préparation aux pics : WooCommerce : préparer l’infrastructure aux pics de trafic et campagnes.

Sur PrestaShop, les problématiques INP/CLS se cachent souvent :

  • dans le thème (DOM trop profond, composants trop lourds au-dessus de la ligne de flottaison),

  • dans les modules front intrusifs (popups promo, chat, recommandations),

  • et dans les scripts tiers (tags partout, souvent en double).

Et si vous êtes en migration, faites-le sans sacrifier les perfs : Migration PrestaShop 8 : stratégie SEO et plan d’URL cross‑site.

Sur du headless, la perf se gagne surtout dans l’architecture (SSR/edge, cache, stratégie de rendu). La question utile n’est pas “headless ou pas”, c’est “quel niveau de rendu serveur, quelle part de JS, et quel cache au plus près de l’utilisateur” : Headless e-commerce : avantages, limites et critères de décision.

Enfin, mettez une gouvernance qui tient après la “task force performance”. Un playbook simple, mais efficace, ressemble à ça :

  • Définition of done par template : par exemple “pages produit : LCP p75 ≤ 2,5 s, INP p75 ≤ 200 ms, CLS p75 ≤ 0,1 + pas de régression Lighthouse mobile sur le chemin critique”.

  • Revue des tiers (mensuelle/trimestrielle) : ce qui n’apporte pas une valeur business mesurable n’a pas à impacter vos CWV.

  • Budgets en CI : bloquer un merge qui ajoute 300 kB de JS “par accident”.

  • Ownership clair : quelqu’un (ou une équipe) responsable de dire “non” aux régressions.

Vous pouvez formaliser ça via une Feuille de route technique et un rôle de Garant de la mise en production si votre organisation a tendance à confondre “livrer” et “mettre en prod un problème”.

Et si vous voulez une vérité simple pour finir : les Core Web Vitals ne sont pas une mode SEO. Ce sont juste des bugs d’ingénierie mesurés avec des chiffres. Ça tombe bien : les chiffres, ça se corrige.

Kévin DECQ-CAILLET, Directeur associé

Co-fondateur du studio de développement Les Vikings, mon cœur est voué aux paradoxes. Amour de la technologie et de l'Histoire, passion pour la gestion, le potager et le béhourd - si vous ne connaissez pas, ça vaut le détour. Accessoirement, une expérience de plus de 15 ans dans le domaine du numérique. Ce qui implique que j'en sais assez pour constater que j'ai encore beaucoup à apprendre.

Résumé de la politique de confidentialité

Ce site utilise des cookies afin que nous puissions vous fournir la meilleure expérience utilisateur possible. Les informations sur les cookies sont stockées dans votre navigateur et remplissent des fonctions telles que vous reconnaître lorsque vous revenez sur notre site Web et aider notre équipe à comprendre les sections du site que vous trouvez les plus intéressantes et utiles.