UNPKG

boomerangjs

Version:

boomerang always comes back, except when it hits something

484 lines (425 loc) 18.2 kB
/* eslint-disable max-len */ /** * Captures session IDs and campaign information from third party analytic vendors * installed on the same page. * * Third party analytics vendors currently supported: * * * Google Analytics * * Adobe Analytics (formerly Omniture Sitecatalyst) * * IBM Digital Analytics (formerly Coremetrics) * * ## Beacon Parameters * * This plugin adds the following parameters to the beacon: * * * `tp.ga.clientid`: Google Analytics [clientID](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id) (unique id per visitor) * * `tp.ga.utm_source`: Google Analytics [Campaign source](https://support.google.com/analytics/answer/1033863?hl=en) * * `tp.ga.utm_medium`: Google Analytics [Campaign medium](https://support.google.com/analytics/answer/1033863?hl=en) * * `tp.ga.utm_term`: Google Analytics [Campaign term](https://support.google.com/analytics/answer/1033863?hl=en) * * `tp.ga.utm_content`: Google Analytics [Campaign content](https://support.google.com/analytics/answer/1033863?hl=en) * * `tp.ga.utm_campaign`: Google Analytics [Campaign ID](https://support.google.com/analytics/answer/1033863?hl=en) * * `tp.aa.aid`: Adobe Analytics [Analytics ID (AID)](https://marketing.adobe.com/resources/help/en_US/reference/) * * `tp.aa.mid`: Adobe Analytics [Marketing ID (MID)](https://marketing.adobe.com/resources/help/en_US/reference/) * * `tp.aa.campaign`: Adobe Analytics [Campaign ID](https://marketing.adobe.com/resources/help/en_US/reference/) * * `tp.aa.purchaseid`: Adobe Analytics [Purchase ID](https://marketing.adobe.com/resources/help/en_US/reference/) * * `tp.ia.coreid`: IBM Analytics [Core ID (unique id per visitor)](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.mmc_vendor`: IBM Analytics [Campaign vendor](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.mmc_category`: IBM Analytics [Campaign category](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.mmc_placement`: IBM Analytics [Campaign placement](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.mmc_item`: IBM Analytics [Campaign item](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.sp_type`: IBM Analytics [Site promotion type](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.sp_promotion`: IBM Analytics [Site promotion](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.sp_link`: IBM Analytics [Site promotion link](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.re_version`: IBM Analytics [Real estate version](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.re_pagearea`: IBM Analytics [Real estate page area](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * `tp.ia.re_link`: IBM Analytics [Real estate link](https://www.ibm.com/support/knowledgecenter/en/SSPG9M/Analytics/kc_welcome_analytics.html) * * * @class BOOMR.plugins.TPAnalytics */ /* eslint-enable max-len */ /* eslint dot-notation:0 */ (function() { BOOMR = window.BOOMR || {}; BOOMR.plugins = BOOMR.plugins || {}; if (BOOMR.plugins.TPAnalytics) { return; } /** * Warning logging * * @param {string} msg Message */ function warn(msg) { BOOMR.warn(msg, "TPAnalytics"); } var impl = { complete: false, // collect client IDs, default to false // overridable by config clientids: false, // list of params we won't beacon // overridable by config dropParams: [], /** * Google Analytics * For Universal Analytics there is a function named "ga" which is used to retreive the clientid * ref: https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference * By default the clientid is stored in a cookie named "_ga" for 2 years * ref: https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id * For Classic GA, we'll parse the "__utma" cookie * * @return {Object} captured metrics */ googleAnalytics: function() { var data = {}; var w = BOOMR.window; var i, param, value, cid, trackers; // list of query params that we want to capture // ref: https://support.google.com/analytics/answer/1033863 var QUERY_PARAMS = ["utm_source", "utm_medium", "utm_term", "utm_content", "utm_campaign"]; if (impl.clientids) { // check for google's global "ga" function then get the clientId if (typeof w.ga === "function") { try { w.ga(function(tracker) { // tracker may be undefined if using GTM or named trackers if (tracker) { data["clientid"] = tracker.get("clientId"); } }); if (!data["clientid"] && typeof w.ga.getAll === "function") { // we may have named trackers, the clientid should be the same for all of them trackers = w.ga.getAll(); if (trackers && trackers.length > 0) { data["clientid"] = trackers[0].get("clientId"); } } } catch (err) { // "ga" wasn't google analytics? warn("googleAnalytics: " + err); } } // if we still don't have the clientid then fallback to cookie parsing if (!data["clientid"]) { // cookie parsing for "Universal" GA // _ga cookie format : GA1.2.XXXXXXXXXX.YYYYYYYYYY // where XXXXXXXXXX.YYYYYYYYYY is the clientid cid = BOOMR.utils.getCookie("_ga"); if (cid) { cid = cid.split("."); if (cid && cid.length === 4) { data["clientid"] = cid[2] + "." + cid[3]; } } else { // cookie parsing for "Classic" GA // __utma #########.XXXXXXXXXX.YYYYYYYYYY.##########.##########.# // where XXXXXXXXXX.YYYYYYYYYY is the clientid cid = BOOMR.utils.getCookie("__utma"); if (cid) { cid = cid.split("."); if (cid && cid.length === 6) { data["clientid"] = cid[1] + "." + cid[2]; } } } } } // capture paramters from the url that are relevant to google analytics for (i = 0; i < QUERY_PARAMS.length; i++) { param = QUERY_PARAMS[i]; value = BOOMR.utils.getQueryParamValue(param); if (value) { data[param] = value; } } return data; }, /** * Adobe Analytics * * AID: Analytics ID * MID: Marketing ID * Adobe's Marketing Cloud ID service uses a cookie named AMVC_#####@AdobeOrg, * where ##### is the site owner's "client id". It stores the valud of MID and optionally AID * If the site is not using Marketing Cloud, Analytics uses a legacy cookie named s_vi (AID) * If the s_vi cookie is unable to be set due to 3rd party cookie restrictions, * there is a fallback to a 1st party cookie named s_fid (AID). * * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_cookies.html * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_idvars.html * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_getmcvid.html * ref: https://marketing.adobe.com/resources/help/en_US/mcvid/mcvid_getanalyticsvisitorid.html * * eVars and props aren't captured * * @return {Object} captured metrics */ adobeAnalytics: function() { var data = {}; var aid, mid, amcv, visitor, m; var w = BOOMR.window; // regex that extracts the "organization id" from the AMCV_ cookie var AMCV_REGEX = /AMCV_([A-Z0-9]+)%40AdobeOrg/; // regex that extracts the id from the s_vi cookie (data between | and [) var SVI_REGEX = /\|([^\[]+)/; // check a few global vars to see if any Adobe products are installed // Adobe/Omniture's Data Tag Management global "_satellite" function // or Adobe/Omniture's Test&Target global "mboxCreate" function // or Adobe's Marketing Cloud ID Service's (AMCV) global "Visitor" function if (typeof w._satellite !== "undefined" || typeof w.mboxCreate === "function" || typeof w.Visitor === "function" || typeof w.s === "object") { if (impl.clientids) { // We'll try to fetch the "organization id" by using the global "s.visitor" object // "s" isn't reliably Adobe's SiteCatalyst object, the site owner might have renamed it if (typeof w.s === "object" && typeof w.s.visitor === "object" && typeof w.s.visitor.getAnalyticsVisitorID === "function" && typeof w.s.visitor.getMarketingCloudVisitorID === "function") { try { mid = w.s.visitor.getMarketingCloudVisitorID(); if (mid) { data["mid"] = mid; } aid = w.s.visitor.getAnalyticsVisitorID(); if (aid) { data["aid"] = w.s.visitor.getAnalyticsVisitorID(); } } catch (err) { warn("adobeAnalytics: " + err); } } else { // Try extracting the "organization id" from the AMCV_ cookie instead // the result of Vistor.getInstance should be the same as if we did have "s.visitor" amcv = AMCV_REGEX.exec(w.document.cookie); if (amcv && typeof w.Visitor === "function" && typeof w.Visitor.getInstance === "function") { // we might have more than one AMCV_ cookie but we just take the first match for now try { visitor = w.Visitor.getInstance(amcv[1] + "@AdobeOrg"); if (visitor && typeof visitor.getAnalyticsVisitorID === "function" && typeof visitor.getMarketingCloudVisitorID === "function") { mid = visitor.getMarketingCloudVisitorID(); if (mid) { data["mid"] = mid; } aid = visitor.getAnalyticsVisitorID(); if (aid) { data["aid"] = visitor.getAnalyticsVisitorID(); } } } catch (err) { warn("adobeAnalytics: " + err); } } else { // AMCV doesn't seem to be installed // the legacy session id is in a cookie named s_vi if the publisher is using a cname to collect metrics // ie. third party cookie but on the same root domain name aid = BOOMR.utils.getCookie("s_vi"); if (aid) { // s_vi will be in a format like this "[CS]v1|2B8147DA850785C4-6000010E2006DC28[CE]" // we need to extract the text between the pipe and the [CE] m = SVI_REGEX.exec(aid); if (m && m.length > 0) { aid = m[1]; } else { aid = ""; } } else { // fallback session id is a first party cookie named s_fid // eg. 6B280792FE0CFE56-162DA99B1988A2F8 aid = BOOMR.utils.getCookie("s_fid"); } if (aid) { data["aid"] = aid; } } } } if (typeof w.s === "object") { // get adobe campaign id // ref: https://marketing.adobe.com/resources/help/en_US/sc/implement/campaign.html if (typeof w.s.campaign === "string" && w.s.campaign) { data["campaign"] = w.s.campaign; } // get adobe purchase id // ref: https://marketing.adobe.com/resources/help/en_US/sc/implement/purchaseID.html if (typeof w.s.purchaseID === "string" && w.s.purchaseID) { data["purchaseid"] = w.s.purchaseID; } } } return data; }, /** * IBM Digital Analytics (CoreMetrics) * IBM provides a global cmRetrieveUserID function to get the "Core ID" ("Visitor ID") * The value is stored in a cookie named "CoreID6". Expiration: 15 years from date set. * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/AccessingIBMVisitorCookie.html * * off-site campaign information for "Marketing Management Center" (MMC), if available, is * stored in a query parameter named "cm_mmc" * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Analytics/MarketingReports/cm_mmcparameter.html * * on-site "Site Promotions Analysis", if available, is stored in a query paramter named "cm_sp" * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/impl_sitepromo.html * * on-site "Real Estate Analysis", if available, is stored in a query parameter named "cm_re" * ref: https://www.ibm.com/support/knowledgecenter/SSPG9M/Implementation/impl_realestate.html * * @return {Object} captured metrics */ ibmAnalytics: function() { var data = {}; var w = BOOMR.window; var param, m, i, k, regex, fieldnames; // regexs to parse the query parameters into their fields var metrics = { "cm_mmc": [ /([^&#]+?)-_-([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["mmc_vendor", "mmc_category", "mmc_placement", "mmc_item"] ], "cm_sp": [ /([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["sp_type", "sp_promotion", "sp_link"] ], "cm_re": [ /([^&#]+?)-_-([^&#]+?)-_-([^&#]+)/, ["re_version", "re_pagearea", "re_link"] ] }; if (impl.clientids && typeof w.cmRetrieveUserID === "function") { try { // in the current implementation of cmRetreiveUserID, the callback is called immediately (ie, not on a timer) w.cmRetrieveUserID(function(userid) { data["coreid"] = userid; }); } catch (err) { // not coremetrics or not properly setup warn("ibmAnalytics: " + err); } } // capture analytics data from url query params for (k in metrics) { if (metrics.hasOwnProperty(k)) { param = BOOMR.utils.getQueryParamValue(k); if (param) { regex = metrics[k][0]; fieldnames = metrics[k][1]; m = regex.exec(param); if (m && m.length > fieldnames.length) { for (i = 0; i < fieldnames.length; i++) { if (m[i + 1]) { // value might be "null" or "na" but send it anyways data[fieldnames[i]] = decodeURIComponent(m[i + 1]); } } } } } } return data; }, /** * Executed on `page_ready` and `xhr_load` */ done: function(edata, ename) { var vendor, data, key, beaconParam; var vendors = { "ga": this.googleAnalytics, "aa": this.adobeAnalytics, "ia": this.ibmAnalytics }; if (this.complete) { // we've already added data to the beacon return; } // // Don't add TPAnalytics to SPA Soft or XHR beacons -- // Only add to Page Load (ename: load) and SPA Hard (ename: xhr // and initiator: spa_hard) beacons. // if (ename !== "load" && (!edata || edata.initiator !== "spa_hard")) { return; } for (vendor in vendors) { data = vendors[vendor](); for (var key in data) { var beaconParam = "tp." + vendor + "." + key; if (!BOOMR.utils.inArray(beaconParam, this.dropParams)) { BOOMR.addVar(beaconParam, data[key], true); } } } this.complete = true; BOOMR.sendBeacon(); }, /* * Fired when the state changes from pre-render to visible */ prerenderToVisible: function() { // ensure we add our data to the beacon even if we had added it // during prerender (in case another beacon went out in between) this.complete = false; // add our data to the beacon this.done({}, "load"); } }; // // Exports // BOOMR.plugins.TPAnalytics = { /** * Initializes the plugin. * * @param {object} config Configuration * @param {boolean} config.TPAnalytics.clientids Whether or not to include * client IDs. * @param {string[]} config.TPAnalytics.dropParams Parameters to not include * on the beacon. * * @returns {@link BOOMR.plugins.TPAnalytics} The TPAnalytics plugin for chaining * @example * BOOMR.init({ * TPAnalytics: { * clientids: false * } * }); * @memberof BOOMR.plugins.TPAnalytics */ init: function(config) { BOOMR.utils.pluginConfig(impl, config, "TPAnalytics", ["clientids", "dropParams"]); if (!impl.initialized) { if (!BOOMR.utils.isArray(impl.dropParams)) { impl.dropParams = []; } // we'll add data to the beacon on whichever happens first BOOMR.subscribe("page_ready", impl.done, "load", impl); BOOMR.subscribe("xhr_load", impl.done, "xhr", impl); BOOMR.subscribe("prerender_to_visible", impl.prerenderToVisible, "load", impl); impl.initialized = true; } return this; }, /** * This plugin is always complete (ready to send a beacon) * * @returns {boolean} `true` * @memberof BOOMR.plugins.TPAnalytics */ is_complete: function() { return true; } }; }());