Skip to content

Instantly share code, notes, and snippets.

@goranefbl
Last active June 4, 2024 22:04
Show Gist options
  • Save goranefbl/905c69ee6668a6f22d114b5fac75effa to your computer and use it in GitHub Desktop.
Save goranefbl/905c69ee6668a6f22d114b5fac75effa to your computer and use it in GitHub Desktop.
const wpgensUTMCookieManage = {
set: function (name, value, days) {
const expires = days ? new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString() : '';
const domain = this.getCleanHost(window.location.href) ? '; domain=' + this.getCleanHost(window.location.href) : '';
document.cookie = `${name}=${encodeURIComponent(value || '')}; expires=${expires}${domain}; path=/`;
},
get: function (name) {
const cookieArray = document.cookie.split(';');
for (let i = 0; i < cookieArray.length; i++) {
let cookie = cookieArray[i].trim();
if (cookie.indexOf(name + '=') === 0) {
return decodeURIComponent(cookie.substring(name.length + 1, cookie.length));
}
}
return null;
},
remove: function (name) {
document.cookie = name + '=; Max-Age=-99999999;';
},
getCleanHost: function (url) {
try {
// Create a URL object from the input URL string.
var parsedUrl = new URL(url);
// Extract the hostname from the URL object.
var hostname = parsedUrl.hostname;
// Remove 'www.' from the hostname if present.
var cleanHostname = hostname.replace(/^www\./, '');
return cleanHostname;
} catch (error) {
console.error('Error parsing URL: ', error);
return null;
}
},
};
(function () {
'use strict';
const clickIdentifiers = {
gclid: {
source: 'google',
medium: 'cpc',
},
dclid: {
source: 'google',
medium: 'cpm',
},
fbclid: {
source: 'facebook',
medium: 'cpc',
},
msclkid: {
source: 'bing',
medium: 'cpc',
},
gclsrc: {
source: 'google',
medium: 'cpc',
},
wbraid: {
source: 'google',
medium: 'cpc',
},
gbraid: {
source: 'google',
medium: 'cpc',
},
};
const searchEngines = {
google: {
p: 'q',
n: 'google',
regex: true,
},
'yahoo.com': {
p: 'p',
n: 'yahoo',
},
'msn.com': {
p: 'q',
n: 'msn',
},
'bing.com': {
p: 'q',
n: 'bing',
},
'duckduckgo.com': {
n: 'duckduckgo',
},
'daum.net': {
p: 'q',
n: 'daum',
},
'eniro.se': {
p: 'search_word',
n: 'eniro ',
},
'naver.com': {
p: 'query',
n: 'naver ',
},
'aol.com': {
p: 'q',
n: 'aol',
},
'lycos.com': {
p: 'q',
n: 'lycos',
},
'ask.com': {
p: 'q',
n: 'ask',
},
'altavista.com': {
p: 'q',
n: 'altavista',
},
'search.netscape.com': {
p: 'query',
n: 'netscape',
},
'cnn.com': {
p: 'query',
n: 'cnn',
},
'about.com': {
p: 'terms',
n: 'about',
},
'mamma.com': {
p: 'query',
n: 'mama',
},
'alltheweb.com': {
p: 'q',
n: 'alltheweb',
},
'voila.fr': {
p: 'rdata',
n: 'voila',
},
'search.virgilio.it': {
p: 'qs',
n: 'virgilio',
},
'baidu.com': {
p: 'wd',
n: 'baidu',
},
'alice.com': {
p: 'qs',
n: 'alice',
},
'yandex.com': {
p: 'text',
n: 'yandex',
},
'najdi.org.mk': {
p: 'q',
n: 'najdi',
},
'seznam.cz': {
p: 'q',
n: 'seznam',
},
'search.com': {
p: 'q',
n: 'search',
},
'brave.com': {
p: 'q',
n: 'brave',
},
'wp.pl': {
p: 'szukaj ',
n: 'wirtulana polska',
},
'online.onetcenter.org': {
p: 'qt',
n: 'o*net',
},
'szukacz.pl': {
p: 'q',
n: 'szukacz',
},
'yam.com': {
p: 'k',
n: 'yam',
},
'pchome.com': {
p: 'q',
n: 'pchome',
},
'kvasir.no': {
p: 'q',
n: 'kvasir',
},
'sesam.no': {
p: 'q',
n: 'sesam',
},
'ozu.es': {
p: 'q',
n: 'ozu ',
},
'terra.com': {
p: 'query',
n: 'terra',
},
'mynet.com': {
p: 'q',
n: 'mynet',
},
'ekolay.net': {
p: 'q',
n: 'ekolay',
},
'rambler.ru': {
p: 'words',
n: 'rambler',
},
};
const exceptionSLDs = ['co', 'com', 'gov', 'ac', 'org', 'edu', 'net', 'mil', 'sch', 'biz', 'eun', 'sci', 'nom', 'int'];
function getDomain_(url, ex_SDLs = exceptionSLDs) {
if (url === null) return null;
const getProtocol = () => window.location.protocol || 'https:';
url = url.substring(0, 4) == 'http' ? url : getProtocol() + '//' + url;
try {
const domain = new URL(url).hostname;
const sldSet = new Set(ex_SDLs);
const domainParts = domain.split('.');
if (sldSet.has(domainParts.slice(-2, -1)[0]) && domainParts.length >= 3) {
return domainParts.slice(-3).join('.');
}
return domainParts.slice(-2).join('.');
} catch (error) {
return null;
}
}
function getUtmTags() {
// get url parameters
const urlParams = new URLSearchParams(window.location.search);
// then turn them into an object with key: value pairs
const urlParamsObject = Object.fromEntries(urlParams);
const utmTagMap = {
utm_source: 'source',
utm_medium: 'medium',
utm_campaign: 'campaign',
utm_content: 'content',
utm_term: 'term',
};
let utmTagResults = {};
for (const key in urlParamsObject) {
if (utmTagMap.hasOwnProperty(key)) {
utmTagResults[utmTagMap[key]] = urlParamsObject[key];
}
}
return Object.keys(utmTagResults).length > 0 ? utmTagResults : null;
}
function getReferrer() {
const referrer = document.referrer;
const referringDomain = getDomain_(referrer, exceptionSLDs);
return referringDomain == null ? null : { medium: 'referral', source: referringDomain };
}
function getPaidUrlData(urlParamsObject, paidUrlParamsConfig) {
// Return first Click Id config found. There should never be more than one anyway.
for (const key in urlParamsObject) {
if (key in paidUrlParamsConfig) {
return paidUrlParamsConfig[key];
}
}
// If no Click Id is found, return null
return null;
}
function getSearchEngineData(referringDomain, urlParamsObject, searchEngineConfig) {
if (referringDomain == null) return null;
if (searchEngineConfig.hasOwnProperty(referringDomain)) {
let returnData = {
source: searchEngineConfig[referringDomain]['n'],
medium: 'organic',
};
const search_p = searchEngineConfig[referringDomain]['p'];
if (urlParamsObject.hasOwnProperty(search_p)) {
returnData['term'] = urlParamsObject[search_p];
}
return returnData;
}
// This bit takes only those searchEngineConfigs where regex == true
// if referring domain isn't otherwise found, we will match against regex, but only then
const filteredSearchEngineConfig = Object.keys(searchEngineConfig).reduce((result, key) => {
if (searchEngineConfig[key]['regex']) {
result[key] = searchEngineConfig[key];
}
return result;
}, {});
for (const key in filteredSearchEngineConfig) {
let safeKey = key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
let regex = new RegExp(safeKey);
if (regex.test(referringDomain)) {
return {
source: searchEngineConfig[key]['n'],
medium: 'organic',
};
}
}
return null;
}
function getDevice() {
const userAgent = navigator.userAgent;
const isMobile = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
const isTablet = /iPad|Android.*Tablet|Kindle|Tablet/i.test(userAgent);
// Check if Facebook App
if (!isMobile && /FBAN|FBAV/i.test(userAgent)) {
isMobile = true;
}
let type = 'desktop';
if (isMobile) {
type = 'mobile';
}
if (isTablet) {
type = 'tablet';
}
const dataBrowsers = [
{ name: 'Chrome', value: 'Chrome', version: 'Chrome' },
{ name: 'Firefox', value: 'Firefox', version: 'Firefox' },
{ name: 'Safari', value: 'Safari', version: 'Version' },
{ name: 'Internet Explorer', value: 'MSIE', version: 'MSIE' },
{ name: 'Opera', value: 'Opera', version: 'Opera' },
{ name: 'BlackBerry', value: 'CLDC', version: 'CLDC' },
{ name: 'Mozilla', value: 'Mozilla', version: 'Mozilla' },
];
const browser = getBrowser(userAgent, dataBrowsers);
return { type, browser };
}
function getBrowser(agentString, browsers) {
for (let i = 0; i < browsers.length; i++) {
const browser = browsers[i];
const regex = new RegExp(browser.value, 'i');
if (regex.test(agentString)) {
const versionRegex = new RegExp(`${browser.version}[- /:;]([\\d._]+)`, 'i');
const matches = agentString.match(versionRegex);
let version = matches && matches[1] ? matches[1].split(/[._]+/).join('.') : '0';
return {
name: browser.name,
version: parseFloat(version),
};
}
}
return { name: 'unknown', version: 0 };
}
function getTrafficSource() {
// get url parameters
const urlParams = new URLSearchParams(window.location.search);
// then turn them into an object with key: value pairs
const urlParamsObject = Object.fromEntries(urlParams);
// this bit strips the protocol away from referrer, since psl doesn't want that
const referrer = document.referrer;
// get only the top level domain of referrer
const referringDomain = getDomain_(referrer, exceptionSLDs);
// Is it direct
var direct = referrer.length === 0;
// Is it internal, just return cookie.
var internal = direct ? false : referrer.indexOf(wpgens_utm.homeUrl) === 0;
if (internal || direct) {
const cookie = JSON.parse(wpgensUTMCookieManage.get('wpg_traffic'));
if (cookie) {
return cookie;
}
}
// checks for click identifiers in url parameters, and if present, results in cpc/cpm
const paidUrlData = getPaidUrlData(urlParamsObject, clickIdentifiers);
// checks referring domain for common search engines, and when found, results in organic
const searchEngineData = getSearchEngineData(referringDomain, urlParamsObject, searchEngines);
const queryString = new URLSearchParams(window.location.search);
// Custom extended query params
const customParams = {};
if (Array.isArray(wpgens_utm.trackingParams) && wpgens_utm.trackingParams.length > 0) {
wpgens_utm.trackingParams.forEach((key) => {
const value = queryString.get(key);
if (value !== null) {
customParams[key] = decodeURIComponent(value);
}
});
}
return {
lpt: new Date().toISOString(),
lp: typeof window.location.pathname !== 'undefined' ? window.location.pathname : '/',
utm_tags: getUtmTags(),
url_params: Object.keys(urlParamsObject).length > 0 ? urlParamsObject : null,
paid_url_data: paidUrlData,
organic_search_data: searchEngineData,
referral_data: getReferrer(),
custom_params: customParams,
device: getDevice(),
};
}
function wpgensUTMManageCookies() {
try {
const source = getTrafficSource();
const existingData = wpgensUTMCookieManage.get('wpg_traffic');
if (JSON.stringify(existingData) !== JSON.stringify(source)) {
wpgensUTMCookieManage.set('wpg_traffic', JSON.stringify(source), wpgens_utm.cookieTime || 7);
}
return source;
} catch (e) {
console.log(e);
}
}
function getFirstPage() {
if (!wpgensUTMCookieManage.get('wpg_first')) {
wpgensUTMCookieManage.set('wpg_first', JSON.stringify(getTrafficSource()), 90);
}
}
const data = {
traffic: wpgensUTMManageCookies(),
fl: getFirstPage(),
};
console.log(data);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment