tracking-crm-core
Version:
Framework simplificado y robusto de tracking CRM - Sistema modular para tracking de visitantes, sesiones, eventos y captura de leads optimizado para navegadores
252 lines (251 loc) • 8.21 kB
JavaScript
/**
* TRACKING CRM FRAMEWORK v2.1 - SIMPLIFICADO
* Framework robusto de tracking para navegadores
*
* @version 2.1.0
* @description Framework modular para tracking de visitantes, sesiones y leads
* @author Innova Marketing
*/
// Variables globales
let currentConfig = null;
let currentSession = null;
let eventBuffer = [];
let isInitialized = false;
// Utilidades básicas
const isBrowser = typeof window !== 'undefined';
const generateUUID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
const getDeviceInfo = () => {
if (!isBrowser) {
return {
type: 'unknown',
os: 'unknown',
browser: 'unknown',
screenResolution: 'unknown',
viewportSize: 'unknown',
userAgent: 'unknown',
language: 'unknown',
timezone: 'unknown'
};
}
const userAgent = navigator.userAgent;
const viewport = `${window.innerWidth}x${window.innerHeight}`;
const screen = `${window.screen.width}x${window.screen.height}`;
return {
type: /Mobile|Android|iPhone|iPad/.test(userAgent) ? 'mobile' : 'desktop',
os: /Windows/.test(userAgent) ? 'Windows' : /Mac/.test(userAgent) ? 'macOS' : /Linux/.test(userAgent) ? 'Linux' : 'unknown',
browser: /Chrome/.test(userAgent) ? 'Chrome' : /Firefox/.test(userAgent) ? 'Firefox' : /Safari/.test(userAgent) ? 'Safari' : 'unknown',
screenResolution: screen,
viewportSize: viewport,
userAgent,
language: navigator.language || 'unknown',
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'unknown'
};
};
const getVisitorId = () => {
if (!isBrowser)
return generateUUID();
let visitorId = localStorage.getItem('tracking_visitor_id');
if (!visitorId) {
visitorId = generateUUID();
localStorage.setItem('tracking_visitor_id', visitorId);
}
return visitorId;
};
const sendToEndpoint = async (endpoint, data) => {
if (!endpoint)
return false;
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
return response.ok;
}
catch (error) {
console.error('Error sending to endpoint:', error);
return false;
}
};
// Funciones principales del framework
export const initTracker = async (businessId, config = {}) => {
if (!isBrowser)
return;
currentConfig = {
businessId,
environment: 'production',
endpoints: {
visitorTracking: 'https://n8n.innovamarketing.uy/webhook/visitor-tracking',
leadCapture: 'https://n8n.innovamarketing.uy/webhook/lead-capture',
eventTracking: 'https://n8n.innovamarketing.uy/webhook/event-tracking',
...config.endpoints
},
debug: {
enabled: false,
verbose: false,
logToConsole: false,
...config.debug
},
timing: {
heartbeatInterval: 30000,
inactivityTimeout: 300000,
scrollThrottle: 1000,
eventBufferSize: 10,
...config.timing
},
...config
};
// Crear nueva sesión
currentSession = {
sessionId: generateUUID(),
visitorId: getVisitorId(),
businessId,
startTime: new Date().toISOString(),
lastActivity: new Date().toISOString(),
pageViews: 1,
events: [],
deviceInfo: getDeviceInfo()
};
isInitialized = true;
// Enviar inicio de sesión
if (currentConfig.endpoints?.visitorTracking) {
await sendToEndpoint(currentConfig.endpoints.visitorTracking, {
session: currentSession,
events: [],
deviceInfo: currentSession.deviceInfo,
pageInfo: {
url: window.location.href,
title: document.title,
referrer: document.referrer
},
userBehavior: {
sessionDuration: 0,
pageViews: 1,
eventsCount: 0
}
});
}
if (currentConfig.debug?.enabled) {
console.log('✅ Tracking inicializado:', { businessId, sessionId: currentSession.sessionId });
}
};
export const trackEvent = (eventType, eventName, eventData = {}) => {
if (!isInitialized || !currentSession || !currentConfig)
return;
const event = {
eventType,
eventName,
eventData,
timestamp: new Date().toISOString(),
pageUrl: window.location.href
};
currentSession.events.push(event);
currentSession.lastActivity = new Date().toISOString();
eventBuffer.push(event);
if (currentConfig.debug?.enabled) {
console.log('📊 Evento trackeado:', event);
}
// Enviar buffer si está lleno
if (eventBuffer.length >= (currentConfig.timing?.eventBufferSize || 10)) {
flushEvents();
}
};
export const captureLead = async (leadData) => {
if (!isInitialized || !currentSession || !currentConfig)
return false;
const enrichedLead = {
...leadData,
sessionId: currentSession.sessionId,
visitorId: currentSession.visitorId,
businessId: currentConfig.businessId,
timestamp: new Date().toISOString(),
pageUrl: window.location.href,
deviceInfo: currentSession.deviceInfo,
sessionData: {
duration: Date.now() - new Date(currentSession.startTime).getTime(),
pageViews: currentSession.pageViews,
eventsCount: currentSession.events.length
}
};
// Trackear evento de lead
trackEvent('conversion', 'lead_captured', leadData);
// Enviar lead
if (currentConfig.endpoints?.leadCapture) {
const success = await sendToEndpoint(currentConfig.endpoints.leadCapture, enrichedLead);
if (currentConfig.debug?.enabled) {
console.log(success ? '✅ Lead capturado' : '❌ Error capturando lead', enrichedLead);
}
return success;
}
return false;
};
export const getTrackingStatus = () => {
return {
isInitialized,
businessId: currentConfig?.businessId,
sessionId: currentSession?.sessionId,
visitorId: currentSession?.visitorId,
eventsCount: currentSession?.events.length || 0,
lastActivity: currentSession?.lastActivity
};
};
const flushEvents = async () => {
if (!currentConfig?.endpoints?.eventTracking || eventBuffer.length === 0)
return;
const eventsToSend = [...eventBuffer];
eventBuffer = [];
await sendToEndpoint(currentConfig.endpoints.eventTracking, {
sessionId: currentSession?.sessionId,
visitorId: currentSession?.visitorId,
businessId: currentConfig.businessId,
events: eventsToSend,
timestamp: new Date().toISOString()
});
};
export const cleanupTracker = () => {
if (eventBuffer.length > 0) {
flushEvents();
}
currentConfig = null;
currentSession = null;
eventBuffer = [];
isInitialized = false;
};
// Funciones de conveniencia
export const trackPageView = (url) => {
trackEvent('navigation', 'page_view', { url: url || window.location.href });
};
export const trackClick = (element, data) => {
trackEvent('interaction', 'click', { element, ...data });
};
export const trackConversion = (type, value, data) => {
trackEvent('conversion', type, { value, ...data });
};
// Exponer funciones de debug en desarrollo
if (isBrowser && typeof window !== 'undefined') {
window.trackingCrmCore = {
getStatus: getTrackingStatus,
trackEvent,
captureLead,
flushEvents
};
}
// Exportaciones por defecto
export default {
initTracker,
trackEvent,
captureLead,
getTrackingStatus,
trackPageView,
trackClick,
trackConversion,
cleanupTracker
};