Insight · IA appliquée

Lighthouse CI sur Astro et Hydrogen : la performance comme contrainte de merge

Lighthouse manuel mesure ; Lighthouse CI gate. Configuration lighthouserc.json complète, intégration GitHub Actions, modes warn / error / ratchet, pièges techniques courants, et budgets opérationnels pour un site DTC mid-market en 2026.

Publié le 7 mai 2026 · 13 min de lecture · Sergio Nokam


Un site qui passe Lighthouse 95 au launch et qui dérive à 72 six mois plus tard est un site qui n’a jamais eu de discipline performance — il a eu un bon jour. Cette dérive silencieuse est le pattern le plus banal du commerce mid-market : la marque investit dans une refonte, célèbre un score Core Web Vitals impeccable au go-live, puis laisse les semaines de release ronger l’acquis. À chaque sprint, deux ou trois cents kilo-octets de JavaScript supplémentaires entrent par la porte de service — un nouveau pixel marketing, une App Block d’avis client, un widget de chat — et personne dans la pipeline ne lève la main.

C’est précisément le problème que Lighthouse CI a été conçu pour résoudre, dans un travail publié par Patrick Hulce et l’équipe Chrome en 2019 et tenu à jour depuis1. L’outil prend les audits Lighthouse — la même mécanique que celle disponible dans l’onglet Lighthouse de Chrome DevTools — et l’embarque dans la pipeline d’intégration continue de manière à ce que chaque pull request mesure son propre coût performance avant le merge. Le verdict n’est plus une opinion d’audit ponctuel. Il devient une contrainte de merge, au même titre qu’un test unitaire qui échoue ou qu’une erreur de typage TypeScript.

L’essai qui suit expose la mécanique de l’outil, la configuration lighthouserc.json opérationnelle que j’embarque sur les sites Astro et Hydrogen, l’intégration GitHub Actions correspondante, les trois modes de gating et leur usage stratégique, et les pièges techniques que toute équipe rencontre dans les premières quatre semaines d’adoption.

Lighthouse manuel ne tient pas, en trois mécaniques

Lighthouse en version manuelle — celle de DevTools, celle de PageSpeed Insights — est un outil de diagnostic, pas un outil de discipline. Il échoue à protéger un site dans la durée par trois mécaniques convergentes.

Variance contextuelle de la mesure unique. La même page mesurée sur le MacBook M2 du tech lead à 9 h obtient un score différent du même site mesuré sur le poste Windows du gestionnaire de projet à 16 h sur connexion d’entreprise. La variance interne d’une mesure Lighthouse unique tourne autour de cinq à dix points, et tient à des facteurs hors contrôle de l’auditeur : charge CPU ambiante de la machine de test, état du cache DNS, négociation TLS, jitter réseau résiduel. Toute comparaison entre deux mesures isolées est, statistiquement, peu fiable.

Cadence ponctuelle de l’audit. Personne dans une équipe n’audite quotidiennement, et même les équipes disciplinées n’auditent qu’à la sortie d’une release ou lorsqu’un sponsor demande un rapport. Entre deux audits, la régression peut s’installer sur cinq, dix, quinze sprints sans laisser de trace dans le journal opérationnel. Quand le rapport CrUX du trimestre arrive avec ses chiffres terrain, il est trop tard pour rétro-blâmer une PR particulière.

Position en aval du merge. Lorsqu’une équipe découvre que le score a chuté, le code en cause est déjà en production ou en staging avancé. La remédiation se fait en mode pompier : coûteuse en temps de spécialiste, fragile dans son rollback parce qu’elle implique souvent plusieurs PR cumulées, conflictuelle avec le sprint en cours. La discipline raisonnable est d’attraper la régression avant qu’elle entre dans la branche principale, ce qui n’est possible qu’avec une mesure automatisée déclenchée à l’ouverture de la pull request.

Architecture Lighthouse CI : runner, assertions, server

Pipeline Lighthouse CI comme contrainte de merge Pipeline d'intégration continue. Une pull request déclenche trois exécutions Lighthouse parallèles dont la médiane est calculée. Cette médiane passe par un système d'assertions configurées dans lighthouserc.json. Si toutes les assertions sont satisfaites, le merge est autorisé. Sinon, la pull request est bloquée jusqu'à correction. Pull Request git push Lighthouse #1 Lighthouse #2 @lhci/cli collect Lighthouse #3 Médiane neutralise variance Assertions lighthouserc.json LCP / INP / CLS / score Merge autorisé main ← PR PR bloquée corriger / retenter
Lighthouse CI transforme la performance en contrainte de merge. La pull request mesure son propre coût avant d'entrer dans la branche principale.

Lighthouse CI se compose de trois éléments distincts qui collaborent : un runner qui exécute Lighthouse de manière reproductible dans la CI, un système d’assertions qui transforme chaque mesure en verdict pass / fail dans le contexte de la PR, et un server qui stocke les résultats historisés.

Le runner — @lhci/cli collect — est invoqué dans la pipeline GitHub Actions, GitLab CI ou équivalent, après que la branche concernée ait été buildée et servie sur un port local. Il lance Lighthouse trois fois sur chaque URL critique, puis retient la médiane des trois mesures. Cette redondance neutralise l’essentiel de la variance de mesure unique. La médiane sur trois runs apporte typiquement une stabilité de plus ou moins un à deux points sur le score, ce qui rend le comparatif utilisable.

Le système d’assertions — défini dans un fichier lighthouserc.json versionné au repo — exprime les budgets que la pull request doit respecter. Une assertion type ressemble à : largest-contentful-paint: ['error', { maxNumericValue: 1800 }], ou total-byte-weight: ['warn', { maxNumericValue: 1500000 }]. Si l’assertion échoue, l’exit code de @lhci/cli assert est non-zéro, la pipeline échoue, et la PR ne peut pas être mergée sans intervention explicite.

Le server — facultatif mais hautement recommandé sur tout site sérieux — héberge les rapports complets de chaque run et permet de comparer la PR courante à la branche principale. Il propose une vue waterfall de chaque audit, l’historique des scores sur les dernières semaines, et un système de liens permanents qui peuvent être attachés en commentaire de la PR par un bot CI. Le tech lead qui revoit la PR voit, sans quitter GitHub, le delta exact en LCP, INP, CLS, poids transféré, temps de blocage thread principal, et les éventuelles régressions sur les audits secondaires comme l’accessibilité.

Configuration lighthouserc.json opérationnelle

Voici la configuration concrète que j’embarque sur un site Astro de production. Elle est conçue pour être lisible par un dev senior qui n’a jamais touché Lighthouse CI auparavant, et reproductible en l’état sur tout site Astro 6.x avec dist statique.

{
  "ci": {
    "collect": {
      "url": [
        "http://localhost:4173/",
        "http://localhost:4173/services/diagnostic-stack",
        "http://localhost:4173/services/ai-spark",
        "http://localhost:4173/insights"
      ],
      "numberOfRuns": 3,
      "settings": {
        "preset": "desktop",
        "throttlingMethod": "simulate",
        "throttling": {
          "rttMs": 40,
          "throughputKbps": 10240,
          "cpuSlowdownMultiplier": 1
        },
        "screenEmulation": {
          "mobile": false,
          "width": 1350,
          "height": 940,
          "deviceScaleFactor": 1
        },
        "chromeFlags": "--no-sandbox --disable-dev-shm-usage --headless=new"
      },
      "startServerCommand": "npm run preview",
      "startServerReadyPattern": "Local:.*4173",
      "startServerReadyTimeout": 30000
    },
    "assert": {
      "assertions": {
        "categories:performance": ["error", { "minScore": 0.95 }],
        "categories:accessibility": ["error", { "minScore": 0.95 }],
        "categories:best-practices": ["error", { "minScore": 0.95 }],
        "categories:seo": ["error", { "minScore": 0.95 }],
        "largest-contentful-paint": ["error", { "maxNumericValue": 1500 }],
        "interaction-to-next-paint": ["error", { "maxNumericValue": 180 }],
        "cumulative-layout-shift": ["error", { "maxNumericValue": 0.05 }],
        "total-blocking-time": ["error", { "maxNumericValue": 150 }],
        "first-contentful-paint": ["warn", { "maxNumericValue": 1000 }],
        "speed-index": ["warn", { "maxNumericValue": 1500 }],
        "uses-text-compression": "error",
        "uses-responsive-images": "error",
        "render-blocking-resources": ["error", { "maxLength": 0 }],
        "unminified-javascript": "error",
        "unused-javascript": ["warn", { "maxLength": 1, "maxNumericValue": 20000 }],
        "total-byte-weight": ["warn", { "maxNumericValue": 700000 }],
        "dom-size": ["warn", { "maxNumericValue": 800 }]
      }
    },
    "upload": {
      "target": "lhci",
      "serverBaseUrl": "https://lhci.nokaris.ca",
      "token": "$LHCI_TOKEN"
    }
  }
}

Quelques points méritent commentaire pour qui n’a jamais opéré Lighthouse CI.

Le bloc settings.throttling désactive le ralentissement CPU et réseau qui s’applique par défaut en mode mobile. Sur un site qui sert une cible mobile-first comme NOKARIS, je conserve une seconde configuration parallèle dédiée mobile avec cpuSlowdownMultiplier: 4 et un throttling 4G dégradé — le lighthouserc.mobile.json est alors lancé en complément du fichier desktop par une matrice GitHub Actions à deux entrées. L’erreur courante est de tester en desktop seulement et d’oublier que Google ranke sur la mesure mobile.

startServerCommand: "npm run preview" lance le serveur Astro après build. Le pattern de prêt Local:.*4173 détecte la ligne que Astro Vite imprime dans stdout dès que le serveur écoute. Sans ce pattern, le runner attaque le serveur avant qu’il soit prêt et obtient des ECONNREFUSED aléatoires qui font échouer la pipeline en apparence à cause de la perf, mais en réalité à cause d’une race condition.

Le bloc chromeFlags: "--no-sandbox --disable-dev-shm-usage --headless=new" est non-négociable dans un environnement CI conteneurisé. Le --no-sandbox est requis parce que les runners GitHub Actions tournent comme root et que Chromium refuse le sandbox dans ce contexte. Le --disable-dev-shm-usage redirige la mémoire partagée vers /tmp parce que le /dev/shm par défaut des conteneurs Docker est limité à 64 Mo, ce qui crashe Chrome sur les pages riches. Le --headless=new active le nouveau mode headless Chromium 109+, plus rapide et plus stable que l’ancien --headless.

L’assertion render-blocking-resources avec maxLength: 0 est stricte mais saine : aucune ressource bloquante ne devrait survivre à un build Astro correctement optimisé. Toute violation est, à 95 % du temps, l’introduction d’un <link rel="stylesheet"> non-différé ou d’un <script> synchrone hérité d’un widget tiers que l’équipe a oublié de wrapper en defer.

GitHub Actions : intégration en 60 lignes

Le workflow associé tient en un fichier .github/workflows/lighthouse-ci.yml qui ressemble à ceci.

name: lighthouse-ci

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  lhci:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - uses: actions/setup-node@v4
        with:
          node-version: 22.12.0
          cache: npm

      - run: npm ci

      - run: npm run build

      - name: Lighthouse CI desktop
        run: npx --no-install lhci autorun --config=lighthouserc.json
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
          LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}

      - name: Lighthouse CI mobile
        run: npx --no-install lhci autorun --config=lighthouserc.mobile.json
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
          LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}

      - name: Upload .lighthouseci/ as artifact
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lhci-reports
          path: .lighthouseci/
          retention-days: 14

Le LHCI_GITHUB_APP_TOKEN provient de l’app GitHub officielle Lighthouse CI2 qui poste un check sur la PR avec le verdict de chaque catégorie d’assertion. Le LHCI_TOKEN authentifie l’upload vers le server self-hosted, soit Cloudflare Tunnel exposé sur lhci.nokaris.ca, soit instance Docker hébergée chez le client. La condition if: always() sur l’upload artifact garantit que les rapports HTML sont récupérables même si les assertions ont échoué — c’est précisément à ce moment-là qu’on en a le plus besoin.

Le timeout-minutes: 10 est une borne dure : un run Lighthouse CI complet desktop + mobile sur quatre URL prend typiquement quatre à six minutes. Au-delà de dix, la cause est presque toujours un crash Chromium silencieux ou un freeze sur un script tiers, et il vaut mieux échouer la pipeline plutôt que la laisser tourner.

La performance n’est pas une compétence individuelle. C’est une discipline d’équipe, et la discipline d’équipe se construit dans la pipeline, pas dans la culture.

Trois modes de gating et leur usage stratégique

L’aspect le plus mal compris de Lighthouse CI tient au fait que la discipline imposée n’est pas binaire. L’outil propose trois modes d’assertion, qui correspondent à trois philosophies de discipline opérationnelle, et le choix entre les trois est stratégique.

Mode warn. L’assertion qui échoue émet un avertissement visible dans la pipeline mais ne bloque pas le merge. C’est le mode d’introduction recommandé sur un site existant non-discipliné, où l’application brutale de budgets stricts paralyserait toute livraison pour les six premières semaines. Le mode warn permet à l’équipe de prendre conscience de l’état réel du site, d’identifier les régressions au fil de l’eau, et de constituer un baseline historique sur lequel cadrer les budgets futurs. Concrètement, je laisse warn pendant trois à quatre sprints, je collecte les distributions sur le server, et je règle les seuils sur le 90e centile observé.

Mode error. L’assertion qui échoue bloque le merge. La PR ne peut pas avancer tant que la régression n’a pas été corrigée ou qu’une dérogation explicite — typiquement une override label GitHub appliquée par un reviewer senior — n’a pas été apposée. C’est le mode opérationnel cible pour tout site en production sérieuse, et c’est celui que j’applique par défaut sur les sites que j’opère après un Diagnostic Stack ou une migration Hydrogen.

Mode assertMatrix avec budget budgétaire. Variante moins documentée mais cruciale : l’assertion ne fait que vérifier que la PR ne dégrade pas le baseline courant — c’est le pattern ratchet. Si le LCP de la branche principale est de 1 650 millisecondes, la PR doit livrer 1 650 ou mieux ; elle n’a pas à atteindre le budget cible si celui-ci est plus strict. Ce mode, exprimé en pratique par une comparaison historique sur le server via le bloc assertMatrix et la median URL comparison, évite l’écueil opposé : interdire toute évolution fonctionnelle parce qu’un budget initial trop strict bloquerait des PR par ailleurs vertueuses. Le ratchet implémente le principe « pas pire qu’avant » et constitue, dans la pratique, le compromis le plus durable pour des équipes en phase de remédiation.

Sur un site en migration, j’utilise les trois en superposition : error absolu sur les trois métriques de classement Google (LCP, INP, CLS) parce qu’elles sont non-négociables, ratchet sur la perf agrégée et le poids JavaScript pour autoriser l’évolution fonctionnelle progressive, et warn sur les audits secondaires pour visibiliser sans bloquer.

Les pièges techniques qui surprennent les premières équipes

Quatre pièges récurrents méritent d’être nommés parce qu’ils cassent la pipeline de manière apparemment aléatoire et consomment, sans cela, deux à trois jours de debug pour un dev qui découvre l’outil.

Cold-start du serveur Astro. Le premier run Lighthouse après startServerCommand mesure la perf du cold cache Vite, pas celle du build de production. Le LCP peut être anormalement élevé sur la première URL auditée. Solution : utiliser npm run preview qui sert le build statique de dist/, et non npm run dev. Sur Hydrogen, le piège est inverse — le serveur dev SSR doit être warm avant le run, ce qui implique soit un lighthouserc warm-up phase, soit un startServerReadyTimeout étendu à 60 secondes minimum.

Cache HTTP et headers cache-control: no-store. Lighthouse pénalise les ressources non-cachables dans la catégorie best-practices. Sur un Worker Cloudflare qui retourne cache-control: no-store par défaut sur ses réponses dynamiques, l’audit échoue alors que la configuration est intentionnelle. Solution : whitelister la route concernée dans le bloc assertions avec un urlPattern qui exempte cette assertion, ou configurer le Worker pour différencier les réponses cachables des non-cachables.

Multipage et état partagé. Lighthouse CI audite chaque URL en isolation par défaut, mais certains sites e-commerce reposent sur un état partagé — panier persisté en localStorage, session anonyme avec cookie pré-rempli. Si l’URL /cart est auditée sans pré-condition, le panier est vide et la mesure ne reflète pas l’expérience réelle. Solution : utiliser un script puppeteerScript qui pré-remplit le panier via l’API Storefront avant la mesure, ou auditer uniquement les URL accessibles en état neutre.

Bundle splitting et chargement différé. Astro et Hydrogen utilisent le code splitting agressif. Lighthouse mesure le bundle critique chargé synchrone, pas le bundle total. Une PR peut ajouter 200 kilo-octets de JavaScript chargés en client:visible sans dégrader le LCP — c’est conforme à la philosophie islands. L’assertion sur total-byte-weight capture cela, mais l’assertion sur unused-javascript peut faux-positiver. Solution : différencier les assertions par catégorie et accepter qu’un site moderne normal dépasse 500 kilo-octets de JavaScript total tant que le critique reste sous 30 kilo-octets.

Custom assertions : le poids des scripts tiers

Au-delà des assertions standards, Lighthouse CI accepte des custom audits qui inspectent le détail des ressources chargées. C’est utile pour borner spécifiquement le poids des scripts tiers — pixels marketing, App Blocks Shopify, widgets de chat — qui sont la source de dérive perf la plus banale en e-commerce mid-market.

"third-party-summary": ["error", {
  "maxLength": 5,
  "warnings": [
    "Klaviyo > 50000 bytes",
    "Yotpo > 80000 bytes",
    "Recharge > 30000 bytes"
  ]
}],
"network-requests": ["warn", {
  "maxLength": 80
}],
"resource-summary:script:size": ["error", {
  "maxNumericValue": 350000
}],
"resource-summary:third-party:size": ["warn", {
  "maxNumericValue": 200000
}]

L’assertion resource-summary:third-party:size capture le poids agrégé de tout ce qui n’est pas servi depuis le domaine de la marque. Sur un site Shopify Plus typique, cette mesure dépasse régulièrement 800 kilo-octets, avec un gros tiers à GTM, Meta Pixel, Klaviyo et un router de cookies de consentement. Plafonner à 200 kilo-octets — comme dans la configuration ci-dessus — n’est pas tenable en l’état ; c’est un objectif qui implique une migration server-side de la majorité des pixels et la suppression des deux ou trois apps tierces les moins justifiées. C’est précisément le type d’arbitrage que je remets en livrable de Diagnostic Stack.

Server self-hosted ou Google-hosted

Le server Lighthouse CI peut être hébergé selon trois patterns, qui correspondent à trois profils de besoin.

Pattern self-hosted Docker. Le repo officiel GoogleChrome/lighthouse-ci fournit un Dockerfile qui tourne sur n’importe quelle infrastructure container — droplet DigitalOcean, ECS, Cloud Run, Fly.io. Le backend par défaut est SQLite ; pour un site avec rétention historique > 6 mois, il vaut mieux configurer Postgres. Le coût d’opération réel sur un droplet de 1 vCPU / 1 Go RAM tourne autour de 6 à 12 dollars US par mois, et tient une équipe jusqu’à 200 PR par semaine sans saturation.

Pattern Cloudflare Tunnel + Docker local. Pour les sites qui n’ont pas d’infrastructure cloud existante, j’opère le server sur le poste du founder ou sur un Raspberry Pi de bureau, exposé via Cloudflare Tunnel sur un sous-domaine lhci.client.ca. Le coût d’infra est nul, l’authentification Cloudflare Access protège l’endpoint, et la pipeline GitHub Actions atteint le server par le tunnel sans configuration réseau complexe. C’est le pattern que j’utilise sur le site NOKARIS lui-même.

Pattern PageSpeed Insights API. Pour les équipes qui ne veulent pas opérer de server, Lighthouse CI peut uploader vers l’API publique Google PageSpeed Insights via target: "temporary-public-storage". Les rapports sont accessibles 7 jours par lien public unique, sans authentification ni stockage long terme. C’est une solution acceptable pour démarrer, mais elle empêche la comparaison historique au-delà d’une semaine, ce qui rend le mode ratchet inopérant.

Pourquoi c’est central pour Ship in 90

La promesse commerciale de NOKARIS, Ship in 90, ne se réduit pas à une livraison rapide. Elle implique que ce qui est livré tient dans le temps — que la marque ne récupère pas, six mois plus tard, un site dégradé qu’il faut réauditer. Cette tenue dans le temps n’est pas affaire de talent individuel ; elle est affaire de mécanique. Lighthouse CI est l’une des deux ou trois mécaniques qui rendent cette tenue reproductible, au même titre que les budget tests sur le poids du bundle ou les tests E2E Playwright sur les parcours critiques.

Lorsque je termine un mandat de migration Hydrogen, le repo client que je remets contient un lighthouserc.json versionné, un lighthouserc.mobile.json parallèle, une intégration GitHub Actions opérationnelle, un server Lighthouse CI déployé chez le client avec backend Postgres, et une documentation interne expliquant comment ajuster les budgets en cas d’évolution fonctionnelle légitime. La culture perf passe alors du one-shot à la steady state, et c’est cette transition qui transforme la migration en investissement durable plutôt qu’en simple coup de peinture technique.

Le Diagnostic Stack à 7 500 dollars CAD que j’opère en amont d’une migration inclut, dans son livrable, un fichier lighthouserc.json calibré sur le site existant, accompagné d’une grille de budgets cibles à atteindre post-migration. Le client peut, s’il choisit de différer la migration, intégrer immédiatement ce fichier dans sa pipeline existante et commencer à arrêter la dérive — même sans NOKARIS comme prestataire d’exécution. C’est une portion du livrable que je remets ouverte, parce qu’elle a de la valeur indépendamment de la suite commerciale, et parce qu’un audit qui ne laisse pas d’outil opérable derrière lui n’a, à mon avis de praticien, qu’une valeur partielle.


Footnotes

  1. Patrick Hulce et l’équipe Google Chrome, Lighthouse CI : web.dev/articles/lighthouse-ci. Documentation officielle, mise à jour 2024 pour la métrique INP. Repo de référence : github.com/GoogleChrome/lighthouse-ci avec exemples GitHub Actions, GitLab CI, CircleCI, Jenkins.

  2. Lighthouse CI GitHub App officielle : github.com/apps/lighthouse-ci. Installation gratuite, poste un check automatique sur chaque PR avec le verdict de chaque catégorie d’assertion. Le token LHCI_GITHUB_APP_TOKEN se génère dans la configuration de l’app après installation.

Questions fréquentes

Quelle est la différence entre Lighthouse et Lighthouse CI ?

Lighthouse est l'outil d'audit ponctuel intégré à Chrome DevTools et à PageSpeed Insights ; il produit un rapport unique pour une mesure donnée. Lighthouse CI est l'orchestrateur qui exécute Lighthouse de manière reproductible dans un pipeline d'intégration continue, retient la médiane sur trois runs pour neutraliser la variance, applique des assertions configurables sur chaque métrique, et bloque ou n'autorise le merge d'une pull request qu'en fonction du verdict. Lighthouse mesure ; Lighthouse CI gate.

Combien de temps un run Lighthouse CI ajoute-t-il à un pipeline ?

Sur un site Astro avec quatre URL critiques auditées, le run complet — collecte sur trois passes, assertions, upload server — dure entre 40 et 90 secondes. Sur un site Shopify Hydrogen avec dix URL et un nombre élevé d'App Blocks, comptez 3 à 5 minutes. C'est un coût marginal sur un pipeline qui inclut déjà build, type-check et tests E2E.

Comment configurer Lighthouse CI sur un site Shopify Hydrogen ?

Hydrogen étant une application Remix / Vite servie en SSR, le serveur doit être démarré dans la pipeline via npm run dev ou un build de preview, puis Lighthouse CI cible localhost. Le runner doit être lancé avec les flags --no-sandbox et --disable-dev-shm-usage pour éviter les crashes Chrome dans les conteneurs CI à mémoire partagée limitée, et les requêtes Storefront API doivent être stubées ou pointées vers une boutique de test pour éviter de polluer l'analytics.

Faut-il choisir le mode error ou le mode ratchet pour bloquer les régressions ?

Le mode error applique un budget absolu (LCP < 1800 ms, par exemple) et bloque toute PR qui le dépasse. Il convient aux sites disciplinés qui ont déjà atteint le budget cible. Le mode ratchet applique le principe du « pas pire qu'avant » en comparant la PR à la branche principale ; il convient aux sites en phase de remédiation progressive, où un budget absolu trop strict bloquerait des PR par ailleurs vertueuses. Sur un site en migration j'utilise les deux : ratchet sur la perf agrégée, error absolu sur les métriques de classement Google (LCP, INP, CLS).

Lighthouse CI fonctionne-t-il sur des pages derrière authentification ?

Oui, via le paramètre extraHeaders ou via un script de pre-puppeteer qui injecte un cookie de session avant l'audit. Pour les sites e-commerce, je recommande d'auditer en mode anonyme uniquement — la performance vue par un utilisateur logué étant typiquement meilleure que celle vue par un anonyme à cause du cache de session et de la personnalisation préchargée. Le KPI client est l'expérience anonyme.

Quels budgets Lighthouse CI pour un site DTC mid-market en 2026 ?

Pour pages produit et collection : LCP plafonné à 1800 ms, INP plafonné à 180 ms, CLS plafonné à 0.05, score Performance plancher à 90, JavaScript transféré plafonné à 350 ko gzippés. Pour la home et pages éditoriales : LCP plafonné à 1500 ms, score Performance plancher à 95, JavaScript plafonné à 200 ko gzippés. Score d'accessibilité plancher à 95 sur tous les types de page. Ces budgets intègrent une marge de 20 % au-dessus des seuils Google Core Web Vitals 2026 pour absorber la variance résiduelle.