Installer un tracking de formulaire sans Google Tag Manager
Le tracking de formulaire sans Google Tag Manager s'installe en JavaScript natif : un script capture le GCLID, les paramètres UTM et les données de navigation, puis les injecte dans des champs cachés du formulaire. Compatible WordPress, Webflow, et tout site HTML. Temps d'installation : 5 à 10 minutes.
J'ai longtemps été partisan de GTM. Quand j'étais chez Capifrance et Optimhome, c'était l'outil standard, et il faisait très bien le job. Mais sur les projets B2B que j'accompagne aujourd'hui, je recommande de plus en plus souvent de s'en passer purement et simplement. Pas par dogmatisme, par pragmatisme. Les cas d'usage où GTM est indispensable se sont raréfiés, et les cas où il devient un risque opérationnel se sont multipliés.
Pourquoi se passer de GTM ?
Google Tag Manager est la solution standard, mais plusieurs raisons peuvent vous pousser à faire autrement :
- Performance : GTM ajoute du poids à la page (le container + tous les tags)
- Contrôle : Vous voulez maîtriser exactement ce qui s'exécute
- Sécurité : Certaines entreprises interdisent GTM pour des raisons de conformité
- Simplicité : Un seul script à maintenir plutôt qu'un container complexe
Le tracking natif fonctionne tout aussi bien, et peut même être plus fiable car moins dépendant de ressources externes. Consultez aussi notre guide pour récupérer le GCLID dans vos formulaires.
Retour d'expérience : pourquoi GTM devient un risque opérationnel
Ce que je constate sur le terrain
Sur les projets LeadZen où on migre les clients vers du tracking server-side ou JS natif, j'observe deux choses quasi-systématiques :
- Le volume de conversions trackées augmente, pas parce qu'on convertit plus, mais parce qu'on en perdait silencieusement via ad blockers et CMP trop agressives.
- Le client comprend enfin son tracking. Avec GTM, 80% des clients que j'audite ne savent pas exactement ce qui s'exécute dans leur container. Avec un script natif, tout est dans leur code source, auditable en 30 secondes.
Le vrai sujet de 2025-2026, ce n'est plus "GTM ou pas GTM" : c'est "combien de couches de dépendance tierce je mets entre le visiteur et ma conversion Google Ads".
Cette bascule est confirmée par les analyses de terrain. Nils Rooijmans (Google Ads Performance Architect) documente en décembre 2025 un cas devenu emblématique :
Un outil tiers a modifié les templates de tracking de conversion sur un compte client pendant le week-end. Sans le script d'alerte, les modifications seraient restées en place : OCI erroné, moins de conversions trackées, Smart Bidding déréglé.
— Nils Rooijmans, nilsrooijmans.com/daily (décembre 2025)
La recommandation de Nils : déployer un script Google Ads de "change history alert" pour détecter toute modification non autorisée du tracking, y compris par des outils API tiers ou des LLM. Avec un tracking natif intégré au code source, ce type de modification invisible est impossible.
Côté pertinence stratégique, Arthur Cassarin-Grand (Happy New Leads) est encore plus tranché sur la question CMP :
Les CMP font perdre des signaux. Un client a vu ses conversions chuter après installation de la CMP. Migration vers le server-side pour retrouver les données. Pour les side-business : zéro cookie, tout en server-side, data first-party.
— Arthur Cassarin-Grand, Happy New Leads (mars 2024)
Que faut-il tracker ?
Un tracking de formulaire complet doit capturer :
- GCLID : Identifiant du clic Google Ads
- gbraid/wbraid : Identifiants iOS 14+
- Paramètres UTM : Source, medium, campaign, content, term
- URL de landing : Première page visitée
- Referrer : D'où vient le visiteur
- Timestamp : Date et heure de la première visite
Le script complet
Voici un script JavaScript complet qui gère tout le tracking. Ajoutez-le dans le <head> de toutes vos pages, le plus haut possible.
<script>
(function() {
'use strict';
// === CONFIGURATION ===
var COOKIE_EXPIRY_DAYS = 90; // Durée de vie des cookies (max attribution Google Ads)
var COOKIE_PREFIX = '_lz_'; // Préfixe pour éviter les conflits
// === UTILITAIRES COOKIES ===
function setCookie(name, value, days) {
var expires = '';
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = '; expires=' + date.toUTCString();
}
document.cookie = COOKIE_PREFIX + name + '=' + encodeURIComponent(value || '') + expires + '; path=/; SameSite=Lax';
}
function getCookie(name) {
var nameEQ = COOKIE_PREFIX + name + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(nameEQ) === 0) {
return decodeURIComponent(c.substring(nameEQ.length));
}
}
return null;
}
// === UTILITAIRES URL ===
function getParam(param) {
var urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
}
function getAllUtmParams() {
var utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
var result = {};
utmParams.forEach(function(param) {
var value = getParam(param);
if (value) result[param] = value;
});
return Object.keys(result).length > 0 ? result : null;
}
// === CAPTURE À L'ARRIVÉE ===
function captureOnLanding() {
// Identifiants publicitaires (écraser si présents)
var gclid = getParam('gclid');
var gbraid = getParam('gbraid');
var wbraid = getParam('wbraid');
var fbclid = getParam('fbclid');
if (gclid) setCookie('gclid', gclid, COOKIE_EXPIRY_DAYS);
if (gbraid) setCookie('gbraid', gbraid, COOKIE_EXPIRY_DAYS);
if (wbraid) setCookie('wbraid', wbraid, COOKIE_EXPIRY_DAYS);
if (fbclid) setCookie('fbclid', fbclid, COOKIE_EXPIRY_DAYS);
// UTM (écraser si présents)
var utmParams = getAllUtmParams();
if (utmParams) {
setCookie('utm', JSON.stringify(utmParams), COOKIE_EXPIRY_DAYS);
}
// Landing URL et referrer (ne pas écraser si déjà présents)
if (!getCookie('landing_url')) {
setCookie('landing_url', window.location.href, COOKIE_EXPIRY_DAYS);
}
if (!getCookie('referrer') && document.referrer) {
// Ne stocker que si le referrer est externe
var referrerHost = new URL(document.referrer).hostname;
if (referrerHost !== window.location.hostname) {
setCookie('referrer', document.referrer, COOKIE_EXPIRY_DAYS);
}
}
if (!getCookie('first_visit')) {
setCookie('first_visit', new Date().toISOString(), COOKIE_EXPIRY_DAYS);
}
}
// === RÉCUPÉRATION DES DONNÉES ===
window.getTrackingData = function() {
var utmCookie = getCookie('utm');
var utmParams = utmCookie ? JSON.parse(utmCookie) : {};
return {
gclid: getCookie('gclid') || '',
gbraid: getCookie('gbraid') || '',
wbraid: getCookie('wbraid') || '',
fbclid: getCookie('fbclid') || '',
utm_source: utmParams.utm_source || '',
utm_medium: utmParams.utm_medium || '',
utm_campaign: utmParams.utm_campaign || '',
utm_content: utmParams.utm_content || '',
utm_term: utmParams.utm_term || '',
landing_url: getCookie('landing_url') || '',
referrer: getCookie('referrer') || '',
first_visit: getCookie('first_visit') || ''
};
};
// === INJECTION DANS LES FORMULAIRES ===
function injectIntoForms() {
var data = window.getTrackingData();
var forms = document.querySelectorAll('form');
forms.forEach(function(form) {
// Créer ou mettre à jour les champs cachés
Object.keys(data).forEach(function(key) {
if (data[key]) {
var field = form.querySelector('input[name="' + key + '"]');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = key;
form.appendChild(field);
}
field.value = data[key];
}
});
});
}
// === INITIALISATION ===
captureOnLanding();
// Injecter au chargement DOM
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', injectIntoForms);
} else {
injectIntoForms();
}
// Réinjecter si nouveaux formulaires ajoutés dynamiquement
if (typeof MutationObserver !== 'undefined') {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
injectIntoForms();
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
})();
</script>
Comment ça fonctionne
1. Capture à l'arrivée
Dès que la page se charge, le script :
- Lit les paramètres de l'URL (gclid, utm_*, etc.)
- Les stocke dans des cookies first-party
- Enregistre l'URL de landing et le referrer (une seule fois)
2. Stockage en cookies
Les données sont stockées en cookies pour :
- Survivre à la navigation entre pages
- Rester disponibles jusqu'à 90 jours
- Être récupérables au moment du formulaire
3. Injection dans les formulaires
Au chargement de la page (et à chaque ajout de formulaire), le script :
- Trouve tous les formulaires de la page
- Crée des champs hidden pour chaque donnée de tracking
- Les remplit avec les valeurs des cookies
Vérifier l'installation
Test rapide
- Ouvrez votre site avec des paramètres de test :
?gclid=test123&utm_source=test&utm_campaign=demo - Ouvrez la console développeur (F12)
- Tapez :
getTrackingData() - Vérifiez que les valeurs sont bien présentes
Test du formulaire
- Inspectez votre formulaire (clic droit > Inspecter)
- Cherchez les champs hidden (input type="hidden")
- Vérifiez que gclid, utm_source, etc. sont présents avec les bonnes valeurs
Test de persistance
- Visitez la page avec les paramètres
- Naviguez vers une autre page du site
- Vérifiez que
getTrackingData()retourne toujours les valeurs
Intégration avec votre backend
Côté serveur, récupérez les champs comme n'importe quel champ de formulaire :
PHP
$gclid = $_POST['gclid'] ?? '';
$utm_source = $_POST['utm_source'] ?? '';
$landing_url = $_POST['landing_url'] ?? '';
// Stocker dans votre base de données ou CRM
$lead = [
'email' => $_POST['email'],
'gclid' => $gclid,
'utm_source' => $utm_source,
'landing_url' => $landing_url,
// ...
];
Node.js (Express)
app.post('/contact', (req, res) => {
const { email, gclid, utm_source, landing_url } = req.body;
// Stocker dans votre base de données
await Lead.create({
email,
gclid,
utm_source,
landing_url,
});
});
Personnalisations courantes
Ajouter d'autres paramètres
Pour tracker des paramètres personnalisés, modifiez la fonction captureOnLanding() :
// Exemple : tracker un paramètre "ref" pour un programme d'affiliation
var ref = getParam('ref');
if (ref) setCookie('ref', ref, COOKIE_EXPIRY_DAYS);
Exclure certains formulaires
Pour ne pas injecter dans certains formulaires (newsletter, recherche, etc.) :
function injectIntoForms() {
var data = window.getTrackingData();
var forms = document.querySelectorAll('form:not([data-no-tracking])');
// ...
}
// HTML : <form data-no-tracking>...</form>
Envoyer les données via JavaScript (AJAX)
Si vous envoyez vos formulaires en AJAX, récupérez les données avant l'envoi :
form.addEventListener('submit', function(e) {
e.preventDefault();
var formData = new FormData(form);
var trackingData = getTrackingData();
// Ajouter les données de tracking
Object.keys(trackingData).forEach(function(key) {
if (trackingData[key]) {
formData.append(key, trackingData[key]);
}
});
fetch('/api/contact', {
method: 'POST',
body: formData
});
});
Quels navigateurs sont compatibles ?
Ce script fonctionne sur :
- Chrome, Firefox, Safari, Edge (versions récentes)
- Internet Explorer 11 (avec polyfill URLSearchParams si nécessaire)
- Navigateurs mobiles iOS et Android
Pour IE11, ajoutez ce polyfill avant le script principal :
<script>
// Polyfill URLSearchParams pour IE11
if (!window.URLSearchParams) {
// ... polyfill code
}
</script>
Quelles sont les implications RGPD ?
Ce script utilise des cookies first-party. Selon votre interprétation du RGPD :
- Position stricte : Attendez le consentement avant d'exécuter le script
- Position modérée : Ces cookies sont nécessaires au fonctionnement du service (attribution des leads à leur source marketing)
Dans tous les cas, mentionnez ces cookies dans votre politique de confidentialité.
LeadZen : tracking clé en main
Notre script de tracking gère automatiquement la capture, le stockage et l'envoi des données d'attribution. Compatible avec tous les formulaires, sans configuration technique.
Essayer gratuitement pendant 30 joursQuels sont les problèmes courants ?
Les champs hidden ne sont pas créés
Cause : Le script s'exécute avant que le DOM soit prêt.
Solution : Vérifiez que l'injection se fait bien au DOMContentLoaded ou utilisez le MutationObserver (inclus dans le script).
Les cookies ne sont pas créés
Cause : Problème de SameSite ou de domaine.
Solution : Vérifiez que vous êtes en HTTPS. Ajoutez ; Secure à la fin du cookie si nécessaire.
Les valeurs sont vides au moment du formulaire
Cause : Le visiteur n'est pas arrivé via une campagne trackée.
C'est normal : Seuls les visiteurs provenant de campagnes avec paramètres (gclid, utm_*) auront des données. Le trafic direct ou organique n'aura pas ces informations. Si vous rencontrez des problèmes, consultez notre guide pour débugger le tracking de conversions.
Le tracking natif en 2026 : server-side et Enhanced Conversions
Deux évolutions 2025/2026 renforcent l'intérêt du tracking JS natif (souvent combiné à du server-side) :
1. Enhanced Conversions for Leads devient le standard B2B
Google a étendu Enhanced Conversions for Leads à tous les annonceurs courant 2024-2025. Principe : au moment de la soumission du formulaire, vous hashez l'email (SHA-256) côté serveur avant de l'envoyer avec la conversion. Google fait le matching avec son propre base d'utilisateurs signés. Résultat : une réattribution des conversions cross-device qui étaient perdues avec le seul GCLID.
Un script JS natif gère cela parfaitement : il suffit de capturer email + GCLID dans le même payload, de hasher côté serveur (Node, PHP, Python), puis d'appeler l'API Google Ads Enhanced Conversions. Pas besoin de GTM pour ça.
2. Le tracking enrichi est mesurable comme avantage compétitif
Les campagnes avec tracking enrichi montrent une accélération significative de la croissance. Server-side tagging, données panier de conversion, données fournies par l'utilisateur (email hashé, téléphone), enrichissement données nouveaux clients. L'avantage des données de haute qualité gagne.
— Louis Bogdan, cité par Miles McNair (PPC Mastery, The PPC Edge #137, août 2025)
3. Data exclusions : un comportement contre-intuitif à connaître
Nils Rooijmans a documenté en octobre 2025 un point critique trop souvent ignoré : les data exclusions ciblent les clics, pas les dates de conversion. Si votre tracking était défaillant du 12 au 14 octobre mais que les conversions arrivent plusieurs jours après le clic, il faut exclure les clics depuis quelques jours avant la période défaillante (ex : exclure les clics du 10 au 14 octobre). Avec un tracking natif, vous avez la main pour reproduire et auditer précisément ce qui s'est passé, chose très difficile en GTM où la configuration peut avoir été modifiée entre-temps.
Documentation officielle
- Auto-tagging et GCLID · Documentation Google Ads
- Import de conversions offline · Documentation Google Ads
Conclusion
Un tracking de formulaire sans GTM est tout à fait viable et peut même être plus performant. L'essentiel est de capturer les données dès l'arrivée du visiteur et de les conserver jusqu'au moment du formulaire.
Les 3 points clés :
- Capturez tout dès l'arrivée : GCLID, UTM, landing URL, referrer (essentiel pour les conversions offline)
- Stockez en cookies first-party : Fiable et durable (90 jours)
- Injectez automatiquement : Les champs hidden évitent les oublis
Besoin d'une solution plus simple ? Testez LeadZen pour un tracking complet sans code à maintenir.
Pour aller plus loin
Cet article fait partie de notre Conversions offline Google Ads : le guide complet. Voici d'autres ressources du même cluster :
Fondateur de LeadZen, spécialiste Google Ads Leadgen
Dans le web depuis 2002, +15 ans en SEO, +5 ans en Google Ads. Ex-responsable SEO chez Capifrance et Optimhome. +50 000 prospects générés pour les réseaux immobiliers français. Certifié Google Ads, formé à la Blaise & Bruno Academy.
LinkedIn