Google Tag Manager a été adopté pour une raison simple : reprendre le contrôle des scripts tiers. Un seul extrait de code dans la page, et le marketing pose, retire et conditionne ses balises sans passer par un déploiement. Quinze ans plus tard, ce conteneur est devenu le premier poste de dépense JavaScript du web, devant YouTube, devant les régies publicitaires, devant les bibliothèques hébergées par Google lui-même.
Un tag manager est un script qui charge d’autres scripts. Le fichier gtm.js embarque la configuration du conteneur, ses balises, ses déclencheurs et ses variables, puis évalue en continu ce qui doit se déclencher, sur le fil unique qui affiche la page et répond aux clics. Il est asynchrone, et c’est précisément ce qui entretient la croyance la plus répandue du marché : asynchrone, donc gratuit. Elle est fausse, et cet article le démontre chiffre par chiffre.
Trois choses sont établies ici : ce que coûte réellement un conteneur, pourquoi ce coût reste invisible aux méthodes de mesure habituelles, et comment le réduire sans perdre une seule donnée. Le lecteur n’a pas besoin d’être développeur, il a besoin d’un accès à son conteneur, ou de savoir à qui le demander. Combien de millisecondes votre conteneur coûte-t-il à chaque visiteur, et combien de ses balises servent encore à quelqu’un ?
Google Tag Manager ralentit-il vraiment un site ?
Oui, et davantage que la plupart des outils qu’il sert à installer. Dans le jeu de données third-party-web consulté le 17 septembre 2026, Google Tag Manager affiche 1 066 millisecondes d’impact moyen sur plus de 15 millions de pages, contre 108 millisecondes pour Google Analytics. Le conteneur coûte donc environ dix fois l’outil de mesure qu’il déploie.
Ce que dit le classement mondial des scripts tiers
Le projet third-party-web de Patrick Hulce agrège chaque mois les audits Lighthouse de l’HTTP Archive sur environ quatre millions de sites mobiles, et attribue à chaque tiers le temps d’exécution de ses scripts sur le thread principal. Au classement par impact total, Google Tag Manager est premier avec plus de 16 millions de secondes cumulées, devant le CDN de Google et YouTube. Rapporté à la page, 1 066 ms d’exécution en moyenne, sur 15 022 156 pages observées. Le tableau ci-dessous situe les principaux tag managers du marché sur la même échelle.
| Tag manager | Impact moyen | Pages observées |
|---|---|---|
| TagCommander (Commanders Act) | 220 ms | 2 600 |
| Tealium | 283 ms | 134 480 |
| Ensighten | 558 ms | 6 750 |
| Adobe Tag Manager | 687 ms | 105 342 |
| Google Tag Manager | 1 066 ms | 15 022 156 |
Deux nuances s’imposent avant d’en tirer une conclusion. L’indicateur mesure ce que le processeur exécute, pas ce que le visiteur attend : il ne dit rien d’un script qui bloque la découverte d’une image ou qui retarde une décision. Et la ligne Google Tag Manager agrège tout ce qui est servi depuis googletagmanager.com, c’est-à-dire gtm.js et gtag.js, le conteneur et la balise Google utilisée sans conteneur. La valeur reflète l’écosystème, pas le seul outil.
Un domaine présent sur un site sur deux
Le Web Almanac 2025 place googletagmanager.com parmi les dix domaines tiers les plus présents du web, dans un top 10 dominé par les services Google, et relève que plus de 90 % des pages embarquent au moins un tiers. La population concernée par ce qui suit est donc la quasi-totalité des sites qui font du marketing. La même précision que plus haut vaut ici : la présence du domaine ne dit pas la part de marché de GTM, puisque la balise Google seule en vient aussi.
Le contexte, 79 requêtes tierces par page
La même édition du Web Almanac donne une médiane de 79 requêtes tierces par page mobile, 83 sur desktop, et 129 sur les mille premiers sites, en hausse d’une année sur l’autre. Un conteneur n’est donc jamais seul : il arrive au milieu de plusieurs dizaines de requêtes tierces qu’il a, pour la plupart, lui-même déclenchées.
Elle porte aussi une remarque de méthode qui vaut de l’or : les robots de l’HTTP Archive ne défilent pas et n’interagissent pas avec les pages, donc tout ce qui se déclenche au défilement, au clic ou à l’intention de sortie est sous-représenté. Les statistiques publiques sur les tiers sont un plancher, jamais un plafond, et un conteneur bien garni en déclencheurs d’interaction coûte plus que ce que ces chiffres montrent.
Pourquoi le coût d’un conteneur est invisible
Pourquoi un script asynchrone ralentit-il quand même la page ? Parce que async protège le téléchargement, pas l’exécution. Le fichier n’empêche plus l’analyse du document, mais son code s’exécute bel et bien sur le thread unique qui affiche la page et répond aux clics, à un moment imprévisible. Google Tag Manager est asynchrone partout, et reste premier au classement mondial du temps d’exécution.
Async est un faux ami
Le snippet officiel, tel qu’il est collé sur des millions de sites, tient en cinq lignes que presque personne ne lit. Le voici commenté, pour montrer que l’attribut async porte sur le téléchargement de gtm.js et sur rien d’autre, et que le fichier téléchargé va lui-même créer d’autres balises script que le navigateur ne pouvait pas connaître :
<!-- Google Tag Manager : le snippet officiel, tel quel -->
<script>(function(w,d,s,l,i){
w[l]=w[l]||[]; // 1. cree window.dataLayer s'il n'existe pas
w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'}); // 2. premier evenement
var f=d.getElementsByTagName(s)[0], // 3. premier <script> de la page
j=d.createElement(s), // 4. une nouvelle balise <script>
dl=l!='dataLayer'?'&l='+l:'';
j.async=true; // 5. async : le TELECHARGEMENT ne bloque pas le parseur
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f); // 6. injection avant le premier script
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
// Ce que gtm.js fait ensuite, et que le snippet ne montre pas :
// - il evalue tous les declencheurs du conteneur, sur le thread principal ;
// - il cree a son tour des balises <script> (gtag/js, pixels, outils) ;
// - chacune est decouverte par le navigateur seulement a ce moment-la.
L’attribut protège donc la bande passante et le parseur HTML, ce qui est bon pour le LCP. Il ne protège pas le thread principal, qui exécute gtm.js dès son arrivée, puis chaque balise qu’il injecte, entre deux tâches de rendu. C’est l’exécution qui coûte, pas le transfert, et un attribut de chargement n’a aucune prise sur elle. Notre guide sur le coût réel d’un script tiers détaille ce mécanisme, qui vaut ici pour le conteneur et pour chacune de ses balises.
Une cascade que le navigateur ne peut pas anticiper
Le chemin réel d’un premier hit de mesure passe par cinq étages : le HTML, puis le snippet inline, puis gtm.js, puis le script de l’outil de mesure, puis le point de collecte. Chaque étage est créé par le précédent en JavaScript, et aucun n’est découvrable par le scanner de préchargement du navigateur, qui ne lit que le HTML. Trois allers-retours réseau sont ainsi sérialisés avant la première donnée, là où une balise écrite en dur en aurait coûté un. Le schéma suivant matérialise ce que le navigateur peut anticiper, et où cela s’arrête.
Le cache ne vous sauve pas
Un lecteur attentif objectera que gtm.js est en cache dès la deuxième page. C’est vrai, et cela n’économise qu’un téléchargement, jamais une exécution. Le fichier est décompressé, analysé, compilé et exécuté à chaque page, à chaque visite, cache ou pas.
La bonne unité pour en juger n’est pas le poids transféré mais le poids décompressé, celui que le processeur doit lire : sur les conteneurs que nous auditons, le rapport entre les deux est couramment de un à trois, un conteneur de production courant représentant plusieurs centaines de kilooctets de JavaScript à analyser. Le schéma plus bas illustre cet ordre de grandeur.
Google donnait lui-même des repères dans ses bonnes pratiques pour les tag managers, mises à jour en août 2022 : la bibliothèque seule pèse environ 33 Ko compressés, le conteneur médian environ 50 Ko, et la taille est plafonnée à 300 Ko avec un avertissement à 70 % de la limite. Un conteneur qui approche du plafond n’est pas un conteneur riche, c’est un conteneur qui n’a jamais été nettoyé.
Ce qui se passe à chaque dataLayer.push()
La même page de web.dev porte une phrase que peu de lecteurs relèvent : mettre à jour la couche de données amène Google Tag Manager à réévaluer toutes les variables du conteneur et potentiellement à déclencher des balises, ce qui implique de l’exécution JavaScript. Chaque dataLayer.push() est donc une réévaluation complète, sur le thread principal. Sur une page à filtres, à carrousel ou à panier, cela se produit à chaque interaction du visiteur, exactement pendant la fenêtre de mesure de l’INP :
// Un push ordinaire, au clic sur "Ajouter au panier"
document.querySelector('#add-to-cart').addEventListener('click', function () {
window.dataLayer.push({
event: 'add_to_cart',
ecommerce: { items: [{ item_id: 'SKU-1234', price: 49.9, quantity: 1 }] }
});
// Ce que ce push declenche, avant que le visiteur voie son panier changer :
// - reevaluation de TOUTES les variables du conteneur ;
// - test de TOUS les declencheurs (clic, timer, visibilite, custom event) ;
// - execution de chaque balise dont la condition est vraie ;
// - le tout sur le thread principal, dans la fenetre mesuree par l'INP.
});
Google précise dans le même document que les déclencheurs sont du code JavaScript qui augmente la taille et le coût d’exécution du conteneur, que plusieurs déclencheurs de clic ou de minuteur peuvent en accroître fortement la charge, et que les variables sont évaluées en continu. Un conteneur n’a pas un coût, il a un coût par interaction, et c’est ce qui le rend si difficile à voir dans un outil qui ne fait que charger la page.
Quel est l’effet sur les Core Web Vitals ?
L’INP en premier, le LCP par contention, et rien de tout cela dans un rapport Lighthouse. L’équipe Chrome écrit sur web.dev avoir observé une corrélation entre la taille des tag managers et de moins bons scores d’INP, et le Web Almanac 2025 relève 69 % de bon INP sur les pages secondaires mobiles contre 80 % sur les pages d’accueil, écart qu’il attribue aux widgets et scripts tiers qui s’activent plus loin dans le parcours.
L’INP, la métrique que le conteneur dégrade en premier
La phrase de web.dev mérite d’être lue dans son contexte : l’Interaction to Next Paint est sensible à la contention du processeur sur le thread principal, et l’équipe Chrome a vu une corrélation entre la taille des tag managers et de moins bons scores d’INP. Détail qui signale l’ancienneté du diagnostic, cette page date de 2022, soit deux ans avant que l’INP ne devienne un Core Web Vital en mars 2024.
Le lien entre conteneur et réactivité était donc documenté avant même que la métrique ne compte pour le référencement, et il n’a fait que se confirmer depuis. Notre guide sur l’INP et comment l’optimiser explique pourquoi une seule interaction lente suffit à dégrader la note d’une page.
Pourquoi le problème s’aggrave sur les pages profondes
Le chapitre Performance du Web Almanac 2025 décrit un basculement : les pages d’accueil mobiles atteignent 80 % de bon INP, en progression de sept points, quand les pages secondaires reculent à 69 %, alors que les deux étaient à égalité l’année précédente.
Les auteurs y voient l’effet d’un travail d’optimisation concentré sur les pages d’atterrissage, et d’une accumulation de JavaScript tiers et d’analytics sur les pages plus profondes, qui portent aussi les interactions complexes, filtres, carrousels et validation de formulaires. La conséquence opérationnelle est directe : auditer sa page d’accueil ne dit rien de son tunnel, et c’est dans le tunnel que le conteneur déclenche le plus.
Et le LCP ?
Le conteneur ne dégrade pas le LCP par son poids, il le dégrade par contention. Pendant qu’il exécute gtm.js puis ses balises, le thread principal n’est pas disponible pour décoder et peindre l’image principale, et un snippet placé tout en haut du <head>, comme Google le recommande, s’exécute avant tout le reste. Notre guide sur le LCP et comment l’optimiser détaille la sous-partie de la métrique concernée, le délai de rendu, celle sur laquelle ni la compression ni le CDN n’ont de prise.
Ce que Lighthouse ne verra pas
Un audit de laboratoire ne produit pas d’INP, faute d’interactions. Le coût d’un conteneur sur la réactivité est donc structurellement invisible à l’outil que tout le monde utilise pour juger, qui n’en capte qu’une ombre à travers le Total Blocking Time du chargement. Notre comparatif PageSpeed Insights vs. Lighthouse rappelle en outre qu’en dessous de cinq points d’écart entre deux audits, on observe du bruit de mesure : retirer une balise et voir le score bouger de deux points ne prouve rien. Seul le terrain juge un conteneur, et le terrain, sur ce sujet, dit ce que nos audits confirment.
Ce que l’on trouve vraiment dans les conteneurs que nous auditons
Les constats qui suivent viennent de nos audits et de nos interventions, sur des sites de secteurs variés, anonymisés par typologie. Ils ont un point commun : aucun ne relève d’un défaut de l’outil, tous relèvent de l’absence de gouvernance du conteneur, et chacun est reproductible sur votre site en quelques minutes dans l’onglet Réseau des DevTools.
Deux ou trois conteneurs sur le même site
Un conteneur pour l’entreprise, un pour l’agence web, un pour le prestataire SEO. Chacun charge sa propre instance de gtm.js, avec sa propre cascade et sa propre réévaluation à chaque push. Sur un site e-commerce de mobilier et de décoration, Google Tag Manager était chargé trois à quatre fois sur la même page, et ressortait dans l’audit comme très fortement générateur de Blocking Time, traduit en tâches longues.
La recommandation a été de ne conserver qu’un seul conteneur, chargé d’appeler tous les scripts tiers, et de donner aux prestataires un accès à ce conteneur plutôt qu’un conteneur à eux.
Le cas le plus fréquent de doublon est plus discret : un conteneur GTM et, à côté, une balise Google installée en dur pour Google Ads ou pour une seconde propriété Analytics. La balise Google sait pourtant envoyer les mêmes données vers plusieurs destinations depuis une seule configuration, et la documentation de routage de gtag.js montre comment regrouper Ads, Analytics et Floodlight dans le même bloc. Une balise, plusieurs identifiants, et une seule exécution :
<!-- AVANT : deux balises Google chargees separement, deux executions -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=AW-YYYYYYY"></script>
<!-- APRES : une seule balise, plusieurs destinations -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){ dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'G-XXXXXXX'); // Google Analytics 4
gtag('config', 'AW-YYYYYYY'); // Google Ads, meme bibliotheque, aucun script de plus
// Dans l'interface, la meme chose se fait par "Google tag > Destinations > + Destination".
</script>
Le conteneur qui s’exécute avant l’image principale
Le constat le plus démonstratif vient d’un site e-commerce de cuisines. Tous les scripts tiers y étaient injectés depuis le bundle JavaScript principal, par un eval, ce qui les forçait en asynchrone : le téléchargement passait en arrière-plan, mais l’exécution restait bloquante et survenait avant même l’élément de LCP. Le rapport d’audit notait que cette approche est particulièrement problématique pour un tag manager, puisqu’il est à son tour responsable du chargement de l’intégralité des pixels de suivi, lesquels ne devraient s’exécuter qu’une fois la page rendue. C’est l’illustration exacte du faux ami de la partie précédente, observée en production.
Le tiers de tags qui ne sert plus à personne
Sur un site de plus de trois ans, une part significative des scripts tiers n’intéresse plus aucun service. Le consultant britannique Andy Davies documente, dans son article sur la réduction de l’impact des tags tiers, le cas d’une compagnie aérienne européenne dont l’audit a révélé que les abonnements d’environ un tiers des tags avaient expiré, sans que personne ne sache qui utilisait certains des autres. Il précise un détail qui complique le nettoyage : à l’expiration, certains fournisseurs renvoient une erreur, d’autres un script vide, mais beaucoup continuent de servir leur script complet.
Le même article porte l’argument commercial le plus fort de ce sujet. Chez un distributeur de mode britannique, un seul tag tiers ralentissait les visiteurs sur Android d’environ quatre secondes ; sa désactivation pour ce segment a produit 26 % de revenu supplémentaire sur ces visiteurs, et le site a poursuivi jusqu’à ramener son temps de chargement médian sur Android de plus de quatorze secondes à moins de six. Andy Davies en tire une règle de gouvernance qui vaut aussi pour les préconnexions que l’on empile dans le <head>.
Tous les domaines n’ont pas besoin d’une préconnexion, et si vous ressentez le besoin de préconnecter de nombreux domaines, c’est probablement que vous utilisez trop de tags.
Andy Davies, consultant en web performance, dans son article Reducing the Site-Speed Impact of Third-Party Tags, publié le 2 octobre 2020
Les campagnes terminées qui tournent encore
Un script d’A/B testing actif sans test en cours, un pixel publicitaire installé le temps d’une campagne close depuis des mois, un outil de heatmap posé pour une refonte livrée l’an dernier. Ces coûts survivent aux projets qui les ont justifiés, faute de date de retrait inscrite quelque part. Le conteneur rend leur pose facile et leur retrait improbable, parce que retirer un tag n’est jamais le problème de personne. La notion de date de péremption par balise, reprise dans la méthode plus loin, est la seule parade que nous ayons vue fonctionner durablement.
Le bandeau cookies chargé par le conteneur
Faut-il charger son bandeau de consentement via Google Tag Manager ? Non, et Google le déconseille explicitement. Les bonnes pratiques de web.dev pour les bandeaux cookies demandent de placer le script directement dans le HTML du document principal, parce qu’un chargement par tag manager le dissimule à l’analyseur anticipé du navigateur et l’empêche de se charger avant l’exécution du JavaScript. Le bandeau arrive donc plus tard, et tout ce qu’il conditionne arrive plus tard encore.
La page des bonnes pratiques pour les tag managers ajoute que certains utilisateurs bloquent les tag managers, et qu’un bandeau chargé par ce canal peut ne jamais s’afficher pour eux.
La double faute observée en audit va plus loin : le bandeau est chargé par le conteneur, et les scripts qu’il est censé retenir se chargent quand même avant tout choix du visiteur, parce que leurs déclencheurs ne sont pas conditionnés au consentement. Le site paie alors le coût du bandeau et celui des scripts, sans remplir la fonction pour laquelle le dispositif a été installé. Notre guide pour bien choisir sa CMP détaille cette articulation ; ce qui suit est le point de doctrine qui la complète.
La CMP, seule balise qu’il ne faut jamais déprioriser
Tout le monde écrit qu’il faut différer les tiers. Presque personne n’explique lesquels ne doivent jamais l’être. La CMP conditionne à la fois la validité de la mesure et l’expérience du visiteur : tant qu’elle n’est pas là, rien ne peut légalement se déclencher, et le bandeau qui surgit tard décale la page. Elle doit donc arriver le plus tôt possible, à l’inverse de tout le reste du conteneur.
Sur un site média, deux préconnexions ont été délibérément réservées à la CMP et aux régies pour cette raison ; sur un site B2B industriel, la CMP a été explicitement exclue de la liste des scripts reportés à la première interaction.
Le cas inverse existe aussi, et il est plus fréquent qu’on ne le croit. Dans un conteneur audité, la CMP était chargée en dernier par Google Tag Manager, après les outils de mesure et les pixels, ce qui imposait de la reprioriser dans le conteneur avant toute autre optimisation. L’ordre des balises dans un conteneur n’est pas neutre, et la première à charger devrait être celle qui autorise les autres.
Le conteneur qui compte des pages jamais vues
Avec les Speculation Rules, une page préparée en arrière-plan par le navigateur est réellement chargée et son JavaScript réellement exécuté, conteneur compris. Google Analytics 4 attend l’affichage effectif avant de compter la visite, mais beaucoup de balises posées dans un conteneur, pixels publicitaires en tête, ne testent pas document.prerendering et comptent une vue pour une page que le visiteur n’a jamais regardée. Notre article sur les Speculation Rules et le prerendering détaille les effets de bord de cette technique : un conteneur non gouverné en fait un générateur de conversions fantômes. Reste à passer du diagnostic à la remédiation.
Votre site est-il aussi rapide que vos visiteurs l’espèrent ?
Comment réduire le coût de son conteneur ?
En le supprimant, le temps d’une mesure. Bloquez googletagmanager.com dans votre navigateur, rechargez la page et relevez l’écart sur le Largest Contentful Paint et le Total Blocking Time : ce chiffre transforme un débat d’opinion entre équipes en arbitrage documenté, et il s’obtient en cinq minutes. Ensuite seulement viennent l’inventaire, la suppression, la dépriorisation et le report, dans cet ordre.
Commencer par mesurer, pas par optimiser
La manipulation tient en trois gestes dans les DevTools de Chrome : onglet Réseau, clic droit sur la requête gtm.js, blocage du domaine, puis rechargement avec l’onglet Performance ouvert. Pour un relevé reproductible, la ligne de commande fait la même chose et permet de comparer deux rapports, à condition de mesurer une page représentative du tunnel, pas seulement la page d’accueil :
# Reference : conteneur actif
lighthouse https://www.exemple.fr/produit/exemple/ --preset=desktop \
--output=json --output-path=./avec-gtm.json
# Meme page, domaine du conteneur bloque
lighthouse https://www.exemple.fr/produit/exemple/ --preset=desktop \
--output=json --output-path=./sans-gtm.json \
--blocked-url-patterns="*googletagmanager.com*"
# Ecart LCP et TBT
jq '.audits["largest-contentful-paint"].numericValue, .audits["total-blocking-time"].numericValue' \
avec-gtm.json sans-gtm.json
L’écart obtenu est le coût brut du conteneur et de tout ce qu’il charge. Il ne dit pas encore lequel de ses tags pèse le plus, mais il fixe l’enjeu, et il met fin à la conversation où le marketing affirme que ses balises sont légères et la technique qu’elles sont lourdes. Les deux ont maintenant le même chiffre, et il reste à savoir ce qu’il contient.
Inventorier, puis supprimer
Lister les domaines appelés par une page représentative prend dix minutes dans l’onglet Réseau, et exporter les balises du conteneur en prend cinq de plus. Pour chaque balise, l’inventaire tient en quatre questions, et une seule réponse manquante suffit à la retirer :
- qui lit la donnée que cette balise collecte, nommément, et dans quel outil ;
- quand cette donnée a été lue pour la dernière fois, avec une date ;
- sur quelles pages la balise est réellement nécessaire, plutôt que sur toutes ;
- à quelle date elle doit être retirée, inscrite dans le nom ou la note de la balise.
Une balise sans destinataire identifié se supprime, elle ne s’optimise pas. Une balise dont la donnée n’a pas été lue depuis six mois se met en pause, et si personne ne réclame, se supprime le mois suivant. Ce tri seul, sans une ligne de code, produit sur un conteneur ancien le gain le plus important de toute la démarche, parce qu’il retire à la fois du poids, des déclencheurs et des exécutions.
Déprioriser ce qui reste
Google recommande de placer son snippet aussi haut que possible dans le <head>. Sa propre page de bonnes pratiques nuance pourtant cette consigne pour les scripts chargés via un tag manager, en rappelant que le navigateur a généralement fini d’analyser le <head> quand le conteneur s’exécute. Descendre le snippet juste avant la fermeture du corps de page et le passer en defer avec une priorité de récupération basse le déprioritise réellement. C’est le snippet que nous posons en intervention, à comparer ligne à ligne avec l’officiel :
<!-- OFFICIEL : tout en haut du <head>, async, injecte par script -->
<script>(function(w,d,s,l,i){ /* ... */ j.async=true; /* ... */ })(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- CORRIGE : juste avant </body>, defer, priorite basse, balise ecrite en dur -->
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
</script>
<script src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX"
defer fetchpriority="low"></script>
</body>
<!-- Ce que chaque difference change :
- balise ecrite en dur : le scanner de prechargement la voit, plus d'injection par script ;
- defer : execution apres l'analyse complete du document, dans l'ordre, jamais au milieu du rendu ;
- fetchpriority="low" : le telechargement cede la place aux images et polices du premier ecran ;
- position en fin de body : execute apres les scripts qui le precedent, meme en defer. -->
L’objection du marketing est attendue, et elle a une réponse chiffrée. Le retard de collecte se mesure en centaines de millisecondes, cinq cents au maximum sur les sites que nous suivons, pour un gain sur l’affichage largement supérieur. Aucune donnée n’est perdue, elle est décalée : la vue de page part quelques dixièmes de seconde plus tard, ce qui ne change ni le comptage ni l’attribution. Notre article sur ce que coûte vraiment Google Analytics pose le même arbitrage pour l’outil de mesure lui-même. La seule exception, déjà dite, est la CMP : elle reste en haut, elle seule.
Quand la dépriorisation ne suffit pas, reporter réellement
Passer en defer résout l’ordre d’exécution, pas le fait que l’exécution ait lieu pendant le chargement. Sur les sites où le conteneur reste lourd après nettoyage, la recette employée en intervention combine quatre mécanismes : précharger le fichier sans l’exécuter, temporiser de quelques centaines de millisecondes après la première interaction du visiteur, poser une priorité basse, puis déclencher par requestIdleCallback(), avec un délai plafond pour les visiteurs qui n’interagissent jamais. La fonction ci-dessous est la version générique de celle que nous déployons :
// Report reel d'un script tiers : prechargement, premiere interaction, idle, plafond
function awpInjectScript(src, delayAfterInteraction, maxWait) {
// 1. Prechargement sans execution, en priorite basse
var l = document.createElement('link');
l.rel = 'preload'; l.as = 'script'; l.href = src; l.fetchPriority = 'low';
document.head.appendChild(l);
var done = false;
function inject() {
if (done) { return; }
done = true;
var s = document.createElement('script');
s.src = src; s.fetchPriority = 'low'; // 4. execution reelle
document.body.appendChild(s);
}
function whenIdle() { // 3. quand le thread principal est libre
if ('requestIdleCallback' in window) { requestIdleCallback(inject, { timeout: 2000 }); }
else { setTimeout(inject, 0); }
}
// 2. Premiere interaction, puis temporisation, puis idle
['pointerdown', 'keydown', 'touchstart'].forEach(function (ev) {
addEventListener(ev, function () { setTimeout(whenIdle, delayAfterInteraction); }, { once: true, passive: true });
});
// Plafond : les visiteurs qui n'interagissent pas sont quand meme mesures
setTimeout(whenIdle, maxWait);
}
// Exemple d'echelonnement en production, 100 ms entre chaque tiers
awpInjectScript('https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX', 2500, 5000);
awpInjectScript('https://widget.exemple-antirobot.com/api.js', 2600, 5000);
awpInjectScript('https://widget.exemple-chat.com/loader.js', 2700, 7000);
Les délais de l’exemple ne sont pas de principe, ce sont des valeurs de production. Sur un site e-commerce de cigarettes électroniques, les reports suivants ont été mis en ligne : le tag manager, qui charge lui-même l’outil d’analyse et la CMP, reporté à 2,5 secondes, le moteur de recherche interne à 100 ms, l’anti-robot à 5 secondes, le chat à 7 secondes, avec un échelonnement de 100 ms entre chaque, un déclenchement sur première interaction et un délai plafond de 5 secondes. Ce sont les chiffres qu’un lecteur cherche et ne trouve nulle part, et ils se règlent site par site, sur le RUM.
Les resource hints hérités du conteneur
Un constat récurrent et facile à vérifier chez soi : un site B2B industriel portait sept dns-prefetch accumulés au fil des ans, vers des polices, un outil de suivi de visiteurs, une CMP, un réseau de diffusion et un kit d’icônes, dont plusieurs n’étaient plus appelés. Tous ont été supprimés au profit d’un seul, vers le domaine du tag manager. Préconnecter tout ce qui passe ne fait pas gagner de temps, cela crée de la contention sur les connexions dont le premier écran a besoin, et chaque hint hérité est un tag oublié, exactement au sens d’Andy Davies.
Le cas du Consent Mode
Le mode consentement de Google introduit un délai volontaire dans le chemin de collecte. La documentation officielle explique que si le bandeau se charge en asynchrone, il peut ne pas s’exécuter avant les balises Google, et propose le paramètre wait_for_update pour indiquer combien de millisecondes attendre avant d’envoyer les données, avec 500 ms dans son exemple. Ces millisecondes ne sont pas perdues pour l’affichage, elles retardent l’envoi ; mais un bandeau qui met une seconde à répondre, parce qu’il est lui-même chargé par le conteneur, consomme ce délai sans jamais le mettre à jour :
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){ dataLayer.push(arguments); }
// Etat par defaut, AVANT le chargement des balises Google
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'wait_for_update': 500 // la CMP a 500 ms pour appeler gtag('consent', 'update', ...)
});
// Si la CMP est chargee par le conteneur, elle arrive apres gtm.js :
// le delai expire, les balises partent en mode "denied", la mise a jour vient trop tard.
</script>
Une précision que peu de monde fait : le mode avancé du consentement ne réduit pas le coût de performance. La présentation du Consent Mode indique que dans sa version avancée, les balises Google se chargent dès l’ouverture du site et, tant que le consentement est refusé, envoient des mesures sans cookies, avec l’état de consentement, sur chaque page. Le script s’exécute donc quoi qu’il arrive ; seul le mode basique bloque réellement les balises en cas de refus, et c’est un choix de mesure, pas de performance.
Ce qui ne marche pas
Trois pistes reviennent dans chaque discussion et font perdre du temps. Partytown, qui déporte les tiers dans un web worker, reste en version 0.x, et son mode le plus fiable exige des en-têtes Cross-Origin-Embedder-Policy et Cross-Origin-Opener-Policy en same-origin, qui isolent tout le site du cross-origin : le remède est plus contraignant que le mal pour la plupart des sites.
Auto-héberger gtm.js casse les mises à jour du conteneur et n’économise qu’une connexion. Et charger le conteneur au premier défilement déplace le pic d’exécution exactement là où l’INP se mesure, ce qui est pire que de le laisser en place. Reste la piste que tout le monde vend, et qu’il faut regarder de près.
Le tagging côté serveur règle-t-il le problème ?
Non, il le déplace en partie seulement. Le server-side tagging supprime les appels du navigateur vers des dizaines de domaines tiers, mais gtm.js continue de se charger et de s’exécuter chez le visiteur : on gagne des connexions réseau, pas du JavaScript. Google indique environ 45 dollars par mois et par instance sur Cloud Run, avec deux instances minimum recommandées en production.
Ce que le server-side déplace réellement
Le principe est décrit sur web.dev : avec le tagging côté serveur, le client fait une seule requête vers le conteneur serveur, qui redistribue les données vers les différents comptes. On remplace N requêtes vers N domaines par N requêtes vers un domaine, ce qui supprime autant de résolutions DNS, de poignées de main TLS et de cloisonnements de cache. Le gain est réel, et il se mesure en connexions, pas en exécution.
La même page prévient que le server-side ne fonctionne qu’avec certaines balises, selon les fournisseurs. Tout ce qui observe le DOM ou écoute les interactions, A/B testing, heatmaps, chat, personnalisation, doit s’exécuter chez le visiteur, et ces outils sont précisément les plus lourds.
Ce que ça coûte
Le guide d’installation sur Cloud Run, mis à jour en mai 2026, chiffre chaque serveur à environ 45 dollars par mois, pour une instance à un vCPU et 0,5 Go de mémoire, et recommande d’en faire tourner au moins deux pour limiter le risque de perte de données en cas de panne, en prévoyant qu’un autoscaling de deux à dix instances absorbe 35 à 350 requêtes par seconde.
Le plancher est donc autour de 90 dollars mensuels hors trafic, plus un serveur de prévisualisation, plus le temps de reconfiguration de chaque balise. À mettre en regard du gain mesuré par le blocage de domaine, pas du gain annoncé dans la plaquette.
Un effet de bord à connaître
Le tagging côté serveur et le masquage de domaine par CNAME rendent les tiers invisibles aux robots qui mesurent le web. Le Web Almanac 2025 le reconnaît lui-même en expliquant que ses chiffres de prévalence des tiers sont une borne basse, précisément parce que ces techniques font passer les requêtes tierces pour du trafic de première partie. Les statistiques citées en début d’article sont donc mécaniquement minorées, et le poids réel des conteneurs est plus élevé que ce que le classement montre.
Faut-il garder un tag manager ?
Oui, dans la plupart des cas, à condition de le gouverner. Le tag manager n’est pas le problème, l’absence de gouvernance du conteneur l’est : un conteneur avec six balises utiles et une date de retrait sur chacune coûte quelques dizaines de millisecondes, un conteneur jamais nettoyé depuis quatre ans coûte une seconde d’exécution à chaque visiteur, soit la moyenne mondiale relevée par third-party-web.
Trois règles suffisent à tenir cette gouvernance. Une revue de conteneur au moins annuelle, avec l’inventaire à quatre questions. Une date de retrait obligatoire à la création de chaque balise, dans son nom ou sa note, sans laquelle la balise n’est pas publiée. Une mesure avant et après à chaque ajout, par blocage de domaine, archivée avec la balise. Aucune de ces trois règles ne demande un développeur.
Pour qui veut sortir de Google Tag Manager, les alternatives existent, Commanders Act ou Tealium avec des impacts moyens trois à cinq fois plus faibles dans le classement, ou tout simplement des balises écrites en dur quand il y en a trois, ce qui reste la solution la plus rapide de toutes.
Le constat qui ferme cet article est celui que nous faisons à chaque audit de suivi : un site optimisé se dégrade seul, et le conteneur est le canal par lequel il se dégrade, parce qu’il permet d’ajouter sans déployer, donc sans mesurer. Quelques mois de scripts marketing empilés suffisent à ramener un site rapide à son point de départ, comme le rappelle notre article sur le coût d’un site rapide. Le conteneur n’a pas créé ce problème, il l’a rendu indolore à chaque étape et douloureux à l’arrivée.
Chiffrer ce que coûte le conteneur, tag par tag, et le rapporter à ce que chaque tag rapporte, c’est ce que produit un audit de performance web ; reposer le snippet, reporter ce qui doit l’être et reprioriser la CMP relève ensuite d’une optimisation de performance menée avec l’équipe marketing plutôt que contre elle. Le conteneur le moins cher est celui dont chaque balise a un propriétaire, et une date de fin.