universal-analytics
Advanced tools
Comparing version 0.4.12 to 0.4.13
# History | ||
## 0.4.13 / 2017-03-29 | ||
- Added `screenview` method | ||
- Updated Readme | ||
## 0.4.12 / 2017-03-16 | ||
@@ -4,0 +9,0 @@ |
765
lib/index.js
@@ -16,3 +16,3 @@ | ||
function init (tid, cid, options) { | ||
return new Visitor(tid, cid, options); | ||
return new Visitor(tid, cid, options); | ||
} | ||
@@ -22,42 +22,42 @@ | ||
if (typeof tid === 'object') { | ||
options = tid; | ||
tid = cid = null; | ||
} else if (typeof cid === 'object') { | ||
options = cid; | ||
cid = null; | ||
} | ||
if (typeof tid === 'object') { | ||
options = tid; | ||
tid = cid = null; | ||
} else if (typeof cid === 'object') { | ||
options = cid; | ||
cid = null; | ||
} | ||
this._queue = []; | ||
this._queue = []; | ||
this.options = options || {}; | ||
this.options = options || {}; | ||
if(this.options.hostname) { | ||
config.hostname = this.options.hostname; | ||
} | ||
if(this.options.path) { | ||
config.path = this.options.path; | ||
} | ||
if(this.options.hostname) { | ||
config.hostname = this.options.hostname; | ||
} | ||
if(this.options.path) { | ||
config.path = this.options.path; | ||
} | ||
if (this.options.https) { | ||
var parsedHostname = url.parse(config.hostname); | ||
config.hostname = 'https://' + parsedHostname.host; | ||
} | ||
if (this.options.https) { | ||
var parsedHostname = url.parse(config.hostname); | ||
config.hostname = 'https://' + parsedHostname.host; | ||
} | ||
if(this.options.enableBatching !== undefined) { | ||
config.batching = options.enableBatching; | ||
} | ||
if(this.options.enableBatching !== undefined) { | ||
config.batching = options.enableBatching; | ||
} | ||
if(this.options.batchSize) { | ||
config.batchSize = this.options.batchSize; | ||
} | ||
if(this.options.batchSize) { | ||
config.batchSize = this.options.batchSize; | ||
} | ||
this._context = context || {}; | ||
this._persistentParams = persistentParams || {}; | ||
this._context = context || {}; | ||
this._persistentParams = persistentParams || {}; | ||
this.tid = tid || this.options.tid; | ||
this.cid = this._determineCid(cid, this.options.cid, (this.options.strictCidFormat !== false)); | ||
if(this.options.uid) { | ||
this.uid = this.options.uid; | ||
} | ||
this.tid = tid || this.options.tid; | ||
this.cid = this._determineCid(cid, this.options.cid, (this.options.strictCidFormat !== false)); | ||
if(this.options.uid) { | ||
this.uid = this.options.uid; | ||
} | ||
} | ||
@@ -70,27 +70,27 @@ | ||
this.tid = tid; | ||
this.options = options; | ||
this.tid = tid; | ||
this.options = options; | ||
var cookieName = (this.options || {}).cookieName || "_ga"; | ||
var cookieName = (this.options || {}).cookieName || "_ga"; | ||
return function (req, res, next) { | ||
return function (req, res, next) { | ||
req.visitor = module.exports.createFromSession(req.session); | ||
req.visitor = module.exports.createFromSession(req.session); | ||
if (req.visitor) return next(); | ||
if (req.visitor) return next(); | ||
var cid; | ||
if (req.cookies && req.cookies[cookieName]) { | ||
var gaSplit = req.cookies[cookieName].split('.'); | ||
cid = gaSplit[2] + "." + gaSplit[3]; | ||
} | ||
var cid; | ||
if (req.cookies && req.cookies[cookieName]) { | ||
var gaSplit = req.cookies[cookieName].split('.'); | ||
cid = gaSplit[2] + "." + gaSplit[3]; | ||
} | ||
req.visitor = init(tid, cid, options); | ||
req.visitor = init(tid, cid, options); | ||
if (req.session) { | ||
req.session.cid = req.visitor.cid; | ||
} | ||
if (req.session) { | ||
req.session.cid = req.visitor.cid; | ||
} | ||
next(); | ||
} | ||
next(); | ||
} | ||
} | ||
@@ -101,5 +101,5 @@ | ||
module.exports.createFromSession = function (session) { | ||
if (session && session.cid) { | ||
return init(this.tid, session.cid, this.options); | ||
} | ||
if (session && session.cid) { | ||
return init(this.tid, session.cid, this.options); | ||
} | ||
} | ||
@@ -111,375 +111,420 @@ | ||
debug: function (debug) { | ||
this.options.debug = arguments.length === 0 ? true : debug; | ||
this._log("Logging enabled") | ||
return this; | ||
}, | ||
debug: function (debug) { | ||
this.options.debug = arguments.length === 0 ? true : debug; | ||
this._log("Logging enabled") | ||
return this; | ||
}, | ||
reset: function () { | ||
this._context = null; | ||
return this; | ||
}, | ||
reset: function () { | ||
this._context = null; | ||
return this; | ||
}, | ||
set: function (key, value) { | ||
this._persistentParams = this._persistentParams || {}; | ||
this._persistentParams[key] = value; | ||
}, | ||
set: function (key, value) { | ||
this._persistentParams = this._persistentParams || {}; | ||
this._persistentParams[key] = value; | ||
}, | ||
pageview: function (path, hostname, title, params, fn) { | ||
pageview: function (path, hostname, title, params, fn) { | ||
if (typeof path === 'object' && path != null) { | ||
params = path; | ||
if (typeof hostname === 'function') { | ||
fn = hostname | ||
} | ||
path = hostname = title = null; | ||
} else if (typeof hostname === 'function') { | ||
fn = hostname | ||
hostname = title = null; | ||
} else if (typeof title === 'function') { | ||
fn = title; | ||
title = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
if (typeof path === 'object' && path != null) { | ||
params = path; | ||
if (typeof hostname === 'function') { | ||
fn = hostname | ||
} | ||
path = hostname = title = null; | ||
} else if (typeof hostname === 'function') { | ||
fn = hostname | ||
hostname = title = null; | ||
} else if (typeof title === 'function') { | ||
fn = title; | ||
title = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = this._translateParams(params); | ||
params = this._translateParams(params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params.dp = path || params.dp || this._context.dp; | ||
params.dh = hostname || params.dh || this._context.dh; | ||
params.dt = title || params.dt || this._context.dt; | ||
params.dp = path || params.dp || this._context.dp; | ||
params.dh = hostname || params.dh || this._context.dh; | ||
params.dt = title || params.dt || this._context.dt; | ||
this._tidyParameters(params); | ||
this._tidyParameters(params); | ||
if (!params.dp && !params.dl) { | ||
return this._handleError("Please provide either a page path (dp) or a document location (dl)", fn); | ||
} | ||
if (!params.dp && !params.dl) { | ||
return this._handleError("Please provide either a page path (dp) or a document location (dl)", fn); | ||
} | ||
return this._withContext(params)._enqueue("pageview", params, fn); | ||
}, | ||
return this._withContext(params)._enqueue("pageview", params, fn); | ||
}, | ||
event: function (category, action, label, value, params, fn) { | ||
screenview: function (screenName, appName, appVersion, appId, appInstallerId, params, fn) { | ||
if (typeof category === 'object' && category != null) { | ||
params = category; | ||
if (typeof action === 'function') { | ||
fn = action | ||
} | ||
category = action = label = value = null; | ||
} else if (typeof label === 'function') { | ||
fn = label; | ||
label = value = null; | ||
} else if (typeof value === 'function') { | ||
fn = value; | ||
value = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
if (typeof screenName === 'object' && screenName != null) { | ||
params = screenName; | ||
if (typeof appName === 'function') { | ||
fn = appName | ||
} | ||
screenName = appName = appVersion = appId = appInstallerId = null; | ||
} else if (typeof appName === 'function') { | ||
fn = appName | ||
appName = appVersion = appId = appInstallerId = null; | ||
} else if (typeof appVersion === 'function') { | ||
fn = appVersion; | ||
appVersion = appId = appInstallerId = null; | ||
} else if (typeof appId === 'function') { | ||
fn = appId; | ||
appId = appInstallerId = null; | ||
} else if (typeof appInstallerId === 'function') { | ||
fn = appInstallerId; | ||
appInstallerId = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = this._translateParams(params); | ||
params = this._translateParams(params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params.ec = category || params.ec || this._context.ec; | ||
params.ea = action || params.ea || this._context.ea; | ||
params.el = label || params.el || this._context.el; | ||
params.ev = value || params.ev || this._context.ev; | ||
params.p = params.p || params.dp || this._context.p || this._context.dp; | ||
params.cd = screenName || params.cd || this._context.cd; | ||
params.an = appName || params.an || this._context.an; | ||
params.av = appVersion || params.av || this._context.av; | ||
params.aid = appId || params.aid || this._context.aid; | ||
params.aiid = appInstallerId || params.aiid || this._context.aiid; | ||
delete params.dp; | ||
this._tidyParameters(params); | ||
this._tidyParameters(params); | ||
if (!params.ec || !params.ea) { | ||
return this._handleError("Please provide at least an event category (ec) and an event action (ea)", fn); | ||
} | ||
if (!params.cd || !params.an) { | ||
return this._handleError("Please provide at least a screen name (cd) and an app name (an)", fn); | ||
} | ||
return this._withContext(params)._enqueue("event", params, fn); | ||
}, | ||
return this._withContext(params)._enqueue("screenview", params, fn); | ||
}, | ||
transaction: function (transaction, revenue, shipping, tax, affiliation, params, fn) { | ||
if (typeof transaction === 'object') { | ||
params = transaction; | ||
if (typeof revenue === 'function') { | ||
fn = revenue | ||
} | ||
transaction = revenue = shipping = tax = affiliation = null; | ||
} else if (typeof revenue === 'function') { | ||
fn = revenue; | ||
revenue = shipping = tax = affiliation = null; | ||
} else if (typeof shipping === 'function') { | ||
fn = shipping; | ||
shipping = tax = affiliation = null; | ||
} else if (typeof tax === 'function') { | ||
fn = tax; | ||
tax = affiliation = null; | ||
} else if (typeof affiliation === 'function') { | ||
fn = affiliation; | ||
affiliation = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
event: function (category, action, label, value, params, fn) { | ||
params = this._translateParams(params); | ||
if (typeof category === 'object' && category != null) { | ||
params = category; | ||
if (typeof action === 'function') { | ||
fn = action | ||
} | ||
category = action = label = value = null; | ||
} else if (typeof label === 'function') { | ||
fn = label; | ||
label = value = null; | ||
} else if (typeof value === 'function') { | ||
fn = value; | ||
value = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = this._translateParams(params); | ||
params.ti = transaction || params.ti || this._context.ti; | ||
params.tr = revenue || params.tr || this._context.tr; | ||
params.ts = shipping || params.ts || this._context.ts; | ||
params.tt = tax || params.tt || this._context.tt; | ||
params.ta = affiliation || params.ta || this._context.ta; | ||
params.p = params.p || this._context.p || this._context.dp; | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
this._tidyParameters(params); | ||
params.ec = category || params.ec || this._context.ec; | ||
params.ea = action || params.ea || this._context.ea; | ||
params.el = label || params.el || this._context.el; | ||
params.ev = value || params.ev || this._context.ev; | ||
params.p = params.p || params.dp || this._context.p || this._context.dp; | ||
if (!params.ti) { | ||
return this._handleError("Please provide at least a transaction ID (ti)", fn); | ||
} | ||
delete params.dp; | ||
this._tidyParameters(params); | ||
return this._withContext(params)._enqueue("transaction", params, fn); | ||
}, | ||
if (!params.ec || !params.ea) { | ||
return this._handleError("Please provide at least an event category (ec) and an event action (ea)", fn); | ||
} | ||
return this._withContext(params)._enqueue("event", params, fn); | ||
}, | ||
item: function (price, quantity, sku, name, variation, params, fn) { | ||
if (typeof price === 'object') { | ||
params = price; | ||
if (typeof quantity === 'function') { | ||
fn = quantity | ||
} | ||
price = quantity = sku = name = variation = null; | ||
} else if (typeof quantity === 'function') { | ||
fn = quantity; | ||
quantity = sku = name = variation = null; | ||
} else if (typeof sku === 'function') { | ||
fn = sku; | ||
sku = name = variation = null; | ||
} else if (typeof name === 'function') { | ||
fn = name; | ||
name = variation = null; | ||
} else if (typeof variation === 'function') { | ||
fn = variation; | ||
variation = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = this._translateParams(params); | ||
transaction: function (transaction, revenue, shipping, tax, affiliation, params, fn) { | ||
if (typeof transaction === 'object') { | ||
params = transaction; | ||
if (typeof revenue === 'function') { | ||
fn = revenue | ||
} | ||
transaction = revenue = shipping = tax = affiliation = null; | ||
} else if (typeof revenue === 'function') { | ||
fn = revenue; | ||
revenue = shipping = tax = affiliation = null; | ||
} else if (typeof shipping === 'function') { | ||
fn = shipping; | ||
shipping = tax = affiliation = null; | ||
} else if (typeof tax === 'function') { | ||
fn = tax; | ||
tax = affiliation = null; | ||
} else if (typeof affiliation === 'function') { | ||
fn = affiliation; | ||
affiliation = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = this._translateParams(params); | ||
params.ip = price || params.ip || this._context.ip; | ||
params.iq = quantity || params.iq || this._context.iq; | ||
params.ic = sku || params.ic || this._context.ic; | ||
params.in = name || params.in || this._context.in; | ||
params.iv = variation || params.iv || this._context.iv; | ||
params.p = params.p || this._context.p || this._context.dp; | ||
params.ti = params.ti || this._context.ti; | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
this._tidyParameters(params); | ||
params.ti = transaction || params.ti || this._context.ti; | ||
params.tr = revenue || params.tr || this._context.tr; | ||
params.ts = shipping || params.ts || this._context.ts; | ||
params.tt = tax || params.tt || this._context.tt; | ||
params.ta = affiliation || params.ta || this._context.ta; | ||
params.p = params.p || this._context.p || this._context.dp; | ||
if (!params.ti) { | ||
return this._handleError("Please provide at least an item transaction ID (ti)", fn); | ||
} | ||
this._tidyParameters(params); | ||
return this._withContext(params)._enqueue("item", params, fn); | ||
if (!params.ti) { | ||
return this._handleError("Please provide at least a transaction ID (ti)", fn); | ||
} | ||
}, | ||
return this._withContext(params)._enqueue("transaction", params, fn); | ||
}, | ||
exception: function (description, fatal, params, fn) { | ||
if (typeof description === 'object') { | ||
params = description; | ||
if (typeof fatal === 'function') { | ||
fn = fatal; | ||
} | ||
description = fatal = null; | ||
} else if (typeof fatal === 'function') { | ||
fn = fatal; | ||
fatal = 0; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
item: function (price, quantity, sku, name, variation, params, fn) { | ||
if (typeof price === 'object') { | ||
params = price; | ||
if (typeof quantity === 'function') { | ||
fn = quantity | ||
} | ||
price = quantity = sku = name = variation = null; | ||
} else if (typeof quantity === 'function') { | ||
fn = quantity; | ||
quantity = sku = name = variation = null; | ||
} else if (typeof sku === 'function') { | ||
fn = sku; | ||
sku = name = variation = null; | ||
} else if (typeof name === 'function') { | ||
fn = name; | ||
name = variation = null; | ||
} else if (typeof variation === 'function') { | ||
fn = variation; | ||
variation = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = this._translateParams(params); | ||
params = this._translateParams(params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params.exd = description || params.exd || this._context.exd; | ||
params.exf = +!!(fatal || params.exf || this._context.exf); | ||
params.ip = price || params.ip || this._context.ip; | ||
params.iq = quantity || params.iq || this._context.iq; | ||
params.ic = sku || params.ic || this._context.ic; | ||
params.in = name || params.in || this._context.in; | ||
params.iv = variation || params.iv || this._context.iv; | ||
params.p = params.p || this._context.p || this._context.dp; | ||
params.ti = params.ti || this._context.ti; | ||
if (params.exf === 0) { | ||
delete params.exf; | ||
} | ||
this._tidyParameters(params); | ||
this._tidyParameters(params); | ||
if (!params.ti) { | ||
return this._handleError("Please provide at least an item transaction ID (ti)", fn); | ||
} | ||
return this._withContext(params)._enqueue("exception", params, fn); | ||
}, | ||
return this._withContext(params)._enqueue("item", params, fn); | ||
timing: function (category, variable, time, label, params, fn) { | ||
}, | ||
if (typeof category === 'object') { | ||
params = category; | ||
if (typeof variable === 'function') { | ||
fn = variable; | ||
} | ||
category = variable = time = label = null; | ||
} else if (typeof variable === 'function') { | ||
fn = variable; | ||
variable = time = label = null; | ||
} else if (typeof time === 'function') { | ||
fn = time; | ||
time = label = null; | ||
} else if (typeof label === 'function') { | ||
fn = label; | ||
label = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
exception: function (description, fatal, params, fn) { | ||
params = this._translateParams(params); | ||
if (typeof description === 'object') { | ||
params = description; | ||
if (typeof fatal === 'function') { | ||
fn = fatal; | ||
} | ||
description = fatal = null; | ||
} else if (typeof fatal === 'function') { | ||
fn = fatal; | ||
fatal = 0; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
params = this._translateParams(params); | ||
params.utc = category || params.utc || this._context.utc; | ||
params.utv = variable || params.utv || this._context.utv; | ||
params.utt = time || params.utt || this._context.utt; | ||
params.utl = label || params.utl || this._context.utl; | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
this._tidyParameters(params); | ||
params.exd = description || params.exd || this._context.exd; | ||
params.exf = +!!(fatal || params.exf || this._context.exf); | ||
return this._withContext(params)._enqueue("timing", params, fn); | ||
}, | ||
if (params.exf === 0) { | ||
delete params.exf; | ||
} | ||
this._tidyParameters(params); | ||
send: function (fn) { | ||
var self = this; | ||
var count = 1; | ||
var fn = fn || function () {}; | ||
self._log("Sending " + self._queue.length + " tracking call(s)"); | ||
return this._withContext(params)._enqueue("exception", params, fn); | ||
}, | ||
var test = function () { | ||
return self._queue.length > 0; | ||
} | ||
timing: function (category, variable, time, label, params, fn) { | ||
var getBody = function(params) { | ||
return params.map(function(x) { return querystring.stringify(x); }).join("\n"); | ||
} | ||
if (typeof category === 'object') { | ||
params = category; | ||
if (typeof variable === 'function') { | ||
fn = variable; | ||
} | ||
category = variable = time = label = null; | ||
} else if (typeof variable === 'function') { | ||
fn = variable; | ||
variable = time = label = null; | ||
} else if (typeof time === 'function') { | ||
fn = time; | ||
time = label = null; | ||
} else if (typeof label === 'function') { | ||
fn = label; | ||
label = null; | ||
} else if (typeof params === 'function') { | ||
fn = params; | ||
params = null; | ||
} | ||
var iterator = function (fn) { | ||
var params = []; | ||
params = this._translateParams(params); | ||
if(config.batching) { | ||
params = self._queue.splice(0, Math.min(self._queue.length, config.batchSize)); | ||
} else { | ||
params.push(self._queue.shift()); | ||
} | ||
params = _.extend({}, this._persistentParams || {}, params); | ||
var useBatchPath = params.length > 1; | ||
params.utc = category || params.utc || this._context.utc; | ||
params.utv = variable || params.utv || this._context.utv; | ||
params.utt = time || params.utt || this._context.utt; | ||
params.utl = label || params.utl || this._context.utl; | ||
var path = config.hostname + (useBatchPath ? config.batchPath :config.path); | ||
this._tidyParameters(params); | ||
self._log(count++ + ": " + JSON.stringify(params)); | ||
return this._withContext(params)._enqueue("timing", params, fn); | ||
}, | ||
var options = _.extend({}, self.options.requestOptions, { | ||
body: getBody(params), | ||
headers: self.options.headers || {} | ||
}); | ||
request.post(path, options, fn); | ||
} | ||
send: function (fn) { | ||
var self = this; | ||
var count = 1; | ||
var fn = fn || function () {}; | ||
self._log("Sending " + self._queue.length + " tracking call(s)"); | ||
async.whilst(test, iterator, function (err) { | ||
self._log("Finished sending tracking calls") | ||
fn.call(self, err || null, count - 1); | ||
}); | ||
var test = function () { | ||
return self._queue.length > 0; | ||
} | ||
}, | ||
var getBody = function(params) { | ||
return params.map(function(x) { return querystring.stringify(x); }).join("\n"); | ||
} | ||
_enqueue: function (type, params, fn) { | ||
var iterator = function (fn) { | ||
var params = []; | ||
if (typeof params === 'function') { | ||
fn = params; | ||
params = {}; | ||
} | ||
if(config.batching) { | ||
params = self._queue.splice(0, Math.min(self._queue.length, config.batchSize)); | ||
} else { | ||
params.push(self._queue.shift()); | ||
} | ||
params = this._translateParams(params) || {}; | ||
var useBatchPath = params.length > 1; | ||
_.extend(params, { | ||
v: config.protocolVersion, | ||
tid: this.tid, | ||
cid: this.cid, | ||
t: type | ||
}); | ||
if(this.uid) { | ||
params.uid = this.uid; | ||
} | ||
var path = config.hostname + (useBatchPath ? config.batchPath :config.path); | ||
this._queue.push(params); | ||
self._log(count++ + ": " + JSON.stringify(params)); | ||
if (this.options.debug) { | ||
this._checkParameters(params); | ||
} | ||
var options = _.extend({}, self.options.requestOptions, { | ||
body: getBody(params), | ||
headers: self.options.headers || {} | ||
}); | ||
this._log("Enqueued " + type + " (" + JSON.stringify(params) + ")"); | ||
request.post(path, options, fn); | ||
} | ||
if (fn) { | ||
this.send(fn); | ||
} | ||
async.whilst(test, iterator, function (err) { | ||
self._log("Finished sending tracking calls") | ||
fn.call(self, err || null, count - 1); | ||
}); | ||
return this; | ||
}, | ||
}, | ||
_enqueue: function (type, params, fn) { | ||
_handleError: function (message, fn) { | ||
this._log("Error: " + message) | ||
fn && fn.call(this, new Error(message)) | ||
return this; | ||
}, | ||
if (typeof params === 'function') { | ||
fn = params; | ||
params = {}; | ||
} | ||
params = this._translateParams(params) || {}; | ||
_.extend(params, { | ||
v: config.protocolVersion, | ||
tid: this.tid, | ||
cid: this.cid, | ||
t: type | ||
}); | ||
if(this.uid) { | ||
params.uid = this.uid; | ||
} | ||
_determineCid: function () { | ||
var args = Array.prototype.splice.call(arguments, 0); | ||
var id; | ||
var lastItem = args.length-1; | ||
var strict = args[lastItem]; | ||
if (strict) { | ||
for (var i = 0; i < lastItem; i++) { | ||
id = utils.ensureValidCid(args[i]); | ||
if (id !== false) return id; | ||
if (id != null) this._log("Warning! Invalid UUID format '" + args[i] + "'"); | ||
} | ||
} else { | ||
for (var i = 0; i < lastItem; i++) { | ||
if (args[i]) return args[i]; | ||
} | ||
} | ||
return uuid.v4(); | ||
}, | ||
this._queue.push(params); | ||
if (this.options.debug) { | ||
this._checkParameters(params); | ||
} | ||
_checkParameters: function (params) { | ||
for (var param in params) { | ||
if (config.acceptedParameters.indexOf(param) !== -1 || config.acceptedParametersRegex.filter(function (r) { | ||
return r.test(param); | ||
}).length) { | ||
continue; | ||
} | ||
this._log("Warning! Unsupported tracking parameter " + param + " (" + params[param] + ")"); | ||
} | ||
}, | ||
this._log("Enqueued " + type + " (" + JSON.stringify(params) + ")"); | ||
_translateParams: function (params) { | ||
if (fn) { | ||
this.send(fn); | ||
} | ||
return this; | ||
}, | ||
_handleError: function (message, fn) { | ||
this._log("Error: " + message) | ||
fn && fn.call(this, new Error(message)) | ||
return this; | ||
}, | ||
_determineCid: function () { | ||
var args = Array.prototype.splice.call(arguments, 0); | ||
var id; | ||
var lastItem = args.length-1; | ||
var strict = args[lastItem]; | ||
if (strict) { | ||
for (var i = 0; i < lastItem; i++) { | ||
id = utils.ensureValidCid(args[i]); | ||
if (id !== false) return id; | ||
if (id != null) this._log("Warning! Invalid UUID format '" + args[i] + "'"); | ||
} | ||
} else { | ||
for (var i = 0; i < lastItem; i++) { | ||
if (args[i]) return args[i]; | ||
} | ||
} | ||
return uuid.v4(); | ||
}, | ||
_checkParameters: function (params) { | ||
for (var param in params) { | ||
if (config.acceptedParameters.indexOf(param) !== -1 || config.acceptedParametersRegex.filter(function (r) { | ||
return r.test(param); | ||
}).length) { | ||
continue; | ||
} | ||
this._log("Warning! Unsupported tracking parameter " + param + " (" + params[param] + ")"); | ||
} | ||
}, | ||
_translateParams: function (params) { | ||
var translated = {}; | ||
@@ -496,22 +541,22 @@ for (var key in params) { | ||
_tidyParameters: function (params) { | ||
for (var param in params) { | ||
if (params[param] === null || params[param] === undefined) { | ||
delete params[param]; | ||
} | ||
} | ||
return params; | ||
}, | ||
_tidyParameters: function (params) { | ||
for (var param in params) { | ||
if (params[param] === null || params[param] === undefined) { | ||
delete params[param]; | ||
} | ||
} | ||
return params; | ||
}, | ||
_log: function (message) { | ||
this.options.debug && console.log("[universal-analytics] " + message); | ||
}, | ||
_log: function (message) { | ||
this.options.debug && console.log("[universal-analytics] " + message); | ||
}, | ||
_withContext: function (context) { | ||
var visitor = new Visitor(this.tid, this.cid, this.options, context, this._persistentParams); | ||
visitor._queue = this._queue; | ||
return visitor; | ||
} | ||
_withContext: function (context) { | ||
var visitor = new Visitor(this.tid, this.cid, this.options, context, this._persistentParams); | ||
visitor._queue = this._queue; | ||
return visitor; | ||
} | ||
@@ -518,0 +563,0 @@ |
{ | ||
"name": "universal-analytics", | ||
"version": "0.4.12", | ||
"version": "0.4.13", | ||
"description": "A node module for Google's Universal Analytics tracking", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
300
README.md
@@ -8,14 +8,27 @@ universal-analytics | ||
`universal-analytics` currently supports the following tracking features: | ||
[![Build Status](https://travis-ci.org/peaksandpies/universal-analytics.png?branch=master)](https://travis-ci.org/peaksandpies/universal-analytics) | ||
* Pageviews | ||
* Events | ||
* E-Commerce with transactions and items | ||
* Exceptions | ||
* User timings | ||
[![Build Status](https://travis-ci.org/peaksandpies/universal-analytics.png?branch=master)](https://travis-ci.org/peaksandpies/universal-analytics) | ||
# Table of Contents | ||
## Getting started | ||
- [Getting started](#getting-started) | ||
- [Tracking](#tracking) | ||
- [Pageviews](#pageview-tracking) | ||
- [Screenviews](#screenview-tracking) | ||
- [Events](#event-tracking) | ||
- [Exceptions](#exception-tracking) | ||
- [User timings](#user-timing-tracking) | ||
- [Transactions](#transaction-tracking) | ||
- [Transaction items](#transaction-item-tracking) | ||
- [Daisy-chaining tracking calls](#daisy-chaining-tracking-calls) | ||
- [Setting persistent parameters](#setting-persistent-parameters) | ||
- [Session-based identification](#session-based-identification) | ||
- [Debug mode](#debug-mode) | ||
- [Request Options](#request-options) | ||
- [Shortcuts](#shortcuts) | ||
- [Tests](#tests) | ||
# Getting started | ||
`universal-analytics` is installed and included like any other node module: | ||
@@ -77,2 +90,6 @@ | ||
# Tracking | ||
## Pageview tracking | ||
@@ -123,4 +140,38 @@ | ||
See also [a acceptable params](AcceptableParams.md). | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
## Screenview tracking | ||
Instead of pageviews app will want to track screenviews. | ||
```javascript | ||
visitor.screenview("Home Screen", "App Name").send() | ||
``` | ||
The following method signatures are available for #screenview: | ||
* `Visitor#screenview(screenName, appName)` | ||
* `Visitor#screenview(screenName, appName, callback)` | ||
* `Visitor#screenview(screenName, appName, appVersion)` | ||
* `Visitor#screenview(screenName, appName, appVersion, callback)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId, callback)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, callback)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, params)` | ||
* `Visitor#screenview(screenName, appName, appVersion, appId, appInstallerId, params, callback)` | ||
* `Visitor#screenview(params)` | ||
* `Visitor#screenview(params, callback)` | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
## Event tracking | ||
@@ -195,67 +246,10 @@ | ||
See also [a acceptable params](AcceptableParams.md). | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
### Daisy-chaining tracking calls | ||
We have seen basic daisy-chaining above when calling `send()` right after `pageview()` and `event()`: | ||
```javascript | ||
visitor.pageview("/").send() | ||
``` | ||
Every call of a tracking method returns a visitor instance you can re-use: | ||
```javascript | ||
visitor.pageview("/").pageview("/contact").send() | ||
``` | ||
## E-commerce tracking | ||
Granted, the chance of this example actually happening in practice might be rather low. | ||
However, `universal-analytics` is smart when it comes to daisy-chaining certain calls. In many cases, a `pageview()` call is instantly followed by an `event()` call to track some additional information about the current page. `universal-analytics` makes creating the connection between the two easy: | ||
```javascript | ||
visitor.pageview("/landing-page-1").event("Testing", "Button color", "Blue").send() | ||
``` | ||
This is the same as two distinct tracking calls. | ||
```javascript | ||
visitor.pageview("/landing-page-1").send() | ||
visitor.event("Testing", "Button color", "Blue", {p: "/landing-page-1"}).send() | ||
``` | ||
Daisy-chaining is context-aware and in this case placing the `event()` call right after the `pageview()` call results in the event being associated with the page path tracking in the `pageview()` call. Even though the attributes (`dp` and `p`) are different internally. | ||
It also works when using a callback since the `this` inside the callback will be the `universal-analytics` Visitor instance: | ||
```javascript | ||
visitor.pageview("/landing-page-1", function (err) { | ||
if (!err) { | ||
this.event("Testing", "Button color", "Blue").send() | ||
} | ||
}); | ||
``` | ||
More generally, the daisy-chaining context keeps all parameters from the previous call around. This means in a situation where similar tracking calls are necessary tracking is simplified: | ||
```javascript | ||
visitor | ||
.event({ec: "Mail Server", ea: "New Team Member Notification sent"}) | ||
.event({ea: "Invitation sent"}) | ||
.send(); | ||
``` | ||
In this example the event category ("Mail Server") is not repeated in the second tracking call. | ||
### Setting persistent parameters | ||
Some parameters should be in every tracking call, such as a user ID or custom dimensions that never or hardly change. For such situations a `#set(key, value)` method is available | ||
visitor.set("uid", "123456789") | ||
The uid parameter will be part of every tracking request of that visitor from now on. | ||
### E-commerce tracking | ||
E-commerce tracking in general is a bit more complex. It requires a combination of one call to the `transaction()` method and one or more calls to the `item()` method. | ||
@@ -329,6 +323,11 @@ | ||
See also [a acceptable params](AcceptableParams.md). | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
### Exception tracking | ||
## Exception tracking | ||
Exception tracking is a way to keep track of any sort of application errors and bugs with Google Analytics. Using it with this module is a way to capture server-side problems. | ||
@@ -358,6 +357,11 @@ | ||
See also [a acceptable params](AcceptableParams.md). | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
### User timing tracking | ||
## User timing tracking | ||
Tracking user timings is a way to capture time-based information similar to the page load speed data tracked automatically by Google Analytics. All arguments to this tracking method are optional, but a category, a variable and a time value should be provided. The time value should be provided in milliseconds. | ||
@@ -382,6 +386,144 @@ | ||
See also [a acceptable params](AcceptableParams.md). | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
## Session-based identification | ||
## Transaction tracking | ||
Transactions are the main tracking calls for ecommerce tracking | ||
```javascript | ||
visitor.transaction("123456", "449.99").send() | ||
``` | ||
The following method signatures are available for #transaction: | ||
* `Visitor#transaction(transactionId)` | ||
* `Visitor#transaction(transactionId, callback)` | ||
* `Visitor#transaction(transactionId, revenue)` | ||
* `Visitor#transaction(transactionId, revenue, callback)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, callback)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax, callback)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, callback)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, params)` | ||
* `Visitor#transaction(transactionId, revenue, shippingCost, tax, affiliation, params, callback)` | ||
* `Visitor#transaction(params)` | ||
* `Visitor#transaction(params, callback)` | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
### Transaction item tracking | ||
Transaction consist of one or more items. | ||
```javascript | ||
visitor.item(449.99, 1, "ID54321", "T-Shirt", {ti: "123456"}).send() | ||
``` | ||
The following method signatures are available for #transaction: | ||
* `Visitor#transaction(price)` | ||
* `Visitor#transaction(price, callback)` | ||
* `Visitor#transaction(price, quantity)` | ||
* `Visitor#transaction(price, quantity, callback)` | ||
* `Visitor#transaction(price, quantity, sku)` | ||
* `Visitor#transaction(price, quantity, sku, callback)` | ||
* `Visitor#transaction(price, quantity, sku, name)` | ||
* `Visitor#transaction(price, quantity, sku, name, callback)` | ||
* `Visitor#transaction(price, quantity, sku, name, variation)` | ||
* `Visitor#transaction(price, quantity, sku, name, variation, callback)` | ||
* `Visitor#transaction(price, quantity, sku, name, variation, params)` | ||
* `Visitor#transaction(price, quantity, sku, name, variation, params, callback)` | ||
* `Visitor#transaction(params)` | ||
* `Visitor#transaction(params, callback)` | ||
See also: [List of acceptable params](AcceptableParams.md). | ||
# Daisy-chaining tracking calls | ||
We have seen basic daisy-chaining above when calling `send()` right after `pageview()` and `event()`: | ||
```javascript | ||
visitor.pageview("/").send() | ||
``` | ||
Every call of a tracking method returns a visitor instance you can re-use: | ||
```javascript | ||
visitor.pageview("/").pageview("/contact").send() | ||
``` | ||
Granted, the chance of this example actually happening in practice might be rather low. | ||
However, `universal-analytics` is smart when it comes to daisy-chaining certain calls. In many cases, a `pageview()` call is instantly followed by an `event()` call to track some additional information about the current page. `universal-analytics` makes creating the connection between the two easy: | ||
```javascript | ||
visitor.pageview("/landing-page-1").event("Testing", "Button color", "Blue").send() | ||
``` | ||
This is the same as two distinct tracking calls. | ||
```javascript | ||
visitor.pageview("/landing-page-1").send() | ||
visitor.event("Testing", "Button color", "Blue", {p: "/landing-page-1"}).send() | ||
``` | ||
Daisy-chaining is context-aware and in this case placing the `event()` call right after the `pageview()` call results in the event being associated with the page path tracking in the `pageview()` call. Even though the attributes (`dp` and `p`) are different internally. | ||
It also works when using a callback since the `this` inside the callback will be the `universal-analytics` Visitor instance: | ||
```javascript | ||
visitor.pageview("/landing-page-1", function (err) { | ||
if (!err) { | ||
this.event("Testing", "Button color", "Blue").send() | ||
} | ||
}); | ||
``` | ||
More generally, the daisy-chaining context keeps all parameters from the previous call around. This means in a situation where similar tracking calls are necessary tracking is simplified: | ||
```javascript | ||
visitor | ||
.event({ec: "Mail Server", ea: "New Team Member Notification sent"}) | ||
.event({ea: "Invitation sent"}) | ||
.send(); | ||
``` | ||
In this example the event category ("Mail Server") is not repeated in the second tracking call. | ||
# Setting persistent parameters | ||
Some parameters should be in every tracking call, such as a user ID or custom dimensions that never or hardly change. For such situations a `#set(key, value)` method is available | ||
```javascript | ||
visitor.set("uid", "123456789") | ||
``` | ||
The uid parameter will be part of every tracking request of that visitor from now on. | ||
# Session-based identification | ||
In order to make session-based apps easier to work with, `universal-analytics` also provides a middleware that works in an Expressjs-style fashion. It will try to detect a client ID based on the `_ga` cookie used by the analytics.js client-side tracking. Additionally it will store the detected client ID in the current session to recognize the visitor later. | ||
@@ -406,3 +548,3 @@ | ||
## Debug mode | ||
# Debug mode | ||
@@ -417,3 +559,3 @@ `universal-analytics` can be instructed to output information during tracking by enabling the debug mode: | ||
## Request Options | ||
# Request Options | ||
@@ -431,3 +573,3 @@ In order to add additional options to the request a `requestOptions` hash can be provided as part of the constructor options. `unviversal-analytics` uses the [`request`](https://www.npmjs.com/package/request) library. Therefor [any option available for that library](https://www.npmjs.com/package/request#requestoptions-callback) can be provided via the `requestOptions`. | ||
## Shortcuts | ||
# Shortcuts | ||
@@ -453,7 +595,7 @@ The tracking methods have shortcuts: | ||
## License | ||
# License | ||
(The MIT License) | ||
Copyright (c) 2016 Peaks & Pies GmbH <hello@peaksandpies.com> | ||
Copyright (c) 2017 Peaks & Pies GmbH <hello@peaksandpies.com> | ||
@@ -460,0 +602,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
166099
2656
632