Last active
November 14, 2024 08:35
-
-
Save idarek/9ade69ac2a2ef00d98ab950426af5791 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* https://go.tacodewolff.nl/minify */ | |
enScroll=!1,enFdl=!1,extCurrent=void 0,filename=void 0,targetText=void 0,splitOrigin=void 0;const lStor=localStorage,sStor=sessionStorage,doc=document,docEl=document.documentElement,docBody=document.body,docLoc=document.location,w=window,s=screen,nav=navigator||{},extensions=["pdf","xls","xlsx","doc","docx","txt","rtf","csv","exe","key","pps","ppt","pptx","7z","pkg","rar","gz","zip","avi","mov","mp4","mpe","mpeg","wmv","mid","midi","mp3","wav","wma"];function a(e,t,n,o){const j="G-XXXXXXXXXX",r=()=>Math.floor(Math.random()*1e9)+1,c=()=>Math.floor(Date.now()/1e3),F=()=>(sStor._p||(sStor._p=r()),sStor._p),E=()=>r()+"."+c(),_=()=>(lStor.cid_v4||(lStor.cid_v4=E()),lStor.cid_v4),m=lStor.getItem("cid_v4"),v=()=>m?void 0:enScroll==!0?void 0:"1",p=()=>(sStor.sid||(sStor.sid=c()),sStor.sid),O=()=>{if(!sStor._ss)return sStor._ss="1",sStor._ss;if(sStor.getItem("_ss")=="1")return void 0},a="1",g=()=>{if(sStor.sct)if(enScroll==!0)return sStor.sct;else x=+sStor.getItem("sct")+ +a,sStor.sct=x;else sStor.sct=a;return sStor.sct},i=docLoc.search,b=new URLSearchParams(i),h=["q","s","search","query","keyword"],y=h.some(e=>i.includes("&"+e+"=")||i.includes("?"+e+"=")),u=()=>y==!0?"view_search_results":enScroll==!0?"scroll":enFdl==!0?"file_download":"page_view",f=()=>enScroll==!0?"90":void 0,C=()=>{if(u()=="view_search_results"){for(let e of b)if(h.includes(e[0]))return e[1]}else return void 0},d=encodeURIComponent,k=e=>{let t=[];for(let n in e)e.hasOwnProperty(n)&&e[n]!==void 0&&t.push(d(n)+"="+d(e[n]));return t.join("&")},A=!1,S="https://www.google-analytics.com/g/collect",M=k({v:"2",tid:j,_p:F(),sr:(s.width*w.devicePixelRatio+"x"+s.height*w.devicePixelRatio).toString(),ul:(nav.language||void 0).toLowerCase(),cid:_(),_fv:v(),_s:"1",dl:docLoc.origin+docLoc.pathname+i,dt:doc.title||void 0,dr:doc.referrer||void 0,sid:p(),sct:g(),seg:"1",en:u(),"epn.percent_scrolled":f(),"ep.search_term":C(),"ep.file_extension":e||void 0,"ep.file_name":t||void 0,"ep.link_text":n||void 0,"ep.link_url":o||void 0,_ss:O(),_dbg:A?1:void 0}),l=S+"?"+M;if(nav.sendBeacon)nav.sendBeacon(l);else{let e=new XMLHttpRequest;e.open("POST",l,!0)}}a();function sPr(){return(docEl.scrollTop||docBody.scrollTop)/((docEl.scrollHeight||docBody.scrollHeight)-docEl.clientHeight)*100}doc.addEventListener("scroll",sEv,{passive:!0});function sEv(){const e=sPr();if(e<90)return;enScroll=!0,a(),doc.removeEventListener("scroll",sEv,{passive:!0}),enScroll=!1}document.addEventListener("DOMContentLoaded",function(){let e=document.getElementsByTagName("a");for(let t=0;t<e.length;t++)if(e[t].getAttribute("href")!=null){const n=e[t].getAttribute("href"),s=n.substring(n.lastIndexOf("/")+1),o=s.split(".").pop();(e[t].hasAttribute("download")||extensions.includes(o))&&e[t].addEventListener("click",fDl,{passive:!0})}});function fDl(e){enFdl=!0;const t=e.currentTarget.getAttribute("href"),n=t.substring(t.lastIndexOf("/")+1),s=n.split(".").pop(),o=n.replace("."+s,""),i=e.currentTarget.text,r=t.replace(docLoc.origin,"");a(s,o,i,r),enFdl=!1} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Version 1.10.200923 | |
// Changelog: | |
// 1.10 | |
// - added ability to track `<a href` links to files with specified extensions and all these links where there is a `download` attribute specified independently of the extension of the file. | |
// | |
// 1.09.1 | |
// - minor changes of single quote in code (') to double quote ("). | |
// 1.09 | |
// - add listener for 90% scroll event. When user scrol to 90%+ of the page then script is fired again with scroll even and then (listener) terminates. | |
// - Specified global parameters and small tweak in search event. | |
// 1.08 | |
// - replaced VAR with LET and moved new URLSearchParams, as caused issues when minified | |
// - changed Minified version from minify-js.com to go.tacodewolff.nl/minify as caused issues with higher number of new users than users | |
// 1.07 | |
// - added event parameter (search_term) when tracking search via view_search_results event | |
// -- commented gtmId as currently not in use, hidden from minified version | |
// 1.06 | |
// - added event identification when page view is a search to set as view_search_results, in other case page_view | |
// 1.05 | |
// - Added _fv (first_visit indicator) based on cid_v4 in local storage for identification of returning users | |
// - Corrected (sr) screen resolution retection to include device Pixel ration (like Retina) | |
// - gtm - value convert to lower case | |
// - gtm - Google Tag Manager (GTM) Hash Info. If the current hit is coming was generated from GTM, it will contain a hash of current GTM/GTAG config | |
// 1.04 | |
// - start new session (_ss) only when it is real new session (store session in sessionStorage); revert cid generation to previous method and store under cid_v4 to do not cause an issue when using minimal UA(v3) with this code. | |
// 1.03 | |
// - split cid generation into two parts and combine at later stage | |
// 1.02 | |
// - corrected generation of cid | |
// 1.01 | |
// - changed method for generating _p, cid & sid | |
// 1.00 | |
// - first release | |
enScroll = false; | |
enFdl = false; | |
extCurrent = undefined; | |
filename = undefined; | |
targetText = undefined; | |
splitOrigin = undefined; | |
const lStor = localStorage; | |
const sStor = sessionStorage; | |
const doc = document; | |
const docEl = document.documentElement; | |
const docBody = document.body; | |
const docLoc = document.location; | |
const w = window; | |
const s = screen; | |
const nav = navigator || {}; | |
const extensions = ["pdf", "xls", "xlsx", "doc", "docx", "txt", "rtf", "csv", "exe", "key", "pps", "ppt", "pptx", "7z", "pkg", "rar", "gz", "zip", "avi", "mov", "mp4", "mpe", "mpeg", "wmv", "mid", "midi", "mp3", "wav", "wma"]; | |
function a(extCurrent, filename, targetText, splitOrigin) { | |
// debug options to clean cache | |
// localStorage.clear(); | |
// sessionStorage.clear(); | |
const trackingId = "G-XXXXXXXXXX"; // set here your Measurement ID for GA4 / Stream ID | |
// gmt > If the current hit is coming was generated from GTM, it will contain a hash of current GTM/GTAG config, example: 2oear0 | |
// Currently not in use, leave XXXXXX , under investigation | |
// let gtmId = "XXXXXX"; | |
// if (gtmId == "XXXXXX") { | |
// let gtmId = undefined; | |
// } | |
// else { | |
// let gtmId = gtmId.toLowerCase(); | |
// } | |
// 10-ish digit number generator | |
const generateId = () => Math.floor(Math.random() * 1000000000) + 1; | |
// UNIX datetime generator | |
const dategenId = () => Math.floor(Date.now() / 1000); | |
const _pId = () => { | |
if (!sStor._p) { | |
sStor._p = generateId(); | |
} | |
return sStor._p; | |
}; | |
const generatecidId = () => generateId() + "." + dategenId(); | |
const cidId = () => { | |
if (!lStor.cid_v4) { | |
lStor.cid_v4 = generatecidId(); | |
} | |
return lStor.cid_v4; | |
}; | |
const cidCheck = lStor.getItem("cid_v4"); | |
const _fvId = () => { | |
if(cidCheck) { | |
return undefined; | |
} | |
else if(enScroll==true) { | |
return undefined; | |
} | |
else { | |
return "1"; | |
} | |
}; | |
const sidId = () => { | |
if (!sStor.sid) { | |
sStor.sid = dategenId(); | |
} | |
return sStor.sid; | |
}; | |
const _ssId = () => { | |
if (!sStor._ss) { | |
sStor._ss = "1"; | |
return sStor._ss; | |
} | |
else if(sStor.getItem("_ss") == "1") { | |
return undefined; | |
} | |
}; | |
const generatesctId = "1"; | |
const sctId = () => { | |
if (!sStor.sct) { | |
sStor.sct = generatesctId; | |
} | |
else if(enScroll==true) { | |
return sStor.sct; | |
} | |
else { | |
x = +sStor.getItem("sct") + +generatesctId; | |
sStor.sct = x; | |
} | |
return sStor.sct; | |
}; | |
// Default GA4 Search Term Query Parameter: q,s,search,query,keyword | |
const searchString = docLoc.search; | |
const searchParams = new URLSearchParams(searchString); | |
//const searchString = "?search1=test&query1=1234&s=dsf"; // test search string | |
const sT = ["q", "s", "search", "query", "keyword"]; | |
const sR = sT.some(si => searchString.includes("&"+si+"=") || searchString.includes("?"+si+"=")); | |
const eventId = () => { | |
if (sR == true) { | |
return "view_search_results"; | |
} | |
else if (enScroll == true) { | |
return "scroll"; | |
} | |
else if (enFdl == true) { | |
return "file_download"; | |
} | |
else { | |
return "page_view"; | |
} | |
}; | |
const eventParaId = () => { | |
if(enScroll==true) { | |
return "90"; | |
} | |
else { | |
return undefined; | |
} | |
}; | |
// get search_term | |
const searchId = () => { | |
if (eventId() == "view_search_results") { | |
//Iterate the search parameters. | |
for (let p of searchParams) { | |
//console.log(p); // for debuging | |
if (sT.includes(p[0])) { | |
return p[1]; | |
} | |
} | |
} | |
else { | |
return undefined; | |
} | |
}; | |
const encode = encodeURIComponent; | |
const serialize = (obj) => { | |
let str = []; | |
for (let p in obj) { | |
if (obj.hasOwnProperty(p)) { | |
if(obj[p] !== undefined) { | |
str.push(encode(p) + "=" + encode(obj[p])); | |
} | |
} | |
} | |
return str.join("&"); | |
}; | |
const debug = false; // enable analytics debuging | |
// url | |
const url = "https://www.google-analytics.com/g/collect"; | |
// payload | |
const data = serialize({ | |
v: "2", // Measurement Protocol Version 2 for GA4 | |
tid: trackingId, // Measurement ID for GA4 or Stream ID | |
//gtm: gtmId, // Google Tag Manager (GTM) Hash Info. If the current hit is coming was generated from GTM, it will contain a hash of current GTM/GTAG config (not in use, currently under investigation) | |
_p: _pId(), // random number, hold in sessionStorage, unknown use | |
sr: (s.width * w.devicePixelRatio+"x"+s.height * w.devicePixelRatio).toString(), // Screen Resolution | |
ul: (nav.language || undefined).toLowerCase(), // User Language | |
cid: cidId(), // client ID, hold in localStorage | |
_fv: _fvId(), // first_visit, identify returning users based on existance of client ID in localStorage | |
_s: "1", // session hits counter | |
dl: docLoc.origin + docLoc.pathname + searchString, // Document location | |
dt: doc.title || undefined, // document title | |
dr: doc.referrer || undefined, // document referrer | |
sid: sidId(), // session ID random generated, hold in sessionStorage | |
sct: sctId(), // session count for a user, increase +1 in new interaction | |
seg: "1", // session engaged (interacted for at least 10 seconds), assume yes | |
en: eventId(), // event like page_view, view_search_results or scroll | |
"epn.percent_scrolled": eventParaId(),// event parameter, used for scroll event | |
"ep.search_term": searchId(), // search_term reported for view_search_results from search parameter | |
"ep.file_extension": extCurrent || undefined, | |
"ep.file_name": filename || undefined, | |
"ep.link_text": targetText || undefined, | |
"ep.link_url": splitOrigin || undefined, | |
_ss: _ssId(), // session_start, new session start | |
_dbg: debug ? 1 : undefined, // console debug | |
}); | |
const fullurl = (url+"?"+data); | |
// for debug purposes | |
// console.log(data); | |
// console.log(url, data); | |
// console.log(fullurl); | |
if(nav.sendBeacon) { | |
nav.sendBeacon(fullurl); | |
} else { | |
let xhr = new XMLHttpRequest(); | |
xhr.open("POST", (fullurl), true); | |
} | |
} | |
a(); | |
// Scroll Percent | |
function sPr() { | |
return (docEl.scrollTop||docBody.scrollTop) / ((docEl.scrollHeight||docBody.scrollHeight) - docEl.clientHeight) * 100; | |
} | |
// add scroll listener | |
doc.addEventListener("scroll", sEv, { passive: true }); | |
// scroll Event | |
function sEv() { | |
const percentage = sPr(); | |
if (percentage < 90) { | |
return; | |
} | |
enScroll = true; | |
// fire analytics script | |
a(); | |
// remove scroll listener | |
doc.removeEventListener("scroll", sEv, { passive: true }); | |
enScroll = false; | |
} | |
// file download listener | |
document.addEventListener("DOMContentLoaded", function() { | |
let Anchors = document.getElementsByTagName("a"); | |
for (let i = 0; i < Anchors.length; i++) { | |
if (Anchors[i].getAttribute("href") != null) { | |
const url = Anchors[i].getAttribute("href"); | |
const file = url.substring(url.lastIndexOf("/") + 1); | |
const ext = file.split(".").pop(); | |
/* if any anchor got download attribute, add event listener */ | |
/* and if any anchor have acceptable extension */ | |
if (Anchors[i].hasAttribute("download") || extensions.includes(ext)) { | |
Anchors[i].addEventListener("click", fDl, { passive: true }); | |
} | |
} | |
} | |
}); | |
// file download Event | |
function fDl(e) { | |
enFdl = true; | |
const urlCurrent = e.currentTarget.getAttribute("href"); | |
const fileCurrent = urlCurrent.substring(urlCurrent.lastIndexOf("/") + 1); | |
const extCurrent = fileCurrent.split(".").pop(); | |
const filename = fileCurrent.replace("." + extCurrent, ""); | |
const targetText = e.currentTarget.text; | |
const splitOrigin = urlCurrent.replace(docLoc.origin, ""); | |
// fire analytics script | |
a(extCurrent, filename, targetText, splitOrigin); | |
enFdl = false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The session hit counter
_s
is wrong as well - this should increase with each recorded event.Again, "session" here means the same thing as the
_p
page ID, so it's literally just a local variable that increments with each event:I tested the original GA script's behavior again, and this appears to be how it works. (whether for
page_view
or other events.)