diff --git a/Traffic Source Tracker GTM Container.json b/Traffic Source Tracker GTM Container.json new file mode 100644 index 0000000..b0cd09c --- /dev/null +++ b/Traffic Source Tracker GTM Container.json @@ -0,0 +1,175 @@ +{ + "exportFormatVersion": 2, + "exportTime": "2018-10-24 14:25:34", + "containerVersion": { + "path": "accounts/152155806/containers/10246515/versions/0", + "accountId": "152155806", + "containerId": "10246515", + "containerVersionId": "0", + "container": { + "path": "accounts/152155806/containers/10246515", + "accountId": "152155806", + "containerId": "10246515", + "name": "Traffic Source Cookie Library", + "publicId": "GTM-WZKBQNM", + "usageContext": [ + "WEB" + ], + "fingerprint": "1540391097055", + "tagManagerUrl": "https://tagmanager.google.com/#/container/accounts/152155806/containers/10246515/workspaces?apiLink=container" + }, + "tag": [ + { + "accountId": "152155806", + "containerId": "10246515", + "tagId": "2", + "name": "JS - Traffic Source Initiator", + "type": "html", + "parameter": [ + { + "type": "TEMPLATE", + "key": "html", + "value": "" + }, + { + "type": "BOOLEAN", + "key": "supportDocumentWrite", + "value": "false" + } + ], + "fingerprint": "1540390347969", + "firingTriggerId": [ + "5", + "6" + ], + "tagFiringOption": "ONCE_PER_EVENT" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "tagId": "1", + "name": "Traffic Source Tracker Library", + "type": "html", + "parameter": [ + { + "type": "TEMPLATE", + "key": "html", + "value": "" + }, + { + "type": "BOOLEAN", + "key": "supportDocumentWrite", + "value": "false" + } + ], + "fingerprint": "1540390870257", + "firingTriggerId": [ + "2147479553" + ], + "tagFiringOption": "ONCE_PER_LOAD" + } + ], + "trigger": [ + { + "accountId": "152155806", + "containerId": "10246515", + "triggerId": "5", + "name": "Dom Ready - All Pages", + "type": "DOM_READY", + "fingerprint": "1540390288643" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "triggerId": "6", + "name": "Dom Ready - Referrer Does not Contain Self Domain", + "type": "DOM_READY", + "filter": [ + { + "type": "MATCH_REGEX", + "parameter": [ + { + "type": "TEMPLATE", + "key": "arg0", + "value": "{{Referrer}}" + }, + { + "type": "TEMPLATE", + "key": "arg1", + "value": "marketlytics.com" + }, + { + "type": "BOOLEAN", + "key": "ignore_case", + "value": "true" + }, + { + "type": "BOOLEAN", + "key": "negate", + "value": "true" + } + ] + } + ], + "fingerprint": "1540390342688" + } + ], + "variable": [ + { + "accountId": "152155806", + "containerId": "10246515", + "variableId": "1", + "name": "Traffic Source Cookie", + "type": "k", + "parameter": [ + { + "type": "BOOLEAN", + "key": "decodeCookie", + "value": "false" + }, + { + "type": "TEMPLATE", + "key": "name", + "value": "traffic_src" + } + ], + "fingerprint": "1540390942201", + "formatValue": {} + } + ], + "builtInVariable": [ + { + "accountId": "152155806", + "containerId": "10246515", + "type": "PAGE_URL", + "name": "Page URL" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "type": "PAGE_HOSTNAME", + "name": "Page Hostname" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "type": "PAGE_PATH", + "name": "Page Path" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "type": "REFERRER", + "name": "Referrer" + }, + { + "accountId": "152155806", + "containerId": "10246515", + "type": "EVENT", + "name": "Event" + } + ], + "fingerprint": "0", + "tagManagerUrl": "https://tagmanager.google.com/#/versions/accounts/152155806/containers/10246515/versions/0?apiLink=version" + } +} \ No newline at end of file diff --git a/library_initiator.js b/library_initiator.js new file mode 100644 index 0000000..2532457 --- /dev/null +++ b/library_initiator.js @@ -0,0 +1,22 @@ + diff --git a/trafficSourceTracker.js b/trafficSourceTracker.js index 79c841e..f727490 100644 --- a/trafficSourceTracker.js +++ b/trafficSourceTracker.js @@ -5,9 +5,9 @@ # This project is free software, distributed under the MIT license. # MarketLytics offers digital analytics consulting and integration services. */ -(function (window, document) -{ - +(function (window, document){ + window.dataLayer=window.dataLayer||[]; + //including javascript in web page when JSON is undifined(first time), creating json source attribute, appending in head tag. if(typeof JSON === 'undefined') { var fileref = document.createElement('script'); fileref.setAttribute('type', 'text/javascript'); @@ -15,12 +15,11 @@ document.getElementsByTagName("head")[0].appendChild(fileref); } - // set cookie name + //cookieStrKey is used to set cookie name. var cookieStrKey = 'traffic_src'; - //inject global function for cookie retrieval - window.getTrafficSrcCookie = function() - { + //inject global function for cookie retrieval. + window.getTrafficSrcCookie = function(){ var cookies = document.cookie.split(';'); var cookieObj; for(var i = 0; i < cookies.length; i++) { @@ -29,6 +28,7 @@ break; } } + //cookie values are copied into cookieObj and return in JSON format. if(cookieObj) { cookieObj = cookieObj.substring(cookieObj.indexOf('=') + 1, cookieObj.length); @@ -38,33 +38,37 @@ }; var utils = { - getParameterByName: function(url, name) - { + /*function is use to compare two parameters and return value if valid, + *it looks for name(any variable) in url and returns its docoded value if found in url. + */ + getParameterByName: function(url, name){ name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"); var results = regex.exec(url); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); }, - getKeywords: function(url) - { + getKeywords: function(url){ + //return empty sting if url is empty or direct, which indicate no keywords used. if(url === '' || url === '(direct)') return ''; + //we compare pre-define searchEngines object to find relavent keywords in url. var searchEngines = 'daum:q eniro:search_word naver:query pchome:q images.google:q google:q yahoo:p yahoo:q msn:q bing:q aol:query aol:q lycos:q lycos:query ask:q cnn:query virgilio:qs baidu:wd baidu:word alice:qs yandex:text najdi:q seznam:q rakuten:qt biglobe:q goo.ne:MT search.smt.docomo:MT onet:qt onet:q kvasir:q terra:query rambler:query conduit:q babylon:q search-results:q avg:q comcast:q incredimail:q startsiden:q go.mail.ru:q centrum.cz:q 360.cn:q sogou:query tut.by:query globo:q ukr:q so.com:q haosou.com:q auone:q'.split(' '); for(var i = 0; i < searchEngines.length; i++) - { + {//set source of traffic to search engine var val = searchEngines[i].split(':'); var name = val[0]; var queryParam = val[1]; - if(url.indexOf(name) >= 0){ - // set source of traffic to search engine - cookieObj.ga_source = name; - if(this.getParameterByName(url, queryParam) !== '') { + if(url.indexOf(name) >= 0) { + cookieObj.ga_source = name; // set source to searchEngine name. + if(this.getParameterByName(url, queryParam) !== ''){ + //return value of queryParamter, extracted keyowrd. return this.getParameterByName(url, queryParam); } } } - + + //if url matches exact case of below regix we return not provided, which means campaign data is not present. var google = new RegExp('^https?:\/\/(www\.)?google(\.com?)?(\.[a-z]{2}t?)?\/?$', 'i'); var yahoo = new RegExp('^https?:\/\/(r\.)?search\.yahoo\.com\/?[^?]*$', 'i'); var bing = new RegExp('^https?:\/\/(www\.)?bing\.com\/?$', 'i'); @@ -75,8 +79,8 @@ return ''; }, - getMedium: function(ccokieObj) - { + //function to set medium based on different params. + getMedium: function(ccokieObj){ if(cookieObj.ga_medium !== '') return cookieObj.ga_medium; if(cookieObj.ga_gclid !== '') return 'cpc'; @@ -90,13 +94,13 @@ return 'referral'; }, - getDateAfterYears: function(years) - { + //getting date and time for define number of years from today. + getDateAfterYears: function(years){ return new Date(new Date().getTime() + (years * 365 * 24 * 60 * 60 * 1000)); }, - getHostname: function(url) - { + //checking url to return approprate hostname. + getHostname: function(url){ var re = new RegExp('^(https:\/\/|http:\/\/)?([^\/?:#]+)'); var match = re.exec(url)[2]; if(match !== null) { @@ -105,6 +109,9 @@ return ''; }, + /*function that waits for the givent condition to be true, + * Checks the condition every 100 milisecond till timeout variable is wqual to 0 + */ waitLoad: function(condition, callback) { var timeout = 100; var poll = function() { @@ -120,10 +127,24 @@ }, 100); }; poll(); + }, + + removeSubdomain : function (host) { + var firstTLDs = "ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|be|bf|bg|bh|bi|bj|bm|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|cl|cm|cn|co|cr|cu|cv|cw|cx|cz|de|dj|dk|dm|do|dz|ec|ee|eg|es|et|eu|fi|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|im|in|io|iq|ir|is|it|je|jo|jp|kg|ki|km|kn|kp|kr|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|na|nc|ne|nf|ng|nl|no|nr|nu|nz|om|pa|pe|pf|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|yt".split('|'); + var secondTLDs = "com|edu|gov|net|mil|org|nom|sch|caa|res|off|gob|int|tur|ip6|uri|urn|asn|act|nsw|qld|tas|vic|pro|biz|adm|adv|agr|arq|art|ato|bio|bmd|cim|cng|cnt|ecn|eco|emp|eng|esp|etc|eti|far|fnd|fot|fst|g12|ggf|imb|ind|inf|jor|jus|leg|lel|mat|med|mus|not|ntr|odo|ppg|psc|psi|qsl|rec|slg|srv|teo|tmp|trd|vet|zlg|web|ltd|sld|pol|fin|k12|lib|pri|aip|fie|eun|sci|prd|cci|pvt|mod|idv|rel|sex|gen|nic|abr|bas|cal|cam|emr|fvg|laz|lig|lom|mar|mol|pmn|pug|sar|sic|taa|tos|umb|vao|vda|ven|mie|北海道|和歌山|神奈川|鹿児島|ass|rep|tra|per|ngo|soc|grp|plc|its|air|and|bus|can|ddr|jfk|mad|nrw|nyc|ski|spy|tcm|ulm|usa|war|fhs|vgs|dep|eid|fet|fla|flå|gol|hof|hol|sel|vik|cri|iwi|ing|abo|fam|gok|gon|gop|gos|aid|atm|gsm|sos|elk|waw|est|aca|bar|cpa|jur|law|sec|plo|www|bir|cbg|jar|khv|msk|nov|nsk|ptz|rnd|spb|stv|tom|tsk|udm|vrn|cmw|kms|nkz|snz|pub|fhv|red|ens|nat|rns|rnu|bbs|tel|bel|kep|nhs|dni|fed|isa|nsn|gub|e12|tec|орг|обр|упр|alt|nis|jpn|mex|ath|iki|nid|gda|inc".split('|'); + host = host.replace(/^www\./, ''); + var parts = host.split('.'); + while (parts.length > 3) { + parts.shift(); + } + if (parts.length === 3 && ((parts[1].length > 2 && parts[2].length > 2) || (secondTLDs.indexOf(parts[1]) === -1) && firstTLDs.indexOf(parts[2]) === -1)) { + parts.shift(); + } + return parts.join('.'); } - }; + }; - // query params keys to look for to get utm data + // query params keys to look for to get utm data. var parameters = [{ key: 'utm_source', label: 'ga_source', @@ -131,11 +152,11 @@ }, { key: 'utm_medium', label: 'ga_medium', - required: true + required: false }, { key: 'utm_campaign', label: 'ga_campaign', - required: true + required: false }, { key: 'utm_content', label: 'ga_content', @@ -146,10 +167,16 @@ required: false }]; + //code starts from here, above declare functions are used here. var cookieObj = {}; - var setCookie = function() - { + /* gclid = checks for presensce of adword. + * function below sets all the required values (traffic detials) in an object name 'cookiObj', + * which is later converted to JSON and saved as cookie, + * function is used to save values in cookie defined above. + */ + + var setCookie = function(getGaClient){ cookieObj.ga_gclid = utils.getParameterByName(document.location.href, 'gclid'); var ignoreUtmParameters = false; @@ -165,38 +192,98 @@ cookieObj[parameters[i]['label']] = value; } - if (cookieObj.ga_gclid !== '' && cookieObj.ga_source === '') - { + //source is assumed to be google when gclid is present and source is NULL + if (cookieObj.ga_gclid !== '' && cookieObj.ga_source === ''){ cookieObj.ga_source = 'google'; } - else if(ignoreUtmParameters) - { + //Checks if ignoreUtmParameters is true. + else if(ignoreUtmParameters){ + //Checks is referrer exists. if(document.referrer.indexOf(document.location.host) >= 0) return; - if(window.getTrafficSrcCookie() !== null && document.referrer === '') return; + + //Checks is Cookie already exists and also checks if referrer exists. + if(getTrafficSrcCookie() !== null && document.referrer === '') return; + //Set the default source value '(direct)'. cookieObj.ga_source = document.referrer !== '' ? document.referrer : '(direct)'; } + //Saves values in cookie object i.e 'cookieObj'. cookieObj.ga_keyword = cookieObj.ga_keyword === '' ? utils.getKeywords(cookieObj.ga_source) : cookieObj.ga_keyword; cookieObj.ga_medium = utils.getMedium(cookieObj); + //landing page is set to current page url. cookieObj.ga_landing_page = document.location.href; cookieObj.ga_source = utils.getHostname(cookieObj.ga_source); - cookieObj.ga_client_id = ga.getAll()[0].get('clientId'); + if (getGaClient) { + cookieObj.ga_client_id = ga.getAll()[0].get('clientId'); + } if(cookieObj.ga_source !== '') { + //coverting Javascript value under cookieObj to JSON String, cookieStr varaible is used to save data in cookie. var cookieStr = JSON.stringify(cookieObj); + //Creating cookie with expiry set for one year, can be accessed by function getTrafficSrcCookie(). document.cookie = cookieStrKey + '=; expires=' + new Date(-1); - document.cookie = cookieStrKey + '=' + cookieStr + '; expires=' + utils.getDateAfterYears(1) + '; path=/'; + document.cookie = cookieStrKey + '=' + cookieStr + '; expires=' + utils.getDateAfterYears(1) + '; path=/; domain=' + utils.removeSubdomain(location.hostname); } - + //Pushes event to dataLayer to prompt that cookies have been saved successfully. + dataLayer.push({'event':'trafficSrcCookieSet'}) + // Creates an event in jQuery on script ready. + if(jQuery){ + jQuery.event.trigger({ + type: "Traffic_Source_Ready_jQuery", + message: "Traffic Source Ready", + cookieData:getTrafficSrcCookie(), + time: new Date() + }); + } + if($){ + $.event.trigger({ + type: "Traffic_Source_Ready_$", + message: "Traffic Source Ready", + cookieData:getTrafficSrcCookie(), + time: new Date() + }); + } + + // Create the event + var event = new CustomEvent("Traffic_Source_Ready_Dom", { + type: "Traffic_Source_Ready", + message: "Traffic Source Ready", + cookieData:getTrafficSrcCookie(), + time: new Date() + }); + + // Dispatch/Trigger/Fire the event + document.dispatchEvent(event); + + cookieObj = {}; }; - utils.waitLoad(function() { - return typeof JSON !== 'undefined'; - }, function() { + var setTrafficSrcCookie = function(options) { + if (!options) { + options = {}; + } + utils.waitLoad(function() { - return typeof ga.getAll !== 'undefined'; - }, setCookie); - }); + //Checks if JSON Lib is included. + return typeof JSON !== 'undefined'; + }, function() { + if (options.getGaClient) { + //works when Analytics tracker(ga) exists on site, wait for some type before returing ga values and calling function setcookie. + utils.waitLoad(function() { + return typeof ga.getAll !== 'undefined'; + }, function() { + setCookie(true); + }); + return; + } + setCookie(false); + + }); + } -})(window, document) + window.trafficSrcCookie = { + setCookie: setTrafficSrcCookie, + getCookie: getTrafficSrcCookie + }; +})(window, document);