On a vu un site média perdre 12 points de LCP dans la Search Console en trois jours. Pas à cause d’une migration, pas à cause d’une mise à jour du CMS. Juste parce que la régie avait poussé un nouveau wrapper pour les formats mobile, soi-disant « plus riche ». Derrière ce wrapper, trois appels supplémentaires vers des ad servers, un polyfill chargé alors qu’il ne servait à rien sous iOS, et une animation en JavaScript qui maintenait le thread principal occupé bien après le chargement du contenu.
Tu peux bosser ton lazy loading, réduire ton bundle CSS, te battre avec ton hébergeur pour gratter 200 ms de TTFB. Si ta page sert une bannière 320x50 non maîtrisée, ces efforts partent en fumée. Et c’est encore pire sur mobile, où le CPU est une ressource rare et où la latence réseau transforme chaque appel à un ad server en loterie.
La régie publicitaire est une black box
La plupart des éditeurs intègrent un tag fourni par leur régie, souvent un script avec un src pointant vers un domaine qu’ils ne contrôlent pas, parfois encapsulé dans un iframe s’ils ont de la chance. Ils n’ont aucune visibilité sur ce que fait ce script. Combien d’appels réseau déclenche-t-il ? Quels polyfills injecte-t-il dans le DOM ? À quel moment bloque-t-il le parsing HTML ?
La réponse est presque toujours la même : trop d’appels, trop de poids, trop tard. Le pire cas qu’on ait rencontré, c’était une régie qui, pour une simple bannière 300x250, déclenchait une enchère en cascade chez quatre ad servers successifs, avec un timeout de 2 secondes à chaque étage. Résultat : un LCP stable à 6,4 secondes sur mobile, dont 4,2 secondes imputables au seul pipeline publicitaire. Le contenu rédactionnel, lui, était prêt en 800 ms.
La première chose à faire, c’est cartographier précisément la chaîne de dépendances. Ouvre le panneau Network de Chrome DevTools, filtre par le domaine de la régie, bascule en mode « Slow 3G » et recharge la page. Tu verras apparaître des requêtes que tu ne soupçonnais pas. C’est le point de départ pour négocier.
Décortiquer l’impact d’une bannière 320x50 sur les métriques terrain
Quand on parle de LCP et d’INP dans le cadre des publicités mobiles, on a tendance à se focaliser sur la taille du fichier image. C’est une erreur. Le vrai problème, c’est le nombre de ressources bloquantes que le tag publicitaire injecte avant même que la créa ne s’affiche.
Prenons un format classique : le bandeau 320x50 en haut de page. Voici ce qu’on a mesuré sur un site e-commerce équipé d’une régie premium et d’un ad server maison :
- Le script wrapper (35 ko) est chargé de manière synchrone dans le
<head>. Il bloque le parsing HTML pendant 180 ms sur un Moto G4. - Ce script appelle l’ad server principal, qui répond en 400 ms avec un XML contenant l’URL de la créa et un script de tracking.
- Le script de tracking (12 ko) est évalué par le navigateur avant que l’image de la créa ne commence à se charger.
- L’image elle-même (45 ko) est servie depuis un CDN optimisé, mais elle n’est découverte qu’après l’exécution du tracking.
Le LCP de la page, qui correspond au titre de l’article situé juste sous la bannière, survient 1,8 seconde après le début du chargement. Sans la bannière, ce même LCP est mesuré à 600 ms. La différence, ce n’est pas le poids de l’image publicitaire, c’est le temps perdu dans les scripts et les allers-retours réseau.
Sur l’INP, le constat est plus vicieux. La bannière elle-même n’est pas interactive. Mais les scripts de tracking et de viewability monitoring installent des écouteurs d’événements sur le document, souvent sans passive: true. Résultat : chaque scroll, chaque toucher sur l’écran déclenche une vérification de visibilité. On a mesuré des INP à 280 ms sur des sessions mobiles, là où la page sans pub tournait à 90 ms.
Interstitiels : le faux coupable, le vrai responsable
Les interstitiels plein écran ont mauvaise presse. Google les pénalise dans ses critères de classement mobile, les utilisateurs les détestent. Pourtant, si on regarde les chiffres bruts du laboratoire Lighthouse, un interstitiel statique affiché après 3 secondes n’est pas forcément ce qui plombe les Core Web Vitals. Le vrai responsable, c’est le code qui décide quand et comment l’interstitiel s’affiche.
La plupart des systèmes d’interstitiel mobile fonctionnent avec un timer et une vérification de l’avancement du scroll. Le script scrute la position de la fenêtre toutes les 100 ms, parfois en utilisant getBoundingClientRect sur plusieurs éléments du DOM pour déterminer si le visiteur a lu 50 % de l’article. Ce polling continu, couplé au chargement asynchrone de la créa publicitaire, maintient le thread principal occupé bien au-delà du raisonnable.
On a déplacé cette logique côté serveur, avec un déclenchement basé sur la profondeur de scroll mesurée via l’API Intersection Observer et un simple seuil. Plus de polling. Le script interstitiel ne s’injecte qu’une fois le seuil franchi, et la créa est préchargée en fetchpriority="low" en amont. L’INP est revenu sous 100 ms, le taux de rebond n’a pas bougé, et le revenu publicitaire non plus.
⚠️ Attention : un préchargement en
fetchpriority="low"peut retarder la disponibilité de la créa si la file réseau est saturée. À tester sur un échantillon de trafic mobile avant de généraliser.
Fetch priority : le levier sous-exploité pour les ressources pubs
Sans indication, le navigateur traite le script de l’ad server comme aussi critique que ta feuille de style principale. L’attribut fetchpriority (disponible sur <link>, <img> et <script>) casse cette égalité. Sur un site qu’on a audité, passer le wrapper régie en fetchpriority="low" et garder fetchpriority="high" sur l’image LCP a fait gagner 0,9 seconde sur mobile, sans toucher au volume d’impressions. Encore faut-il contrôler le balisage : si la régie te fournit un JavaScript opaque, retour à la table de négo.
Négocier avec la régie : ce qui se joue dans le contrat d’insertion
La régie publicitaire vend des audiences. Elle ne mesure pas tes Core Web Vitals. Elle mesure le taux de clic, le viewability rate, le CPM. Son indicateur de performance, c’est le revenu généré. Le tien, c’est le trafic organique et l’expérience utilisateur. Ces deux métriques ne sont pas naturellement alignées.
Ce qui a marché pour plusieurs sites qu’on accompagne, c’est d’introduire une clause de performance technique dans le contrat d’insertion. Pas un SLA vague, mais un engagement mesurable : par exemple, le temps d’exécution total des scripts publicitaires ne doit pas dépasser 500 ms sur un Moto G4, mesuré via l’API Long Tasks en condition de laboratoire. Si cette limite est franchie pendant plus de 10 % des sessions mensuelles, l’éditeur peut exiger une modification du wrapper publicitaire sans pénalité financière.
Ça paraît agressif. Pourtant, les régies sérieuses acceptent ce cadre. Elles savent qu’un site rapide génère plus de pages vues, donc plus d’impressions, donc plus de revenus pour elles. La difficulté, c’est d’obtenir les moyens techniques de contrôler ce qu’elles injectent. Le « tag sandbox léger » se négocie noir sur blanc dans le contrat : pas de polyfills inutiles, pas d’animations JavaScript, pas d’appels en cascade au-delà de deux ad servers, script auditable avant mise en prod. Quand la régie répond « notre stack ne le permet pas », il en existe d’autres, et certaines commencent à communiquer sur leur compatibilité Core Web Vitals.
Quand la pub casse l’INP : l’overlay qui bloque le scroll
Le cas d’école qu’on a rencontré l’an dernier : un site lifestyle avec un format publicitaire « habillage mobile » qui ajoutait un overlay semi-transparent sur les bords gauche et droit de l’écran, redirigeant vers l’annonceur au clic. Visuellement discret. Techniquement dévastateur.
L’overlay était constitué de deux <div> positionnées en fixed, chacune dotée d’un écouteur click et d’un script de tracking qui vérifiait en permanence les coordonnées du toucher. Ce script tournait dans la boucle d’animation du navigateur via requestAnimationFrame, même quand l’utilisateur lisait l’article sans toucher les bords. Résultat : chaque frame mobilisait 12 ms de traitement JavaScript. Sur un écran à 60 fps, 12 ms par frame, c’est 72 % du budget de 16 ms par frame consommés par la pub, avant même que le contenu n’ait une chance de s’afficher.
On a remplacé l’écouteur continu par une délégation d’événement unique sur le body, avec une vérification de la cible du clic uniquement au moment de l’interaction. Plus de requestAnimationFrame. Le script de tracking a été déplacé dans un setTimeout de 50 ms pour ne pas bloquer le rendu. L’INP est passé de 340 ms à 110 ms. Le taux d’interaction avec la pub n’a pas bougé.
Si tu peux auditer ce code de tracking, tu peux le réparer. Sinon, c’est un sujet contractuel, pas technique.
Le piège du viewport mobile et du lazy loading mal calibré
Beaucoup de sites mettent en place un lazy loading sur les bannières situées sous la ligne de flottaison. L’intention est bonne : ne pas charger une pub qui ne sera jamais vue. L’exécution, souvent ratée.
Sur mobile, la hauteur du viewport est variable, et le seuil de déclenchement du lazy loading est souvent calculé en pixels absolus. Résultat : une bannière placée en milieu d’article se déclenche 300 px avant l’entrée dans le viewport, pile au moment où l’utilisateur scrolle vite. Le script publicitaire se lance, le parsing bloque, l’utilisateur voit un blanc de 800 ms, puis la bannière apparaît, mais il est déjà passé à la suite.
Ce qui fonctionne mieux, c’est d’utiliser une marge de déclenchement dynamique, basée sur la vitesse de scroll et la puissance estimée du device. L’API navigator.hardwareConcurrency et la mesure du temps de réponse des dernières interactions permettent de calibrer un seuil qui évite ce « jank publicitaire ». Sur un device lent, on déclenche le chargement plus tôt, mais avec une priorité basse, pour que le navigateur ait le temps de le traiter sans bloquer le scroll. Sur un device rapide, on peut se permettre de le déclencher plus près du viewport.
Ce type de réglage demande un peu de développement, mais une fois en place, il profite à tous les formats publicitaires du site. On a mis ça en place via un petit module JavaScript de 2 ko qui s’intègre à l’Intersection Observer natif. Le gain sur l’INP mobile a été immédiat, sans impact sur le viewability rate.
Questions fréquentes
Est-ce que Google pénalise les sites qui utilisent des interstitiels publicitaires sur mobile ?
Google ne pénalise pas tous les interstitiels. La règle documentée cible les interstitiels intrusifs qui rendent le contenu moins accessible, surtout immédiatement après l’arrivée sur la page ou pendant la navigation. Un interstitiel affiché après un temps de lecture significatif, facile à fermer et laissant le contenu principal visible n’est pas sanctionné mécaniquement. Ce qui plombe le classement, c’est surtout la dégradation des Core Web Vitals qu’il provoque, et cette dégradation, Google la mesure via les données de terrain Chrome.
Faut-il bloquer purement les publicités sur les pages à fort enjeu SEO comme les articles piliers ?
Bloquer les publicités, c’est renoncer à la monétisation, donc rarement une option durable pour un média. La bonne stratégie, c’est de leur appliquer un traitement différencié : sur une page pilier qui doit performer en SEO, on réduit le nombre de formats à un seul, on exige un tag audité et optimisé, et on met en place un monitoring strict des métriques de champ. Le manque à gagner est souvent compensé par une meilleure rétention et un trafic organique plus élevé sur le long terme.
L’impact des pubs sur l’INP est-il le même sur iOS et Android ?
Non. Sous iOS, tous les navigateurs utilisent WebKit, qui gère la priorité des timers et des écouteurs d’événements de manière légèrement différente. On observe souvent un INP publicitaire plus bas sur iPhone récent que sur un Android milieu de gamme. L’essentiel du trafic mobile sensible aux régressions INP se trouve donc sur les devices Android modestes. C’est sur cette population qu’il faut concentrer les tests de performance, pas sur le dernier iPhone Pro en Wi-Fi.