
★★★★★
"From the airport pickup to the last dinner, everything was flawless. Chef Silva made our anniversary unforgettable."
— Google Review · 5.0

/** * GA4 ADVANCED TRACKING SYSTEM * www.privatechefloscabos.com * * Arquitectura escalable de eventos para Google Analytics 4 * Permite agregar eventos sin modificar código base * * Version: 1.0.0 * Updated: 2026-07-28 * Status: PRODUCTION READY */ (function() { 'use strict'; // ==================== CONFIGURACIÓN CENTRALIZADA ==================== const GA4_CONFIG = { measurementId: 'G-0PKFN3PBS2', enableDebug: true, enableConsoleLogging: true, version: '1.0.0', lastUpdated: '2026-07-28' }; // ==================== EVENT REGISTRY (ESCALABLE) ==================== const EVENT_REGISTRY = { 'service_button_click': { name: 'service_button_click', category: 'service_inquiry', description: 'Usuario hace clic en un botón de servicio', parameters: ['service_name', 'service_id', 'utm_source', 'utm_medium', 'utm_campaign'], isMicroConversion: true, isKeyEvent: true, phase: 'PHASE_3.1' }, 'page_view_enhanced': { name: 'page_view_enhanced', category: 'page_view', description: 'Vista de página con contexto de campaña', parameters: ['utm_source', 'utm_medium', 'utm_campaign', 'service_name'], isMicroConversion: false, isKeyEvent: false, phase: 'PHASE_3.1' }, 'page_exit': { name: 'page_exit', category: 'engagement', description: 'Usuario abandona la página', parameters: ['time_on_page', 'user_segment', 'service_name'], isMicroConversion: false, isKeyEvent: false, phase: 'PHASE_3.1' }, 'form_started': { name: 'form_started', category: 'form_interaction', description: 'Usuario comienza un formulario', parameters: ['form_type', 'form_id', 'service_name'], isMicroConversion: true, isKeyEvent: false, phase: 'PHASE_3.2' }, 'form_submission': { name: 'form_submission', category: 'conversion', description: 'Usuario envía un formulario', parameters: ['form_type', 'form_id', 'service_name', 'user_email'], isMicroConversion: false, isKeyEvent: true, phase: 'PHASE_3.2' }, 'phone_call_initiated': { name: 'phone_call_initiated', category: 'communication', description: 'Usuario inicia una llamada', parameters: ['phone_number', 'service_name'], isMicroConversion: false, isKeyEvent: true, phase: 'PHASE_3.2' }, 'booking_initiated': { name: 'booking_initiated', category: 'booking', description: 'Usuario inicia una reserva', parameters: ['booking_id', 'service_name', 'service_price', 'guest_count', 'booking_date'], isMicroConversion: false, isKeyEvent: false, phase: 'PHASE_3.3' }, 'booking_completed': { name: 'booking_completed', category: 'booking', description: 'Usuario completa una reserva', parameters: ['booking_id', 'service_name', 'service_price', 'guest_count', 'booking_date', 'transaction_id'], isMicroConversion: false, isKeyEvent: true, phase: 'PHASE_3.3' }, 'purchase': { name: 'purchase', category: 'commerce', description: 'Compra completada', parameters: ['transaction_id', 'value', 'currency', 'service_name', 'items'], isMicroConversion: false, isKeyEvent: true, phase: 'PHASE_3.3' } }; const Utils = { getUTMParameters: function() { const params = {}; const urlParams = new URLSearchParams(window.location.search); const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; utmKeys.forEach(key => { if (urlParams.has(key)) { params[key] = urlParams.get(key); } }); return params; }, extractServiceName: function(text) { if (!text) return 'unknown_service'; return text.toLowerCase().trim().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '').substring(0, 50); }, getDeviceInfo: function() { return { is_mobile: /Mobile|Android|iPhone/.test(navigator.userAgent), browser: this.getBrowser(), os: this.getOS() }; }, getBrowser: function() { if (navigator.userAgent.indexOf('Chrome') > -1) return 'Chrome'; if (navigator.userAgent.indexOf('Safari') > -1) return 'Safari'; if (navigator.userAgent.indexOf('Firefox') > -1) return 'Firefox'; return 'Other'; }, getOS: function() { if (navigator.userAgent.indexOf('Win') > -1) return 'Windows'; if (navigator.userAgent.indexOf('Mac') > -1) return 'MacOS'; if (navigator.userAgent.indexOf('Linux') > -1) return 'Linux'; if (navigator.userAgent.indexOf('Android') > -1) return 'Android'; if (navigator.userAgent.indexOf('iPhone') > -1) return 'iOS'; return 'Other'; }, log: function(message, data = null) { if (!GA4_CONFIG.enableConsoleLogging) return; const timestamp = new Date().toISOString(); if (data) { console.log(`[GA4 ${timestamp}] ${message}`, data); } else { console.log(`[GA4 ${timestamp}] ${message}`); } }, isValidEvent: function(eventName) { return eventName in EVENT_REGISTRY; } }; const GA4Tracker = { init: function() { Utils.log('Inicializando GA4 Tracking System v' + GA4_CONFIG.version); if (typeof gtag === 'undefined') { Utils.log('ERROR: gtag no está disponible'); return false; } this.trackPageViewEnhanced(); this.trackServiceButtons(); this.trackPageExit(); Utils.log('✅ GA4 Event Tracking System inicializado correctamente'); return true; }, trackPageViewEnhanced: function() { const utmParams = Utils.getUTMParameters(); const eventData = { event_category: EVENT_REGISTRY['page_view_enhanced'].category, page_title: document.title, page_path: window.location.pathname }; Object.assign(eventData, utmParams); gtag('event', 'page_view_enhanced', eventData); Utils.log('📄 Page View Enhanced registrado', eventData); }, trackServiceButtons: function() { const self = this; const utmParams = Utils.getUTMParameters(); const serviceLinks = document.querySelectorAll('a[href*="utm_campaign"]'); if (serviceLinks.length === 0) { Utils.log('⚠️ No se encontraron botones de servicio con parámetros UTM'); return; } Utils.log(`ℹ️ Encontrados ${serviceLinks.length} botones de servicio para rastrear`); serviceLinks.forEach((link, index) => { link.addEventListener('click', function(e) { const buttonText = this.innerText || this.textContent || 'Unknown'; const href = this.getAttribute('href') || ''; const serviceName = Utils.extractServiceName(buttonText); const urlParams = new URLSearchParams(href.split('?')[1]); const eventData = { event_category: 'service_inquiry', event_label: buttonText, service_name: serviceName, button_position: index + 1, button_text: buttonText, href: href, page_path: window.location.pathname, timestamp: new Date().toISOString() }; ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(param => { if (urlParams.has(param)) { eventData[param] = urlParams.get(param); } }); gtag('event', 'service_button_click', eventData); Utils.log('🎯 Service Button Click registrado', eventData); }); }); }, trackPageExit: function() { let pageStartTime = Date.now(); window.addEventListener('beforeunload', () => { const timeOnPage = Math.round((Date.now() - pageStartTime) / 1000); const eventData = { event_category: 'engagement', time_on_page: timeOnPage, page_path: window.location.pathname }; gtag('event', 'page_exit', eventData); Utils.log('👋 Page Exit registrado', eventData); }); }, trackEvent: function(eventName, eventData = {}) { if (!Utils.isValidEvent(eventName)) { Utils.log(`⚠️ Evento no registrado: ${eventName}`); return false; } const eventRegistry = EVENT_REGISTRY[eventName]; const finalData = { event_category: eventRegistry.category, ...eventData, timestamp: new Date().toISOString() }; gtag('event', eventName, finalData); Utils.log(`✨ Evento registrado: ${eventName}`, finalData); return true; }, setUserProperty: function(propertyName, value) { gtag('set', {'user_properties': {[propertyName]: value}}); Utils.log(`👤 User property: ${propertyName} = ${value}`); }, getAvailableEvents: function() { return Object.keys(EVENT_REGISTRY); }, getEventInfo: function(eventName) { return EVENT_REGISTRY[eventName] || null; }, debugInfo: function() { console.group('GA4 System Debug Info'); console.log('Config:', GA4_CONFIG); console.log('Available Events:', Object.keys(EVENT_REGISTRY)); console.log('UTM Parameters:', Utils.getUTMParameters()); console.log('Device Info:', Utils.getDeviceInfo()); console.groupEnd(); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { GA4Tracker.init(); }); } else { GA4Tracker.init(); } window.GA4Tracker = GA4Tracker; window.GA4_CONFIG = GA4_CONFIG; (function(){const e={measurementId:'G-0PKFN3PBS2',v:'1.0.0'},t={service_button_click:{name:'service_button_click',category:'service_inquiry',phase:'PHASE_3.1'},form_submission:{name:'form_submission',category:'conversion',phase:'PHASE_3.2'},booking_completed:{name:'booking_completed',category:'booking',phase:'PHASE_3.3'},purchase:{name:'purchase',category:'commerce',phase:'PHASE_3.3'}};const n={getUTMParameters(){const e=new URLSearchParams(window.location.search),n={};return['utm_source','utm_medium','utm_campaign'].forEach(t=>{e.has(t)&&(n[t]=e.get(t))}),n},log(e){console.log(`[GA4 v${t.version}] ${e}`)}};const o={init(){if('undefined'==typeof gtag)return!1;this.trackServiceButtons(),console.log('[GA4] ✅ GA4 Event Tracking System inicializado'),!0},trackServiceButtons(){const e=document.querySelectorAll('a[href*="utm_campaign"]');e.length>0&&e.forEach((e,t)=>{e.addEventListener('click',()=>{const i=new URLSearchParams(e.href.split('?')[1]);gtag('event','service_button_click',{service_name:e.textContent,utm_campaign:i.get('utm_campaign'),button_index:t})})})},trackEvent(e,n={}){t[e]&>ag('event',e,{...n,timestamp:new Date().toISOString()})}};'loading'===document.readyState?document.addEventListener('DOMContentLoaded',()=>{o.init()}):o.init(),window.GA4Tracker=o,window.GA4_CONFIG=e,window.EVENT_REGISTRY=t,console.log('[GA4] Sistema disponible como window.GA4Tracker')})(); Utils.log('GA4 Tracking System disponible'); })();

★★★★★
"From the airport pickup to the last dinner, everything was flawless. Chef Silva made our anniversary unforgettable."
— Google Review · 5.0
