Files
4ventures-client-portal/public/_4v_attr.js

183 lines
6.3 KiB
JavaScript

/**
* 4Ventures — Universal Attribution Script v1.0
* Almacena parámetros UTM y Click IDs en cookie '_4v_attr' (90 días)
* e inyecta automáticamente en formularios y enlaces de WhatsApp.
*/
(function() {
'use strict';
var COOKIE_NAME = '_4v_attr';
var COOKIE_DAYS = 90;
function getQueryParam(name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
return results !== null ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
}
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();
}
var secure = location.protocol === 'https:' ? '; Secure' : '';
document.cookie = name + '=' + encodeURIComponent(JSON.stringify(value)) + expires + '; path=/; SameSite=Lax' + secure;
}
function getCookie(name) {
var nameEQ = name + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) {
try {
return JSON.parse(decodeURIComponent(c.substring(nameEQ.length, c.length)));
} catch (e) {
return null;
}
}
}
return null;
}
function detectReferrerSource() {
var ref = document.referrer.toLowerCase();
if (!ref) return { source: 'direct', medium: 'none' };
if (ref.indexOf('google.') !== -1) return { source: 'google', medium: 'organic' };
if (ref.indexOf('bing.') !== -1) return { source: 'bing', medium: 'organic' };
if (ref.indexOf('instagram.') !== -1) return { source: 'instagram', medium: 'social' };
if (ref.indexOf('facebook.') !== -1) return { source: 'facebook', medium: 'social' };
if (ref.indexOf('linkedin.') !== -1) return { source: 'linkedin', medium: 'social' };
if (ref.indexOf('tiktok.') !== -1) return { source: 'tiktok', medium: 'social' };
if (ref.indexOf('youtube.') !== -1) return { source: 'youtube', medium: 'social' };
try {
var url = new URL(ref);
return { source: url.hostname, medium: 'referral' };
} catch(e) {
return { source: 'referral', medium: 'referral' };
}
}
function captureAttribution() {
var utmSource = getQueryParam('utm_source');
var utmMedium = getQueryParam('utm_medium');
var utmCampaign = getQueryParam('utm_campaign');
var utmContent = getQueryParam('utm_content');
var utmTerm = getQueryParam('utm_term');
var gclid = getQueryParam('gclid');
var fbclid = getQueryParam('fbclid');
var ttclid = getQueryParam('ttclid');
var liFatId = getQueryParam('li_fat_id');
var clickId = gclid || fbclid || ttclid || liFatId || null;
var clickType = gclid ? 'gclid' : fbclid ? 'fbclid' : ttclid ? 'ttclid' : liFatId ? 'li_fat_id' : null;
var existingAttr = getCookie(COOKIE_NAME);
// Si hay nuevos parámetros en URL, actualizamos o creamos
if (utmSource || clickId) {
var newAttr = {
source: utmSource || (gclid ? 'google' : fbclid ? 'meta' : ttclid ? 'tiktok' : liFatId ? 'linkedin' : 'unknown'),
medium: utmMedium || (clickId ? 'cpc' : 'unknown'),
campaign: utmCampaign || '',
content: utmContent || '',
term: utmTerm || '',
click_id: clickId,
click_type: clickType,
landing_page: window.location.href,
referrer: document.referrer || '',
timestamp: new Date().toISOString()
};
setCookie(COOKIE_NAME, newAttr, COOKIE_DAYS);
return newAttr;
}
// Si no hay params y ya hay cookie previa, la mantenemos
if (existingAttr) {
return existingAttr;
}
// Si es primera visita sin parámetros, deducimos del referrer
var refData = detectReferrerSource();
var defaultAttr = {
source: refData.source,
medium: refData.medium,
campaign: '',
content: '',
term: '',
click_id: null,
click_type: null,
landing_page: window.location.href,
referrer: document.referrer || '',
timestamp: new Date().toISOString()
};
setCookie(COOKIE_NAME, defaultAttr, COOKIE_DAYS);
return defaultAttr;
}
function injectHiddenFields(attr) {
var forms = document.querySelectorAll('form');
var fieldKeys = ['source', 'medium', 'campaign', 'content', 'term', 'click_id', 'click_type', 'landing_page', 'referrer'];
forms.forEach(function(form) {
fieldKeys.forEach(function(key) {
var inputName = 'utm_' + key;
if (key === 'click_id' || key === 'click_type' || key === 'landing_page' || key === 'referrer') {
inputName = key;
}
var val = attr[key] || '';
var existing = form.querySelector('input[name="' + inputName + '"]');
if (existing) {
existing.value = val;
} else {
var input = document.createElement('input');
input.type = 'hidden';
input.name = inputName;
input.value = val;
form.appendChild(input);
}
});
});
}
function injectWhatsAppLinks(attr) {
if (!attr.click_id && !attr.source) return;
var links = document.querySelectorAll('a[href*="wa.me"], a[href*="api.whatsapp.com"]');
var tag = ' [ref:' + (attr.source || 'web') + (attr.click_id ? '-' + attr.click_id.substring(0, 8) : '') + ']';
links.forEach(function(link) {
var href = link.getAttribute('href');
if (href && href.indexOf('[ref:') === -1) {
if (href.indexOf('text=') !== -1) {
link.setAttribute('href', href + encodeURIComponent(tag));
} else {
var sep = href.indexOf('?') !== -1 ? '&' : '?';
link.setAttribute('href', href + sep + 'text=' + encodeURIComponent('Hola,' + tag));
}
}
});
}
// Inicialización inmediata y en DOMContentLoaded
var currentAttr = captureAttribution();
function init() {
injectHiddenFields(currentAttr);
injectWhatsAppLinks(currentAttr);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// Exponer API global
window._4v = {
getAttribution: function() { return currentAttr; },
refresh: captureAttribution,
inject: init
};
})();