TTFB : qu'est-ce que le Time to First Byte et comment l'optimiser ?
TTFB trop élevé ? Comprenez ce que mesure le Time to First Byte, les seuils Google, les causes fréquentes et les leviers concrets pour l'améliorer.
Le TTFB (Time to First Byte) mesure le délai entre la requête HTTP et le premier octet de réponse reçu par le navigateur. Google cible < 800 ms en données terrain (P75). Les causes les plus fréquentes : absence de cache de page, dilution du cache par des query parameters, requêtes BDD non optimisées, absence de CDN. Côté serveur, un cache de page complet descend à 20-50 ms ; un CDN bien configuré étend ce gain à l'ensemble des régions. Sur un site e-commerce SFCC, la normalisation des clés de cache a réduit la dilution de 80 % et fait passer le Server Response de 0,74 s à 0,63 s (-15 %) en field data.
TTFB : définition et seuils Google
Le TTFB mesure le temps écoulé entre le moment où le navigateur envoie une requête HTTP et celui où il reçoit le premier octet de la réponse du serveur. Ce délai comprend trois composantes : la latence réseau (aller-retour DNS + TCP + TLS), le temps de traitement serveur (exécution applicative, requêtes BDD, rendu de la réponse), et la mise en file d'attente éventuelle côté serveur.
Google définit trois niveaux de performance pour le TTFB :
| Niveau | Seuil | Statut |
|---|---|---|
| Bon | < 800 ms | Vert |
| À améliorer | 800 ms à 1 800 ms | Orange |
| Mauvais | > 1 800 ms | Rouge |
Ces seuils s'appliquent aux données terrain au 75e percentile (P75) : 75 % des visites réelles doivent passer sous 800 ms pour être considérées bonnes.
La place du TTFB dans le waterfall réseau
Le TTFB est la première phase du chargement d'une page. Dans le waterfall de navigation, il précède tout le reste : le parser HTML ne peut pas commencer avant que le premier octet soit arrivé, les ressources critiques (CSS, polices, image LCP) ne peuvent pas être découvertes avant le parsing, et le LCP ne peut pas se déclencher avant que l'élément visuel soit rendu. Un TTFB de 800 ms consomme 800 ms du budget LCP avant même que le navigateur ait commencé à travailler. Si le LCP cible est 2,5 s, un TTFB à 1,2 s ne laisse que 1,3 s pour tout le reste.
Comment mesurer le TTFB
Chrome DevTools (diagnostic ponctuel)
Ouvrir DevTools (F12), onglet Network, cliquer sur la première requête HTML, puis consulter le panneau Timing. La ligne "Waiting for server response" est le temps de traitement serveur pur. Cas d'usage : identifier rapidement si le problème vient du réseau (DNS/TCP/TLS élevés) ou du serveur (Waiting élevé). Un "Waiting" de 900 ms avec un DNS/TCP/TLS normal indique un problème applicatif.
WebPageTest (benchmark contrôlé)
WebPageTest mesure le TTFB depuis des agents localisés dans des villes précises, sur des conditions réseau simulées (Moto G4, 4G). Cas d'usage : mesurer depuis "Paris, France" en profil mobile pour benchmarker un site e-commerce français, ou identifier un écart géographique (1,2 s depuis Paris, 3,8 s depuis Singapour) qui révèle un CDN absent ou mal configuré.
Google Search Console (données terrain P75)
La Search Console rapporte le TTFB via les données CrUX, agrégées sur 28 jours glissants au P75. Cas d'usage : connaître le TTFB réel de ses utilisateurs, tous réseaux et toutes localisations confondus. Un écart entre WebPageTest (bon) et GSC (mauvais) révèle souvent un CDN mal couvrant ou un serveur qui se dégrade sous la charge du trafic réel.
Les 5 causes principales d'un TTFB élevé
1. Absence de cache de page
C'est la cause la plus fréquente et la plus impactante. Sans cache, chaque requête déclenche l'intégralité de la chaîne applicative : routing, authentification, requêtes BDD, rendu du template, sérialisation de la réponse. Sur un CMS ou un e-commerce standard, cela représente 300 ms à 2 s selon la complexité. Avec un cache de page complet, la même réponse est servie depuis la mémoire en 5-50 ms.
2. Dilution du cache par des query parameters
Le cache est en place, mais le taux de cache hit est effondré. Cause : chaque combinaison de paramètres d'URL (?color=red&size=L&sort=price_asc) génère une clé de cache distincte. Sur un catalogue e-commerce avec 20 filtres de 5 valeurs chacun, cela représente des milliers de combinaisons, dont la plupart ne seront jamais réchauffées. Résultat : la majorité des requêtes tombe en cache miss et le TTFB reste élevé malgré le cache existant.
3. Requêtes BDD lentes ou non indexées
Une page produit qui charge 5 blocs de contenu dynamiques (recommandations, stock, avis, prix personnalisés, navigation facettée) peut déclencher 20 à 50 requêtes SQL. Sans index adapté sur les colonnes filtrées, chaque requête fait un full table scan. Sur un catalogue de 500 000 produits, une requête non indexée sur product_category_id peut prendre 800 ms à elle seule.
4. Absence de CDN ou CDN non configuré pour le caching
Même avec un cache serveur parfait, la latence réseau est incompressible. Entre un serveur en France et un utilisateur à Singapour, l'aller-retour réseau seul ajoute 150-200 ms. Avec 3-4 aller-retours pour DNS + TCP + TLS + requête, le TTFB mécanique atteint 600-800 ms avant même que le serveur traite quoi que ce soit. Un CDN avec edge caching élimine ce problème en servant la réponse depuis un noeud local.
5. Calculs lourds bloquants en synchrone
Certains traitements s'exécutent en synchrone dans le chemin critique : calcul de prix personnalisés, appels à des APIs tierces bloquants (traduction, personnalisation, recommandations en temps réel). Un appel API tiers avec un timeout de 2 s dans le chemin synchrone fixe le TTFB minimum à 2 s en cas de défaillance. La solution est la mise en cache de ces résultats ou leur déplacement en asynchrone.
Optimiser le TTFB côté serveur
Cache de page complet
Le cache de page complet (full-page cache) sérialise la réponse HTML finale et la stocke en mémoire (Redis, Memcached) ou sur disque. Les requêtes suivantes sur la même URL sont servies depuis le cache, sans toucher la BDD ni l'applicatif. Gain typique : de 800 ms-2 s sans cache à 20-80 ms avec cache Redis. Sur Laravel, Nginx FastCGI Cache ou Varnish, la mise en place est immédiate pour les pages publiques sans personnalisation.
// Laravel : cache de page simple avec Redis
Route::get('/produit/{slug}', function ($slug) {
return Cache::remember("page:produit:{$slug}", 3600, function () use ($slug) {
$produit = Product::with(['images', 'variants', 'category'])
->where('slug', $slug)->firstOrFail();
return view('produit', compact('produit'))->render();
});
});
Normalisation des clés de cache (anti-dilution)
L'objectif est de réduire le nombre de clés de cache distinctes en excluant les paramètres qui ne changent pas le contenu servi. Un filtre de couleur sélectionné en JavaScript ne modifie pas le HTML brut de la page ; seule la sélection UI côté client change.
// Construire une clé de cache normalisée : exclure les paramètres non structurants
function buildCacheKey(Request $request): string {
$structuralParams = ['page', 'category', 'brand']; // influencent le contenu
// Paramètres exclus : color, size, sort, utm_source, ref...
$params = $request->only($structuralParams);
ksort($params); // ordre alphabétique pour éviter les doublons
return 'page:' . $request->path() . ':' . md5(serialize($params));
}
Optimisation BDD
Deux actions à fort impact : l'indexation des colonnes de filtrage et la réduction du nombre de requêtes par page.
-- Index composite pour les listes produits filtrées par catégorie et prix
CREATE INDEX idx_products_category_price
ON products (category_id, price, status)
WHERE status = 'active'; -- index partiel : ignore les produits inactifs
Utiliser EXPLAIN ANALYZE (PostgreSQL) ou EXPLAIN (MySQL/MariaDB) pour identifier les full table scans avant d'indexer. Un full scan sur une table de 500 000 lignes coûte systématiquement plus de 200 ms.
PHP et SFCC : réduire le temps de traitement applicatif
Sur PHP natif, activer OPcache élimine la recompilation des scripts à chaque requête (gain de 60-80 % sur le temps d'exécution PHP). Sur SFCC, la mise en cache des pipelines via Business Manager permet de contrôler quelles routes utilisent le cache applicatif et avec quelle TTL. Les cartridges personnalisés avec des appels API synchrones dans le pipeline de rendu sont la cause n°1 des TTFB élevés côté SFCC.

Dilution de cache SFCC par query parameters.
Sur un site SFCC d'une maison de luxe (catalogue plusieurs milliers de références), le cache applicatif était en place mais le TTFB restait élevé. L'analyse a révélé que les paramètres color, size et sort généraient des clés de cache distinctes pour chaque combinaison d'URL, y compris des combinaisons jamais visitées. Le taux de cache hit était proche de zéro malgré un cache configuré en apparence. Action menée : normalisation des clés de cache SFCC (exclusion des paramètres non structurants du calcul de clé) et mise en place d'un cache applicatif avancé avec des TTL adaptées par type de page. Résultat en field data RUM : dilution du cache réduite de 80 %, Server Response passé de 0,74 s à 0,63 s (-15 %). La leçon : un cache mal configuré peut être presque aussi coûteux qu'un cache absent — et l'audit de la dilution doit précéder toute décision d'infrastructure.
Réduire le TTFB avec un CDN
Edge caching
Un CDN avec edge caching stocke la réponse HTML au plus près des utilisateurs. Quand un utilisateur à Tokyo charge une page, la réponse est servie depuis un noeud Tokyo, pas depuis un serveur à Paris : la latence réseau tombe de 150-200 ms à 5-20 ms. La condition pour que ça fonctionne : la réponse doit être cacheable (Cache-Control: public, max-age=3600). Une réponse avec Set-Cookie ou Cache-Control: private ne sera pas mise en cache edge et atteindra systématiquement l'origine.
# Nginx : headers pour activer l'edge caching CDN sur les pages produit
location ~* ^/produit/ {
add_header Cache-Control "public, max-age=3600, stale-while-revalidate=300";
add_header Vary "Accept-Language"; # varier par langue uniquement
proxy_hide_header Set-Cookie; # éviter que les cookies bloquent le cache CDN
proxy_pass http://backend;
}
Cloudflare et Akamai : configuration avancée
La normalisation des query parameters est aussi configurable directement au niveau du CDN. Les Cache Rules de Cloudflare permettent de définir précisément quels paramètres entrent dans la clé de cache edge : ignorer les paramètres de tri et de filtrage UI réduit drastiquement le nombre d'entrées distinctes, exactement comme la normalisation côté applicatif.
Sur les infrastructures à fort trafic, la configuration de Akamai offre un contrôle fin : SureRoute optimise le chemin réseau vers le serveur d'origine, Property Manager gère la clé de cache edge, et le Cache-Control Modification Behavior surcharge les headers de l'origine sans toucher au code applicatif. Un cache hit ratio inférieur à 85 % sur les pages produit est le premier signal d'une dilution ou d'un TTL trop court.
Early Hints HTTP 103
HTTP 103 Early Hints permet au serveur d'envoyer des directives Link: rel=preload avant que la réponse 200 complète soit prête. Le navigateur précharge les ressources critiques (CSS, polices, image LCP) pendant que le serveur génère encore la page. Sur un TTFB de 600 ms, Early Hints peut précharger le CSS critique et la police de marque en parallèle, réduisant le LCP de 200-400 ms sans toucher au TTFB lui-même. Nginx supporte HTTP 103 depuis la version 1.25.1 ; Cloudflare et Akamai le transmettent nativement depuis leurs edges sans configuration serveur.
Un cache hit ratio inférieur à 85 % mérite un audit web performance dédié pour distinguer dilution, TTL trop court et headers mal configurés. Si le TTFB n'est qu'un symptôme d'une performance serveur globalement fragile, l'optimisation des performances serveur couvre la priorisation des axes d'amélioration sur l'ensemble de la stack.
Sources
- Web Vitals — Time to First Byte (TTFB) — Google web.dev
- Optimize TTFB — Google web.dev
- HTTP 103 Early Hints — MDN Web Docs
- CrUX Dashboard — Chrome Developers