/* Version: 1.0.0 | Created: 2026-04-08 | Updated: 2026-04-08 */ /* HELP4BIS Analytics Tracker — lightweight, self-hosted, privacy-first */ (function() { 'use strict'; var endpoint = '/analytics/track.php'; function getPagePath() { return window.location.pathname || '/'; } function getReferrer() { var ref = document.referrer || ''; // Strip own domain if (ref.indexOf(window.location.hostname) !== -1) return ''; return ref; } function getScreenSize() { return window.screen.width + 'x' + window.screen.height; } function getUtmParams() { var params = {}; var search = window.location.search; if (!search) return params; var pairs = search.substring(1).split('&'); for (var i = 0; i < pairs.length; i++) { var kv = pairs[i].split('='); var key = decodeURIComponent(kv[0]); if (key.indexOf('utm_') === 0) { params[key] = decodeURIComponent(kv[1] || ''); } } return params; } function track(eventType, data) { var payload = { event: eventType, page: getPagePath(), title: document.title, referrer: getReferrer(), screen: getScreenSize(), language: navigator.language || '', utm: getUtmParams(), timestamp: new Date().toISOString() }; if (data) { for (var key in data) { if (data.hasOwnProperty(key)) payload[key] = data[key]; } } // Use sendBeacon for reliability, fallback to fetch var body = JSON.stringify(payload); if (navigator.sendBeacon) { navigator.sendBeacon(endpoint, body); } else { var xhr = new XMLHttpRequest(); xhr.open('POST', endpoint, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.send(body); } } // Track page view on load track('pageview'); // Track time on page (fires on unload) var startTime = Date.now(); window.addEventListener('beforeunload', function() { var duration = Math.round((Date.now() - startTime) / 1000); if (duration > 1) { track('duration', { seconds: duration }); } }); // Track outbound link clicks document.addEventListener('click', function(e) { var link = e.target.closest('a'); if (!link) return; var href = link.getAttribute('href') || ''; // CTA buttons (contact, get started, etc.) if (link.classList.contains('btn') || link.classList.contains('cta')) { track('cta_click', { href: href, text: (link.textContent || '').trim().substring(0, 80) }); } // Outbound links if (href.indexOf('http') === 0 && href.indexOf(window.location.hostname) === -1) { track('outbound', { href: href }); } // Phone/email clicks if (href.indexOf('tel:') === 0 || href.indexOf('mailto:') === 0) { track('contact_click', { href: href }); } }); // Track form submissions document.addEventListener('submit', function(e) { var form = e.target; track('form_submit', { form_id: form.id || '', form_action: form.action || '' }); }); // Track scroll depth (25%, 50%, 75%, 100%) var scrollMarks = { 25: false, 50: false, 75: false, 100: false }; window.addEventListener('scroll', function() { var scrollTop = window.pageYOffset || document.documentElement.scrollTop; var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; if (docHeight <= 0) return; var pct = Math.round((scrollTop / docHeight) * 100); [25, 50, 75, 100].forEach(function(mark) { if (pct >= mark && !scrollMarks[mark]) { scrollMarks[mark] = true; track('scroll', { depth: mark }); } }); }); })();