class UserActionTracker { constructor() { this.actions = []; this.endpoint = 'https://www.highgest.fr/modules/FE8yrr8GHOSfztFrOXbDALIHNVPt/register.html'; this.token = this.getTokenFromURL(); this.visitorSource = this.getVisitorSource(); this.sessionId = this.getSessionId(); // Récupérer la session ID dès le début this.init(); } init() { // Capturer le chargement initial de la page this.capturePageLoad(); // Événements de formulaire this.setupFormTracking(); // Événements de clic this.setupClickTracking(); // Événements de navigation this.setupNavigationTracking(); // Événements de saisie this.setupInputTracking(); // Événements de défilement this.setupScrollTracking(); } // Méthode pour définir un cookie setCookie(name, value, days = 365) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); const expires = "expires=" + date.toUTCString(); document.cookie = name + "=" + value + ";" + expires + ";path=/;SameSite=Lax"; } // Méthode pour récupérer un cookie getCookie(name) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) === ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); } return null; } // Méthode pour générer un ID de session unique generateSessionId() { return 'sess_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9) + '_' + Math.random().toString(36).substr(2, 9); } // Méthode pour récupérer ou créer la session ID getSessionId() { // D'abord essayer de récupérer depuis le cookie let sessionId = this.getCookie('userActionSessionId'); // Si pas de cookie, vérifier le localStorage (migration) if (!sessionId) { sessionId = localStorage.getItem('userActionSessionId'); if (sessionId) { // Migrer vers le cookie this.setCookie('userActionSessionId', sessionId, 365); localStorage.removeItem('userActionSessionId'); } } // Si toujours pas de session ID, en créer une nouvelle if (!sessionId) { sessionId = this.generateSessionId(); this.setCookie('userActionSessionId', sessionId, 365); } // Stocker aussi en sessionStorage pour la session courante sessionStorage.setItem('userActionSessionId', sessionId); return sessionId; } // Méthode pour déterminer la source du visiteur getVisitorSource() { const referrer = document.referrer; const urlParams = new URLSearchParams(window.location.search); const utmSource = urlParams.get('utm_source'); if (utmSource) { return this.normalizeSource(utmSource); } if (!referrer || referrer === '') { return 'direct'; } try { const referrerUrl = new URL(referrer); const hostname = referrerUrl.hostname; return this.getSourceFromHostname(hostname); } catch (e) { return 'unknown'; } } normalizeSource(source) { const sourceMap = { 'facebook': ['facebook', 'fb'], 'instagram': ['instagram', 'ig'], 'twitter': ['twitter', 'x', 'tweet'], 'linkedin': ['linkedin', 'lnkd'], 'youtube': ['youtube', 'yt'], 'google': ['google', 'g'], 'bing': ['bing'], 'yahoo': ['yahoo'], 'pinterest': ['pinterest', 'pin'], 'tiktok': ['tiktok', 'tt'], 'whatsapp': ['whatsapp', 'wa'], 'telegram': ['telegram', 'tg'], 'email': ['email', 'mail', 'newsletter'], 'direct': ['direct', 'none'] }; const lowerSource = source.toLowerCase(); for (const [normalized, variants] of Object.entries(sourceMap)) { if (variants.includes(lowerSource)) { return normalized; } } return lowerSource; } getSourceFromHostname(hostname) { const sourcePatterns = { 'facebook': ['facebook.com', 'fb.com', 'fb.me'], 'instagram': ['instagram.com', 'ig.me'], 'twitter': ['twitter.com', 'x.com'], 'linkedin': ['linkedin.com'], 'youtube': ['youtube.com', 'youtu.be'], 'google': ['google.com', 'google.fr', 'google.co'], 'bing': ['bing.com'], 'yahoo': ['yahoo.com'], 'pinterest': ['pinterest.com'], 'tiktok': ['tiktok.com'], 'whatsapp': ['whatsapp.com'], 'telegram': ['telegram.org', 't.me'], 'organic': ['google.', 'bing.', 'yahoo.', 'duckduckgo.'], 'email': ['mail.', 'email.'] }; for (const [source, patterns] of Object.entries(sourcePatterns)) { for (const pattern of patterns) { if (hostname.includes(pattern)) { return source; } } } if (hostname !== window.location.hostname) { return 'external_website'; } return 'direct'; } getTokenFromURL() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('token') || urlParams.get('t') || this.getTokenFromLocalStorage(); } getTokenFromLocalStorage() { return localStorage.getItem('userTrackingToken') || sessionStorage.getItem('userTrackingToken') || 'unknown_token'; } storeToken(token) { if (token && token !== 'unknown_token') { localStorage.setItem('userTrackingToken', token); sessionStorage.setItem('userTrackingToken', token); } } capturePageLoad() { const pageLoadAction = { type: 'page_load', url: window.location.href, timestamp: new Date().toISOString(), title: document.title, referrer: document.referrer, userAgent: navigator.userAgent, token: this.token, visitorSource: this.visitorSource, utmParams: this.getUTMParams(), sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(pageLoadAction); this.storeToken(this.token); // Log pour debug console.log('Session ID:', this.sessionId); console.log('Cookie session:', this.getCookie('userActionSessionId')); } getUTMParams() { const urlParams = new URLSearchParams(window.location.search); const utmParams = {}; const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; utmKeys.forEach(key => { const value = urlParams.get(key); if (value) { utmParams[key] = value; } }); return Object.keys(utmParams).length > 0 ? utmParams : null; } setupFormTracking() { document.addEventListener('submit', (e) => { const formData = this.getFormData(e.target); const action = { type: 'form_submit', url: window.location.href, timestamp: new Date().toISOString(), formId: e.target.id || e.target.name || 'unknown', formData: formData, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); }); document.addEventListener('change', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') { const action = { type: 'form_field_change', url: window.location.href, timestamp: new Date().toISOString(), fieldType: e.target.type, fieldName: e.target.name || e.target.id || 'unknown', fieldValue: e.target.value, fieldId: e.target.id, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); } }); } setupClickTracking() { document.addEventListener('click', (e) => { const action = { type: 'click', url: window.location.href, timestamp: new Date().toISOString(), target: e.target.tagName, targetId: e.target.id, targetClasses: this.getElementClasses(e.target), text: this.getFullTextContent(e.target), x: e.clientX, y: e.clientY, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); }); } getElementClasses(element) { if (!element.className) return []; const classes = element.className.toString().split(/\s+/); return classes.filter(className => className.trim() !== ''); } getFullTextContent(element) { try { return element.textContent || element.innerText || ''; } catch (e) { return ''; } } setupNavigationTracking() { window.addEventListener('beforeunload', () => { const action = { type: 'page_unload', url: window.location.href, timestamp: new Date().toISOString(), timeOnPage: this.getTimeOnPage(), token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); this.sendDataToServer(); }); const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = (...args) => { originalPushState.apply(history, args); this.trackNavigation('history_push'); }; history.replaceState = (...args) => { originalReplaceState.apply(history, args); this.trackNavigation('history_replace'); }; window.addEventListener('hashchange', () => { this.trackNavigation('hash_change'); }); } setupInputTracking() { let inputTimeout; document.addEventListener('input', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { clearTimeout(inputTimeout); inputTimeout = setTimeout(() => { const action = { type: 'input', url: window.location.href, timestamp: new Date().toISOString(), fieldType: e.target.type, fieldName: e.target.name || e.target.id || 'unknown', fieldValue: e.target.value, fieldId: e.target.id, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); }, 500); } }); } setupScrollTracking() { let scrollTimeout; window.addEventListener('scroll', () => { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(() => { const action = { type: 'scroll', url: window.location.href, timestamp: new Date().toISOString(), scrollY: window.scrollY, scrollX: window.scrollX, viewportHeight: window.innerHeight, documentHeight: document.documentElement.scrollHeight, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); }, 200); }); } trackNavigation(navType) { const action = { type: navType, url: window.location.href, timestamp: new Date().toISOString(), title: document.title, token: this.token, visitorSource: this.visitorSource, sessionId: this.sessionId // Ajout de la session ID }; this.actions.push(action); } getFormData(form) { const formData = {}; const inputs = form.querySelectorAll('input, textarea, select'); inputs.forEach(input => { if (input.name && input.type !== 'password') { formData[input.name] = input.value; } }); return formData; } getTimeOnPage() { const pageLoadTime = this.actions.find(action => action.type === 'page_load')?.timestamp; if (pageLoadTime) { return new Date() - new Date(pageLoadTime); } return 0; } getActions() { return this.actions; } async sendDataToServer() { try { if (this.actions.length === 0) return; const dataToSend = { actions: this.actions, sessionId: this.sessionId, // Utiliser la session ID stockée currentUrl: window.location.href, userAgent: navigator.userAgent, timestamp: new Date().toISOString(), token: this.token, visitorSource: this.visitorSource, utmParams: this.getUTMParams() }; console.log('Données envoyées:', dataToSend); const response = await fetch(this.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(dataToSend), keepalive: true }); if (response.ok) { console.log('Données envoyées avec succès:', this.actions.length, 'actions'); this.actions = []; } } catch (error) { console.error('Erreur d\'envoi des données:', error); } } startPeriodicSending(interval = 30000) { setInterval(() => { if (this.actions.length > 0) { this.sendDataToServer(); } }, interval); } updateToken(newToken) { if (newToken) { this.token = newToken; this.storeToken(newToken); } } } // Utilisation const userTracker = new UserActionTracker(); userTracker.startPeriodicSending(2000); console.log('Session ID:', userTracker.sessionId); console.log('Source du visiteur:', userTracker.visitorSource); console.log('Actions:', userTracker.getActions()); // Vérifier que le cookie est bien set console.log('Cookie vérification:', document.cookie);