optimisation core web vitals 8 min

Cookie de session : le tueur silencieux de TTFB que personne ne surveille

Un cookie de session placé sur les pages publiques peut doubler votre Time to First Byte. Voici comment le mesurer, le confiner et regagner jusqu'à 400 ms sans changer d'hébergement.

Par Julien Morel
Partager

On a debuggué un site e-commerce qui plafonnait à 55 au PageSpeed Insights sur mobile alors que le serveur répondait en 80 ms en local. Le TTFB réel, mesuré depuis Paris sur une connexion fibre, oscillait entre 500 et 700 ms. Le coupable n’était ni la base de données, ni le SSR, ni un bundle JavaScript trop lourd. C’était un Set-Cookie émis sur la page d’accueil, les fiches produit et les pages catégories, par un middleware de session qui n’avait rien à y faire. Supprimer ce cookie sur les routes publiques a fait chuter le TTFB à 110 ms sans toucher à l’infrastructure. Voici comment reproduire ce diagnostic et ce qu’il dit de notre rapport collectif aux sessions.

Quand un visiteur non authentifié arrive sur une page, la plupart des CDN et des proxies inverses regardent l’en-tête Cookie de la requête pour décider de servir une version en cache ou de remonter au serveur d’origine. Si une réponse contient un Set-Cookie, le CDN considère qu’elle est personnalisée et ne la met pas en cache. Si la requête suivante porte un cookie, même vide, le CDN bypasse le cache parce qu’il ne peut pas savoir si le contenu dépend de ce cookie. Résultat : chaque visiteur, qu’il soit identifié ou pas, tape l’origine.

Cette mécanique est documentée, mais sous-estimée. On a mesuré l’écart sur un site statique hébergé derrière Fastly : sans cookie, le TTFB médian depuis une dizaine de sondes européennes était de 12 ms. Avec un Set-Cookie de session posé par un script PHP en amont, le TTFB montait à 230 ms. La seule différence était l’aller-retour vers l’origine. Multiplié par le nombre de pages vues d’un site à 100 000 visites mensuelles, l’impact cumulé se chiffre en centaines d’heures de latence.

Le piège, c’est que beaucoup d’applications placent un cookie de session avant même de savoir si l’utilisateur en aura besoin. Un framework PHP classique, une application Rails, un middleware Express qui appelle session.init() au niveau de l’application entière : la session est créée, le cookie est posé, et le cache part en fumée sur l’ensemble du site. Même les pages de mentions légales héritent d’un PHPSESSID ou d’un connect.sid.

La session n’a rien à faire sur une page publique

Distinguons deux types de routes. Les routes authentifiées : compte utilisateur, panier, commandes, espace client. Les routes publiques : page d’accueil, fiches produit, articles de blog, résultats de recherche. Sur ces dernières, un cookie de session ne sert à rien dans 99 % des cas. Le panier peut être géré côté client avec un localStorage synchronisé au moment du checkout. La personnalisation basée sur l’historique peut attendre une requête API authentifiée, qui portera un token dans l’en-tête Authorization plutôt qu’un cookie global.

Le problème vient rarement d’une intention explicite. C’est presque toujours un défaut de configuration : un intergiciel de session monté sur *, un fichier .htaccess qui initialise la session avant le routage, ou une configuration Next.js où le middleware vérifie la session sur chaque requête, y compris celles qui servent des assets statiques. Le développeur pense sécuriser son application. Il la freine.

La correction est étonnamment simple : ne poser le cookie de session que sur les routes qui en ont besoin. Dans Express, cela revient à placer le middleware de session après le routage des pages publiques. Dans Next.js, on peut utiliser un matcher de middleware qui exclut les pages statiques et les assets. Sur un serveur Apache ou Nginx, on peut conditionner l’appel à la session via des règles de localisation. Le gain en TTFB est immédiat.

⚠️ Attention : si vous utilisez un cookie de session pour le panier, le transférer brutalement vers le stockage local peut casser le tunnel de conversion. Mesurez le taux d’abandon avant et après. Le compromis performance / conversion se juge sur un A/B test, pas dans un article.

Deux approches pour les apps qui ont quand même besoin d’état

Certaines applications front-end modernes ont besoin de connaître l’état de l’utilisateur pour afficher un header personnalisé (« Bonjour, Kevin ») sur toutes les pages, même publiques. L’approche classique consiste à vérifier la session côté serveur à chaque requête, donc à poser un cookie. Une alternative efficace : injecter l’état utilisateur dans le HTML initial via un script JSON dans le <head>, puis gérer l’affichage côté client avec un store. C’est là qu’un outil comme Zustand devient pertinent : il permet de peupler un état global à partir de ce blob JSON, sans déclencher d’appels serveur supplémentaires sur les pages statiques.

La requête qui vérifie l’authentification peut être déplacée vers un appel API asynchrone, après le chargement de la page, avec un token stocké en localStorage ou en httpOnly cookie strictement scopé à l’API. La page se charge sans cookie, le CDN la met en cache, l’utilisateur voit le contenu immédiatement, et le header se met à jour 200 ms plus tard. La différence perçue est nulle. La différence mesurée au TTFB, elle, est massive.

L’autre approche consiste à utiliser un cookie uniquement pour le domaine de l’API. Si votre front est sur www.example.com et votre API sur api.example.com, vous pouvez poser le cookie de session sur api.example.com uniquement. Le front ne reçoit jamais de Set-Cookie, le CDN fonctionne normalement, et les appels API authentifiés portent le cookie via credentials: 'include'. Cette séparation demande une configuration CORS propre, mais elle est documentée et stable.

Le cas Next.js : un middleware de session peut ruiner l’ISR

Next.js est un cas intéressant parce qu’il mélange pages statiques, pages rendues côté serveur et Incrémental Static Regeneration (ISR). Un middleware qui vérifie la session sur toutes les routes empêche la réponse d’être servie depuis le cache Edge. L’ISR continue de régénérer les pages, mais personne n’en profite : chaque requête traverse le middleware, qui récupère le cookie, appelle la base de données pour vérifier la session, et retourne une réponse marquée private, donc non cachable.

On a mesuré l’effet sur une fiche produit Next.js 14 avec ISR configuré sur 60 secondes. Sans middleware de session, le TTFB depuis le cache Edge était de 15 ms. En ajoutant un middleware qui lit le cookie session_token et le valide même sur cette fiche produit, le TTFB est passé à 340 ms. La page était toujours régénérée en arrière-plan, mais le CDN la considérait comme dynamique à cause du comportement du middleware.

La documentation Next.js recommande d’utiliser le matcher de middleware pour exclure les routes qui n’ont pas besoin d’authentification. Dans la pratique, on voit encore des configurations où matcher couvre tout le site « par sécurité ». Le résultat, c’est une application qui se comporte comme si elle n’avait aucun cache, avec un TTFB dégradé uniformément.

La solution n’est pas de supprimer le middleware, mais de le restreindre aux routes d’API et aux pages authentifiées. Pour un site e-commerce dont les fiches produit représentent 80 % du trafic, l’impact SEO d’une telle correction peut dépasser celui d’une optimisation d’images ou d’un lazy-loading. Pourtant les audits Core Web Vitals pointent rarement le cookie comme cause racine. La plupart des outils s’arrêtent au TTFB élevé sans remonter à l’en-tête qui l’explique.

Comment diagnostiquer en dix minutes montre en main

Ouvre ton terminal. Lance une requête curl sur ta page publique la plus visitée :

curl -I https://tonsite.com/

Regarde l’en-tête Set-Cookie présent dans la réponse. S’il apparaît sur une page qui n’a pas de formulaire de connexion, méfiance. Refais la même requête en simulant un visiteur qui a déjà un cookie :

curl -I -H "Cookie: session=test" https://tonsite.com/

Compare le X-Cache ou le CF-Cache-Status. Si la première réponse est HIT et la seconde MISS ou BYPASS, le cookie est en train de désactiver le cache.

Ensuite, mesure l’impact réel avec WebPageTest ou votre outil de monitoring favori. Lance deux tests sur la même URL : un sans cookie, un avec un cookie bidon. Compare les TTFB médians. Un écart supérieur à 100 ms confirme que le cache ne fonctionne pas pour les utilisateurs porteurs de session. Si votre audience est majoritairement connectée, l’impact est généralisé.

Les logs serveur apportent une confirmation supplémentaire. Une augmentation du nombre de requêtes vers l’origine après le déploiement d’un cookie de session est un signal clair. Certains CDN fournissent des métriques de « cache hit ratio » par type de contenu. Une chute de ce ratio sur les pages HTML coïncidant avec l’apparition du Set-Cookie valide le diagnostic sans ambiguïté.

💡 Conseil : ne vous arrêtez pas au cookie de session. Un simple cookie de tracking analytics configuré en cookie first-party peut produire le même effet s’il est émis sur le domaine principal. Vérifiez tous les Set-Cookie.

Ce que ça change concrètement sur les Core Web Vitals

Le TTFB est un sous-composant du LCP. Aujourd’hui, un site qui veut un LCP sous les 2,5 secondes a besoin d’un TTFB sous les 800 ms en mobile sur une connexion 4G. Retirer un cookie de session superflu fait souvent passer le TTFB de 600 ms à 150 ms. Ce gain de 450 ms est directement retranché du LCP. Aucune optimisation d’images ni aucun fetchpriority ne produira un tel effet avec aussi peu de code modifié.

L’impact sur l’INP est indirect, mais mesurable. Un TTFB plus bas signifie que le thread principal commence à parser le HTML plus tôt. Les scripts se chargent plus tôt. L’interactivité est repoussée moins loin. On a vu un gain de 80 ms sur l’INP p95 d’une landing page simplement en supprimant le Set-Cookie qui empêchait le cache Edge de fonctionner. Le lien de causalité n’est pas immédiat, mais il est réel.

L’effet sur le crawl est plus difficile à quantifier, mais le raisonnement est simple. Googlebot crawle avec un budget. S’il rencontre des réponses dynamiques plus lentes qu’attendu, il peut ralentir son rythme de crawl ou réduire la profondeur. Un site qui sert ses pages publiques sans cookie renvoie un signal de performance cohérent. Ce n’est pas un facteur de classement direct, mais c’est un facteur de crawl efficiency, ce qui est parfois plus précieux.

La correction est souvent un diff Git de cinq lignes dans un fichier de configuration. Le ratio effort / gain en fait l’un des leviers les plus sous-cotés de l’optimisation technique. La raison pour laquelle on en parle si peu tient au fait que la plupart des outils de performance mesurent le TTFB sans identifier la cause. C’est en regardant les en-têtes de réponse qu’on trouve l’explication, et les en-têtes, personne ne les lit.

Questions fréquentes

Puis-je garder un cookie de session sur les pages publiques si j’utilise un cache serveur comme Varnish ?

Varnish peut être configuré pour ignorer le cookie de session et servir une version en cache. Mais si le cookie est placé sur toutes les pages publiques, il faut s’assurer qu’aucun contenu personnalisé ne fuite d’un utilisateur à l’autre. La configuration est fragile et les erreurs ont des conséquences RGPD. Il est plus robuste de ne pas poser le cookie du tout sur ces pages.

Un cookie httpOnly sans Secure peut-il empirer le TTFB ?

L’absence de l’attribut Secure n’affecte pas le cache, mais elle empêche le navigateur d’envoyer le cookie sur les requêtes HTTPS futures dans certaines conditions modernes (SameSite par défaut). Cela peut provoquer des boucles de redirection coûteuses si votre application redirige vers la connexion. L’impact sur le TTFB est indirect, mais réel.

Comment suivre un utilisateur anonyme sur des pages publiques sans cookie ?

Les solutions côté serveur sans cookie, comme les empreintes de navigateur, sont à éviter pour des raisons de vie privée. Une meilleure approche consiste à déplacer le suivi vers des événements client-side transmis à un endpoint dédié, sans cookie sur le domaine principal. Cela préserve le cache et limite la collecte aux interactions réelles.

Articles similaires

Julien Morel

Julien Morel

Ancien dev front React passé SEO technique après une migration e-commerce qui a fait perdre 60% du trafic organique à son employeur en une nuit (fichier robots.txt oublié en staging). Depuis, il écrit pour que ça n'arrive à personne d'autre et teste sur ses propres side-projects avant de publier quoi que ce soit.

Cet article est publie a titre informatif. Faites vos propres recherches avant toute decision.