keen-tracking
Advanced tools
Comparing version 0.0.0 to 0.0.1
;(function (f) { | ||
// RequireJS | ||
if (typeof define === "function" && define.amd) { | ||
define("keen", [], function(){ return f(); }); | ||
if ('undefined' !== typeof define && define.amd && typeof define === 'function') { | ||
define('keen-tracking', [], function(){ return f(); }); | ||
} | ||
// CommonJS | ||
if (typeof exports === "object" && typeof module !== "undefined") { | ||
if (typeof exports === 'object' && typeof module !== 'undefined') { | ||
module.exports = f(); | ||
@@ -12,7 +12,7 @@ } | ||
var g = null; | ||
if (typeof window !== "undefined") { | ||
if (typeof window !== 'undefined') { | ||
g = window; | ||
} else if (typeof global !== "undefined") { | ||
} else if (typeof global !== 'undefined') { | ||
g = global; | ||
} else if (typeof self !== "undefined") { | ||
} else if (typeof self !== 'undefined') { | ||
g = self; | ||
@@ -24,8 +24,185 @@ } | ||
})(function() { | ||
"use strict"; | ||
'use strict'; | ||
var Keen = require('./index'); | ||
var Keen = require('./'); | ||
var each = require('./utils/each'); | ||
var extend = require('./utils/extend'); | ||
var listener = require('./utils/listener')(Keen); | ||
// ------------------------ | ||
// Methods | ||
// ------------------------ | ||
extend(Keen.prototype, require('./record-events-browser')); | ||
extend(Keen.prototype, require('./defer-events')); | ||
extend(Keen.prototype, { | ||
'extendEvent': require('./extend-events').extendEvent, | ||
'extendEvents': require('./extend-events').extendEvents | ||
}); | ||
// ------------------------ | ||
// Deprecated | ||
// ------------------------ | ||
Keen.prototype.trackExternalLink = trackExternalLink; | ||
// ------------------------ | ||
// Helpers | ||
// ------------------------ | ||
extend(Keen.helpers, { | ||
'getBrowserProfile' : require('./helpers/getBrowserProfile'), | ||
'getDatetimeIndex' : require('./helpers/getDatetimeIndex'), | ||
'getDomNodePath' : require('./helpers/getDomNodePath'), | ||
'getScreenProfile' : require('./helpers/getScreenProfile'), | ||
'getUniqueId' : require('./helpers/getUniqueId'), | ||
'getWindowProfile' : require('./helpers/getWindowProfile') | ||
}); | ||
// ------------------------ | ||
// Utils | ||
// ------------------------ | ||
extend(Keen.utils, { | ||
'cookie' : require('./utils/cookie'), | ||
'deepExtend' : require('./utils/deepExtend'), | ||
'each' : each, | ||
'extend' : extend, | ||
'listener' : listener, | ||
'parseParams': require('./utils/parseParams'), | ||
'timer' : require('./utils/timer') | ||
}); | ||
Keen.listenTo = function(listenerHash){ | ||
each(listenerHash, function(callback, key){ | ||
var split = key.split(' '); | ||
var eventType = split[0], | ||
selector = split.slice(1, split.length).join(' '); | ||
// Create an unassigned listener | ||
return listener(selector).on(eventType, callback); | ||
}); | ||
}; | ||
Keen.noConflict = function(){ | ||
root.Keen = previousKeen; | ||
return Keen; | ||
}; | ||
Keen.ready = function(fn){ | ||
if (Keen.loaded) { | ||
fn(); | ||
} | ||
else { | ||
Keen.once('ready', fn); | ||
} | ||
}; | ||
domReady(function(){ | ||
Keen.loaded = true; | ||
Keen.emit('ready'); | ||
}); | ||
function domReady(fn){ | ||
if (Keen.loaded || 'undefined' === typeof document) { | ||
fn(); | ||
return; | ||
} | ||
// Firefox 3.5 shim | ||
if(document.readyState == null && document.addEventListener){ | ||
document.addEventListener('DOMContentLoaded', function DOMContentLoaded(){ | ||
document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false); | ||
document.readyState = 'complete'; | ||
}, false); | ||
document.readyState = 'loading'; | ||
} | ||
testDom(fn); | ||
} | ||
function testDom(fn){ | ||
if (/in/.test(document.readyState)) { | ||
setTimeout(function(){ | ||
testDom(fn); | ||
}, 9); | ||
} | ||
else { | ||
fn(); | ||
} | ||
} | ||
// ------------------------------ | ||
// DEPRECATED | ||
// Apply client.globalProperties | ||
// ------------------------------ | ||
function trackExternalLink(jsEvent, eventCollection, payload, timeout, timeoutCallback){ | ||
this.emit('error', 'This method has been deprecated. Check out DOM listeners: https://github.com/keen/keen-tracking.js#listeners'); | ||
var evt = jsEvent, | ||
target = (evt.currentTarget) ? evt.currentTarget : (evt.srcElement || evt.target), | ||
timer = timeout || 500, | ||
triggered = false, | ||
targetAttr = '', | ||
callback, | ||
win; | ||
if (target.getAttribute !== void 0) { | ||
targetAttr = target.getAttribute('target'); | ||
} else if (target.target) { | ||
targetAttr = target.target; | ||
} | ||
if ((targetAttr == '_blank' || targetAttr == 'blank') && !evt.metaKey) { | ||
win = window.open('about:blank'); | ||
win.document.location = target.href; | ||
} | ||
if (target.nodeName === 'A') { | ||
callback = function(){ | ||
if(!triggered && !evt.metaKey && (targetAttr !== '_blank' && targetAttr !== 'blank')){ | ||
triggered = true; | ||
window.location = target.href; | ||
} | ||
}; | ||
} | ||
else if (target.nodeName === 'FORM') { | ||
callback = function(){ | ||
if(!triggered){ | ||
triggered = true; | ||
target.submit(); | ||
} | ||
}; | ||
} | ||
else { | ||
this.trigger('error', '#trackExternalLink method not attached to an <a> or <form> DOM element'); | ||
} | ||
if (timeoutCallback) { | ||
callback = function(){ | ||
if(!triggered){ | ||
triggered = true; | ||
timeoutCallback(); | ||
} | ||
}; | ||
} | ||
this.recordEvent(eventCollection, payload, callback); | ||
setTimeout(callback, timer); | ||
if (!evt.metaKey) { | ||
return false; | ||
} | ||
} | ||
// IE-specific polyfills, yay! | ||
// ----------------------------- | ||
if (!Array.prototype.indexOf){ | ||
Array.prototype.indexOf = function(elt /*, from*/) { | ||
var len = this.length >>> 0; | ||
var from = Number(arguments[1]) || 0; | ||
from = (from < 0) | ||
? Math.ceil(from) | ||
: Math.floor(from); | ||
if (from < 0) | ||
from += len; | ||
for (; from < len; from++) { | ||
if (from in this && | ||
this[from] === elt) | ||
return from; | ||
} | ||
return -1; | ||
}; | ||
} | ||
module.exports = Keen; | ||
return Keen; | ||
}); |
132
lib/index.js
var Emitter = require('component-emitter'); | ||
var JSON2 = require('JSON2'); | ||
var each = require('./utils/each'); | ||
var extend = require('./utils/extend'); | ||
var queue = require('./utils/queue'); | ||
var root = this; | ||
var previousKeen = root.Keen; | ||
var Keen = { | ||
version: '__VERSION__' | ||
var Keen = function(config){ | ||
this.configure(config); | ||
Keen.emit('client', this); | ||
}; | ||
Keen.noConflict = function(){ | ||
root.Keen = previousKeen; | ||
return Keen; | ||
Keen.prototype.configure = function(config){ | ||
var self = this, defaultProtocol; | ||
if (config['host']) { | ||
config['host'].replace(/.*?:\/\//g, ''); | ||
} | ||
defaultProtocol = 'https'; | ||
// IE<10 request shim | ||
if ('undefined' !== typeof document && document.all) { | ||
config['protocol'] = (document.location.protocol !== 'https:') ? 'http' : defaultProtocol; | ||
} | ||
self.config = self.config || { | ||
// projectId | ||
// writeKey | ||
host: 'api.keen.io', | ||
protocol: defaultProtocol, | ||
requestType: 'jsonp' | ||
// writePath (generated) | ||
}; | ||
extend(self.config, config || {}); | ||
self.queue = queue(); | ||
self.queue.on('flush', function(){ | ||
self.recordDeferredEvents(); | ||
}); | ||
self.extensions = { | ||
events: [], | ||
collections: {} | ||
}; | ||
if (Keen.debug) { | ||
self.on('error', Keen.log); | ||
} | ||
self.emit('ready'); | ||
return self; | ||
}; | ||
Keen.prototype.projectId = function(str){ | ||
if (!arguments.length) return this.config.projectId; | ||
this.config.projectId = (str ? String(str) : null); | ||
return this; | ||
}; | ||
Keen.prototype.writeKey = function(str){ | ||
if (!arguments.length) return this.config.writeKey; | ||
this.config.writeKey = (str ? String(str) : null); | ||
return this; | ||
}; | ||
Keen.prototype.writePath = function(str){ | ||
if (!arguments.length) { | ||
if (!this.projectId()) { | ||
this.emit('error', 'Keen is missing a projectId property'); | ||
return; | ||
} | ||
return this.config.writePath ? this.config.writePath : ('/3.0/projects/' + this.projectId() + '/events'); | ||
} | ||
this.config.writePath = (str ? String(str) : null); | ||
return this; | ||
}; | ||
Keen.prototype.url = function(path, data){ | ||
var url; | ||
if (!this.projectId()) { | ||
this.emit('error', 'Keen is missing a projectId property'); | ||
return; | ||
} | ||
url = this.config.protocol + '://' + this.config.host + '/3.0/projects/' + this.projectId(); | ||
if (path) { | ||
url += path; | ||
} | ||
if (data) { | ||
url += '?' + serialize(data); | ||
} | ||
return url; | ||
}; | ||
// ---------------------- | ||
// DEPRECATED | ||
// ---------------------- | ||
Keen.prototype.setGlobalProperties = function(props){ | ||
this.emit('error', 'This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events'); | ||
if (!props || typeof props !== 'function') { | ||
this.emit('error', 'Invalid value for global properties: ' + props); | ||
return; | ||
} | ||
this.config.globalProperties = props; | ||
return this; | ||
}; | ||
Emitter(Keen); | ||
Emitter(Keen.prototype); | ||
extend(Keen, { | ||
debug: false, | ||
enabled: true, | ||
loaded: false, | ||
helpers: {}, | ||
utils: {}, | ||
version: '__VERSION__' | ||
}); | ||
Keen.log = function(message) { | ||
if (Keen.debug && typeof console == 'object') { | ||
console.log('[Keen IO]', message); | ||
} | ||
}; | ||
function serialize(data){ | ||
var query = []; | ||
each(data, function(value, key){ | ||
if ('string' !== typeof value) { | ||
value = JSON2.stringify(value); | ||
} | ||
query.push(key + '=' + encodeURIComponent(value)); | ||
}); | ||
return query.join('&'); | ||
} | ||
module.exports = Keen; |
{ | ||
"name": "keen-tracking", | ||
"version": "0.0.0", | ||
"version": "0.0.1", | ||
"main": "index.js", | ||
@@ -25,19 +25,21 @@ "browser": "lib/browser.js", | ||
}, | ||
"browserify": { | ||
"transform": [ | ||
"browserify-versionify" | ||
] | ||
}, | ||
"dependencies": { | ||
"browserify-versionify": "^1.0.4", | ||
"component-emitter": "^1.2.0" | ||
"JSON2": "^0.1.0", | ||
"component-emitter": "^1.2.0", | ||
"cookies-js": "^1.2.1" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^9.0.8", | ||
"chai": "^2.3.0", | ||
"chai-spies": "^0.6.0", | ||
"del": "^1.1.1", | ||
"gulp": "^3.8.11", | ||
"gulp-awspublish": "0.0.23", | ||
"gulp-connect": "^2.2.0", | ||
"gulp-derequire": "^2.1.0", | ||
"gulp-mocha": "^2.0.1", | ||
"gulp-mocha-phantomjs": "^0.6.1", | ||
"gulp-remove-empty-lines": "0.0.2", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-replace": "^0.5.3", | ||
"gulp-sourcemaps": "^1.5.2", | ||
@@ -47,7 +49,20 @@ "gulp-strip-comments": "^1.0.1", | ||
"gulp-yuicompressor": "0.0.3", | ||
"proclaim": "^3.2.1", | ||
"karma": "^0.12.32", | ||
"karma-chrome-launcher": "^0.1.12", | ||
"karma-firefox-launcher": "^0.1.6", | ||
"karma-mocha": "^0.2.0", | ||
"karma-nyan-reporter": "0.0.60", | ||
"karma-requirejs": "^0.2.2", | ||
"karma-safari-launcher": "^0.1.1", | ||
"karma-sauce-launcher": "^0.2.11", | ||
"karma-sinon": "^1.0.4", | ||
"mocha": "^2.2.5", | ||
"moment": "^2.10.3", | ||
"nock": "^2.0.1", | ||
"phantomjs": "^1.9.17", | ||
"proclaim": "^3.3.0", | ||
"sinon": "^1.14.1", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0", | ||
"vinyl-transform": "^1.0.0" | ||
"vinyl-source-stream": "^1.1.0" | ||
} | ||
} |
953
README.md
@@ -1,91 +0,73 @@ | ||
# keen-tracking.js | ||
# keen-tracking.js [![Build Status](https://travis-ci.org/keen/keen-tracking.js.svg?branch=master)](https://travis-ci.org/keen/keen-tracking.js) | ||
**Important:** This project is not yet functional. We're building this in public, in open collaboration with our customers and community members! Below is a sketch of planned functionality. [Learn more about contributing to this project](./CONTRIBUTING.md). | ||
This project contains the most advanced event tracking functionality available for [Keen IO](https://keen.io), and will soon be built directly into [keen-js](https://github.com/keen/keen-js), replacing and upgrading the current tracking capabilities of that library. | ||
Run the following commands to get this dev project set up locally: | ||
Why did we split this library out of [keen-js](https://github.com/keen/keen-js)? Tracking and Analysis+Dataviz are two distinct workflows and it rarely makes sense for these tools to be duct-taped together. Monolithic codebases bring more heartache than Nirvana. | ||
```ssh | ||
# Clone the repo | ||
$ git clone https://github.com/keen/keen-tracking.js.git && cd keen-tracking.js | ||
**Upgrading from keen-js?** [Read this](#upgrading-from-keen-js). | ||
# Install common dependencies | ||
$ npm install | ||
This [example setup](#example-setup) demonstrates how to put this library to work. | ||
# Install browser dependencies for tests | ||
$ bower install | ||
**Getting started:** | ||
# Build and launch project site | ||
$ gulp | ||
If you haven't done so already, login to Keen IO to create a project. The Project ID and API Keys are available on the Project Overview page. You will need these for the next steps. | ||
# Build and launch with tests | ||
$ gulp with-tests | ||
* [Install the library](#install-the-library) | ||
* [Connect](#connect) a new client instance for each project | ||
* [Record events](#record-events) to the API individually or in batches | ||
* [Defer events](#defer-events) to be recorded at a given interval, or when the queue reaches a given capacity | ||
* [Extend events](#extend-events) to build intricate, useful data models and ease instrumentation | ||
# View test results at http://localhost:9000 | ||
``` | ||
**Helpful utilities:** | ||
### Overview | ||
* [Cookies](#cookies) (browser-only) for persisting data from one page to the next | ||
* [Listeners](#listeners) (browser-only) for capturing and taking action during common DOM events like click, scroll, and submit | ||
* [Timers](#timers) for tracking time before and between user or system interactions | ||
``` | ||
var client = new Keen.Client(object); | ||
**Helpful helpers:** | ||
// Config accessors | ||
client.projectId("PROJECT_ID"); | ||
client.writeKey("WRITE_KEY"); | ||
* [Datetime index](#datetime-index) for decomposing a date object into a set of properties like "hour_of_day" or "day_of_month" | ||
* [Unique ID](#unique-id) for generating UUIDs | ||
* [DOM node path](#dom-node-path) for returning the xPath for a given DOM element | ||
* [Screen profile](#screen-profile) for generating a set of properties describing the current device screen, like "height", "availHeight", and "orientation" | ||
* [Window profile](#window-profile) for generating a set of properties describing the current window, like "height", "scrollHeight", and "ratio" to screen dimensions | ||
* [Browser profile](#browser-profile) for generating a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](#screen-profile) and [window](#window-profile) profiles | ||
// Record events | ||
client.recordEvent("collection", {}, function(err, res){ }); | ||
client.recordEvents({ "collection": [{}] }, function(err, res){ }); | ||
<a name="upgrading-from-keen-js"></a> | ||
**Upgrading from keen-js:** | ||
// Defer events for batch upload at a configurable interval | ||
client.deferEvent("collection", {}, function(err, res){ }); | ||
client.deferEvents({ "collection": [{}] }, function(err, res){ }); | ||
There are several new methods and name changes from keen-js, but fear not! We have included shims and legacy methods to make this library fully backward-compatible with the core functionality of keen-js. Here are the methods and their replacement methods: | ||
* `addEvent` and `addEvents` are now [`recordEvent`](#record-a-single-event) and [`recordEvents`](#record-multiple-events) | ||
* `setGlobalProperties` is now handled by the [`extendEvents`](#extend-events) methods | ||
* `trackExternalLinks` is now handled by the [DOM listeners](#listeners) utility (browser-only) | ||
// Force-clear the deferred queue | ||
client.recordDeferredEvents(); | ||
Please avoid using these deprecated methods, as they will eventually get axed. Deprecation messages will be visible in the developer console if [debugging](#debugging) is enabled. | ||
// Configure deferred queue | ||
client.queueCapacity(5000); | ||
client.queueInterval(15000); | ||
<a name="additional-resources"></a> | ||
**Additional resources:** | ||
// Extend each event body for one or all collections | ||
// Accepts a static object or function that returns an object | ||
client.extendEvent("collection", {}); | ||
client.extendEvent("collection", function(){ return {} }); | ||
client.extendEvents({}); | ||
client.extendEvents(function(){ return {} }); | ||
* [Example setup](#example-setup) demonstrates how to put all of this to work | ||
* [Debugging](#debugging) options can make life a little easier | ||
* [Contributing](#contributing) is awesome and we hope you do! | ||
* [Custom builds](#custom-builds) are encouraged as well - have fun! | ||
// Listen to DOM events | ||
Keen.listenTo({ | ||
"submit form": function(e){ ... } | ||
}); | ||
/* alternate: | ||
Keen.listenTo(document.getElementById("signup-form"), "submit", function(e){ ... }); | ||
Keen.listenTo("#signup-form", "submit", function(e){ ... }); | ||
*/ | ||
Keen.deferDomEvents("FORM", "submit", 500); | ||
<a name="support"></a> | ||
**Support:** | ||
// Miscellaneous | ||
Need a hand with something? Shoot us an email at [contact@keen.io](mailto:contact@keen.io). We're always happy to help, or just hear what you're building! Here are a few other resources worth checking out: | ||
// Get/extend base API URL | ||
client.url(); | ||
client.url("/events"); | ||
* [API status](http://status.keen.io/) | ||
* [API reference](https://keen.io/docs/api) | ||
* [How-to guides](https://keen.io/guides) | ||
* [Data modeling guide](https://keen.io/guides/data-modeling-guide/) | ||
* [Slack (public)](http://slack.keen.io/) | ||
// Get API URL with url-encoded params | ||
client.url("/events/name", { key: "value" }); | ||
// Read events in progress | ||
Keen.debug(true); | ||
client.on("all", Keen.log); | ||
client.on("recordEvent", Keen.log); | ||
``` | ||
### Getting started | ||
## Install the library | ||
* Project ID | ||
* API Write Key | ||
This library is best loaded asynchronously with the copy-paste technique outlined below, but can also be installed via [npm](https://www.npmjs.com/package/keen-tracking) or [bower](http://bower.io/search/?q=keen-tracking): | ||
### Install the library | ||
``` | ||
```ssh | ||
# via npm | ||
@@ -98,77 +80,260 @@ $ npm install keen-tracking | ||
For quick browser use, copy/paste this snippet of JavaScript above the </head> tag of your page: | ||
Copy/paste this snippet of JavaScript above the </head> tag of your page to load the tracking library asynchronously. This technique sneaks the library into your page without significantly impacting page load speed. | ||
```html | ||
<script> | ||
// Loads the library asynchronously from any URI | ||
!function(name,path,ctx){ | ||
var latest,prev=name!=='Keen'&&window.Keen?window.Keen:false;ctx[name]=ctx[name]||{ready:function(fn){var h=document.getElementsByTagName('head')[0],s=document.createElement('script'),w=window,loaded;s.onload=s.onerror=s.onreadystatechange=function(){if((s.readyState&&!(/^c|loade/.test(s.readyState)))||loaded){return}s.onload=s.onreadystatechange=null;loaded=1;latest=w.Keen;if(prev){w.Keen=prev}else{try{delete w.Keen}catch(e){w.Keen=void 0}}ctx[name]=latest;ctx[name].ready(fn)};s.async=1;s.src=path;h.parentNode.insertBefore(s,h)}} | ||
}('Keen','https://d26b395fwzu5fz.cloudfront.net/keen-tracking-0.0.1.min.js',this); | ||
// Executes when the library is loaded and ready | ||
Keen.ready(function(){ | ||
// Create a new client instance | ||
var client = new Keen({ | ||
projectId: 'YOUR_PROJECT_ID', | ||
writeKey: 'YOUR_WRITE_KEY' | ||
}); | ||
// Record an event! | ||
client.recordEvent('pageviews', { | ||
// Define your event data model | ||
title: document.title | ||
}); | ||
}); | ||
</script> | ||
``` | ||
// async loader ... | ||
!function(a,b){a("Keen","https://d26b395fwzu5fz.cloudfront.net/0.0.1/keen-tracking.min.js",b)}(function(a,b,c){var d,e,f;c["_"+a]={},c[a]=function(b){c["_"+a].clients=c["_"+a].clients||{},c["_"+a].clients[b.projectId]=this,this._config=b},c[a].ready=function(b){c["_"+a].ready=c["_"+a].ready||[],c["_"+a].ready.push(b)},d=["recordEvent","recordEvents","on"];for(var g=0;g<d.length;g++){var h=d[g],i=function(a){return function(){return this["_"+a]=this["_"+a]||[],this["_"+a].push(arguments),this}};c[a].prototype[h]=i(h)}e=document.createElement("script"),e.async=!0,e.src=b,f=document.getElementsByTagName("script")[0],f.parentNode.insertBefore(e,f)},this); | ||
This loader works a little differently than all the previous versions we have released. | ||
Notice the last line of the asynchronous loader snippet: `}('Keen', './filename.js', this);`. These three arguments can be overwritten, allowing you to customize important details about the installation process. | ||
1. **Namespace:** Define a custom namespace for the library, instead of the default `Keen`, like `MyCustomKeenBuild`. | ||
2. **Script URI:** Define the location of the script to load. You don't need to rely on our CDN. You can use your own, or host the file locally. | ||
3. **Context:** Define where the library should be installed. Global pollution is a problem. This helps you fight back. | ||
Here's an example that uses all of these features together: | ||
```javascript | ||
var modules = {}; | ||
!function(name,path,ctx){ | ||
//~ .etc | ||
}('MyKeenBuild','/assets/js/custom-keen-tracking.js', modules); | ||
modules.MyKeenBuild.ready(function(){ | ||
var client = new modules.MyKeenBuild.Client({ | ||
projectId: 'YOUR_PROJECT_ID', | ||
writeKey: 'YOUR_WRITE_KEY' | ||
}); | ||
// client.recordEvent('pageviews', {}); | ||
}); | ||
``` | ||
Or load the library synchronously from our CDN: | ||
**Important:** This update brings an important change to note. In past versions of keen-js, we shimmed tracking-methods so you could begin using them immediately without the `.ready()` callback wrapper. This created a lot of strange edge cases and version conflicts. Now, everything must be initialized from within the `.ready(function(){ ... })` wrapper. | ||
**RequireJS** | ||
The library is published with an explicitly named module ID of 'keen-tracking'. This presents a light configuration step, but prevents anonymous define() mismatch mayhem. | ||
To use this module, configure a paths record, like so: | ||
```html | ||
<script data-main="path/to/app.js" src="require.js"></script> | ||
``` | ||
https://d26b395fwzu5fz.cloudfront.net/0.0.1/keen-tracking.min.js | ||
```javascript | ||
// app.js | ||
requirejs.config({ | ||
paths: { | ||
'keen-tracking': 'path/to/keen-tracking.js' | ||
} | ||
}); | ||
require([ | ||
'keen-tracking' | ||
], function(KeenAMD) { | ||
var client = new KeenAMD.Client({ | ||
projectId: "123", | ||
writeKey: "456" | ||
}); | ||
}); | ||
``` | ||
### Configure a new client for each project | ||
Also note a global `Keen` object will still be defined. This is meant to ensure the library can initialize in environments where neighboring scripts are unknown or uncontrollable. | ||
``` | ||
var client = new Keen.Client({ | ||
projectId: "YOUR_PROJECT_ID", | ||
writeKey: "YOUR_WRITE_KEY" | ||
## Connect | ||
The client instance is the core of the library and will be required for all API-related functionality. The `client` variable defined below will also be used throughout this document. | ||
```javascript | ||
var client = new Keen({ | ||
projectId: 'YOUR_PROJECT_ID', | ||
writeKey: 'YOUR_WRITE_KEY', | ||
/* Additional options (defaults shown): | ||
writePath: '/3.0/projects/YOUR_PROJECT_ID/events' | ||
host: 'api.keen.io' | ||
protocol: 'https' | ||
requestType: 'jsonp' // Also: 'xhr', 'beacon' | ||
*/ | ||
}); | ||
// Callback used by examples | ||
function callback(err, res){ | ||
console.log(err, res); | ||
}; | ||
// Optional accessor methods are available too | ||
client.projectId('PROJECT_ID'); | ||
client.writeKey('WRITE_KEY'); | ||
``` | ||
### Record events | ||
**Important notes about client configuration options:** | ||
These methods push single or multiple events to their respective API endpoints. | ||
* `host` and `writePath`: these options can be overwritten to make it easier than ever to proxy events through your own intermediary host. | ||
* `protocol`: older versions of IE feature a fun little quirk where cross-domain requests to a secure resource (https) from an insecure host (!https) fail. In these rare cases the library will match the current host's protocol. | ||
* `requestType`: this option sets a default for GET requests, which is only supported when recording single events. There are limits to the URL string length of a request, so if this limit is exceeded we'll attempt to execute a POST instead, using XHR. In rare cases where XHR isn't supported, the request will fail. | ||
## Record events | ||
These methods push single or multiple events to their respective API endpoints. Wondering what you should record? Browse our [data modeling guide](https://keen.io/guides/data-modeling-guide/), and let us know if you don't find what you're looking for. | ||
### Record a single event | ||
Here is an example for recording a "purchases" event. Note that dollar amounts are tracked in cents: | ||
```javascript | ||
// Create a data object with the properties you want to record | ||
var purchaseEvent = { | ||
item: 'golden gadget', | ||
price: 2550, // track dollars as cents | ||
referrer: document.referrer, | ||
keen: { | ||
timestamp: new Date().toISOString() | ||
} | ||
}; | ||
client.recordEvent('purchases', purchaseEvent, function(err, res){ | ||
if (err) { | ||
// there was an error! | ||
} | ||
else { | ||
// see sample response below | ||
} | ||
}); | ||
``` | ||
// Single event | ||
client.recordEvent("transaction", {}, callback); | ||
// Multiple events | ||
client.recordEvents({ | ||
"transaction": [ {} ], | ||
"purchase": [ {}, {}, {} ], | ||
"pageview": [ {} ] | ||
}, callback); | ||
**API response for recording a single event:** | ||
```jsonp | ||
{ | ||
"created": true | ||
} | ||
``` | ||
### Defer events | ||
### Record multiple events | ||
These methods handle an internal queue of events, which is pushed to the Events resource endpoint on a given interval. | ||
Here is an example for how to record multiple events with a single API call. Note that dollar amounts are tracked in cents: | ||
```javascript | ||
var multipleEvents = { | ||
purchases: [ | ||
{ | ||
item: 'golden gadget', | ||
price: 2550, | ||
transaction_id: 'f029342' | ||
}, | ||
{ | ||
item: 'a different gadget', | ||
price: 1775, | ||
transaction_id: 'f029342' | ||
} | ||
], | ||
transactions: [ | ||
{ | ||
id: 'f029342', | ||
items: 2, | ||
total: 4325 | ||
} | ||
] | ||
}; | ||
// Send multiple events to several collections | ||
client.recordEvents(multipleEvents, function(err, res){ | ||
if (err) { | ||
// there was an error! | ||
} | ||
else { | ||
// see sample response below | ||
} | ||
}); | ||
``` | ||
// Single event | ||
client.deferEvent("transaction", {}, callback); | ||
// Multiple events | ||
client.deferEvents({ "Name": [{},{}] }, callback); | ||
**API response for recording multiple events:** | ||
// Force-clear the deferred queue | ||
```json | ||
{ | ||
"purchases": [ | ||
{ | ||
"success": true | ||
}, | ||
{ | ||
"success": true | ||
} | ||
], | ||
"transactions": [ | ||
{ | ||
"success": true | ||
} | ||
] | ||
} | ||
``` | ||
## Defer events | ||
These methods handle an internal queue of events, which is pushed to the [events](https://keen.io/docs/api/#record-multiple-events) API resource on a given interval (default: 15 seconds), or when the queue reaches a maximum capacity (default: 5000). | ||
```javascript | ||
// Single event from the previous example | ||
client.deferEvent('purchase', purchaseEvent); | ||
// Multiple events from the previous example | ||
client.deferEvents(multipleEvents); | ||
// Flush the deferred queue | ||
client.recordDeferredEvents(); | ||
// Configure deferred queue | ||
// Record events when queue contains at least N events (default: 5000) | ||
client.queueCapacity(5000); | ||
client.queueInterval(15000); | ||
client.queueCapacity(); // 5000 | ||
// Record events every N seconds (default: 15) | ||
client.queueInterval(15); | ||
client.queueInterval(); // 15 | ||
``` | ||
### Extend events (global properties) | ||
## Extend events | ||
These methods extend the event body of all or specified collections, and accept either an object or function that returns an object. Global transforms will be applied first, followed by per-collection transforms. In either case, transforms will be applied in the order that they are defined, and use a deep-extend method to fully blend nested objects together. | ||
These methods extend the event body of every event sent through `recordEvent()` or `recordEvents()`, for all or specified collections, and accepts either a predefined object (static) or a function that returns an object (dynamic). This returned object is then grafted into the original event body with a deep-extend operation that seamlessly blends nested objects. | ||
``` | ||
`extendEvents` transforms will be applied first, followed by collection-specific `extendEvent` transforms. In either case, transforms will be applied in the order that they are defined. Properties provided in the originating `recordEvent/s()` call will override any matching properties (static or dynamic) returned by these methods. | ||
```javascript | ||
// Extend events for a single collection | ||
client.extendEvent("transaction", {}); | ||
client.extendEvent("transaction", function(){ return {}; }); | ||
client.extendEvent('transaction', {}); | ||
client.extendEvent('transaction', function(){ | ||
return {}; | ||
}); | ||
// Extend events for all collections | ||
client.extendEvents({}); | ||
client.extendEvents(function(){ return {}; }); | ||
client.extendEvents(function(){ | ||
return {}; | ||
}); | ||
@@ -178,13 +343,19 @@ // Example usage | ||
var userProps = { | ||
full_name: "User Dude", | ||
email: "name@domain.com", | ||
id: "f1233423h", | ||
username: "userdude213" | ||
full_name: 'User Dude', | ||
email: 'name@domain.com', | ||
id: 'f1233423h', | ||
username: 'userdude213' | ||
}; | ||
client.extendEvent("purchase", { | ||
"user": userProps | ||
// Include a predefined 'user' object with every purchase event | ||
client.extendEvent('purchases', { | ||
'user': userProps | ||
}); | ||
client.extendEvents({ "user": userProps }); | ||
// Include a predefined 'user' object with every event | ||
client.extendEvents({ | ||
'user': userProps | ||
}); | ||
// Include a dynamic 'keen.timestamp' property with every event | ||
client.extendEvents(function(){ | ||
@@ -197,46 +368,151 @@ return { | ||
}); | ||
client.extendEvent("pageview", { title: document.title }); | ||
``` | ||
### DOM Element tracking | ||
**Example usage:** | ||
This method surfaces events from user interactions. Form submits and clicks will be delayed by default (configurable). | ||
```javascript | ||
// Object (static) | ||
client.extendEvents({ | ||
page: { | ||
href: document.location.href, | ||
title: document.title | ||
}, | ||
referrer: document.referrer, | ||
user: { | ||
email: 'name@domain.com', | ||
id: 'f1233423h', | ||
username: 'someuser123' | ||
} | ||
}); | ||
Also check out declarative binding demo here: http://jsfiddle.net/hm514aj8/10/ | ||
// Function that returns an object (dynamic) | ||
// Useful for attaching time-sensitive data | ||
client.extendEvents(function(){ | ||
return { | ||
keen: { | ||
timestamp: new Date().toISOString() | ||
} | ||
} | ||
}); | ||
// | ||
client.recordEvent('pageviews'); | ||
/* Resulting event body: | ||
{ | ||
user: { | ||
email: 'name@domain.com', | ||
id: 'f1233423h', | ||
username: 'someuser123' | ||
}, | ||
page: { | ||
href: 'https://github.com/keen/keen-tracking.js#extend-events', | ||
title: document.title | ||
}, | ||
referrer: 'https://github.com/keen/', | ||
keen: { | ||
timestamp: '2015-06-28T22:01:38.824Z' | ||
} | ||
} | ||
*/ | ||
``` | ||
## Utilities | ||
### Cookies | ||
`Keen.utils.cookie(key)` finds or creates a cookie with a given key (string) value, and returns an object with several methods for managing the data contained in that cookie. | ||
```javascript | ||
var session = Keen.utils.cookie('visitor-stats'); | ||
// Set a single value | ||
session.set('user_id', '222323843234'); | ||
// Set multiple values | ||
session.set({ | ||
user_id: '222323843234', | ||
first_referrer: 'https://github.com/keen/keen-tracking.js' | ||
}) | ||
// Get a single value | ||
session.get('user_id'); // '222323843234' | ||
// Get all values | ||
session.get(); // { user_id: '222323843234' } | ||
// Expire the cookie | ||
session.expire(); | ||
// Set options on the cookie | ||
session.options({ | ||
domain: '...', | ||
secure: true | ||
}); | ||
``` | ||
This utility uses [ScottHamper's](https://github.com/ScottHamper) wonderfully simple [Cookies.js](https://github.com/ScottHamper/Cookies) library. Read all options for Cookies.js [here](https://github.com/ScottHamper/Cookies#cookiessetkey-value--options). | ||
### Listeners | ||
`Keen.utils.listener()` helps surface common DOM element events like "click", "scroll", and "submit". There is also a `Keen.listenTo()` method for quickly setting a series of listeners (below) | ||
**Important:** Form submits and clicks will be delayed by 500ms, unless the event is cancelled within a given listener's callback. | ||
<!-- Should we add this? http://jsfiddle.net/hm514aj8/10/ --> | ||
```javascript | ||
// Listen to DOM events | ||
Keen.listenTo({ | ||
// Form submits and clicks will be delayed (configurable) | ||
"submit form#my-fancy-form": function(e){ | ||
client.recordEvent("signup"); | ||
}, | ||
// Create a new element listener (assigned) | ||
var navLinks = Keen.utils.listener('.nav li > a'); | ||
"click .nav > a": function(e){ | ||
client.recordEvent("user_action", { type: "click" }); | ||
}, | ||
// Listen for a given event | ||
navLinks.on('click', function(e){ | ||
// You have 500ms to record an event! | ||
}); | ||
"mouseover .nav > a.login": function(e){ | ||
client.recordEvent("user_action", { type: "mouseover" }); | ||
} | ||
// Listen for event once | ||
myClicker.once('click', function(e){ | ||
// First click! | ||
}); | ||
Keen.listenTo({ "submit form": function(e){ ... } }); | ||
// Cancel a given event listener | ||
function clickHandler(e){ | ||
// do something! | ||
} | ||
myClicker.on('click', clickHandler); | ||
myClicker.off('click', clickHandler); | ||
// Override DOM event timeouts (defaults shown) | ||
Keen.deferDomEvents("A", "click", 500); | ||
Keen.deferDomEvents("FORM", "submit", 500); | ||
// Cancel all listeners for a given event | ||
myClicker.off('click'); | ||
// .. or all events | ||
myClicker.off(); | ||
var formListener = Keen.utils.listener('form#signup'); | ||
formListener.on('submit', function(e){ | ||
client.recordEvent('signup', { | ||
// record signup data | ||
}); | ||
}); | ||
// TODO: Override DOM event timeouts (defaults shown) | ||
// Keen.deferDomEvents('A', 'click', 500); | ||
// Keen.deferDomEvents('FORM', 'submit', 500); | ||
``` | ||
#### Window events | ||
#### Keen.listenTo() | ||
``` | ||
This is a convenience function for quickly creating multiple listeners. These listeners are constructed with the `Keen.utils.listener` utility, so the behavior will be identical to calling `Keen.utils.listener(selector).on(eventType, callback);`. | ||
```javascript | ||
Keen.listenTo({ | ||
"scroll window": function(e){ | ||
// update engagement helper's scroll tracking | ||
'click .nav li > a': function(e){ | ||
// You have 500ms to record an event! | ||
}, | ||
"unload window": function(e){ | ||
// kick out a synchronous request | ||
'submit form#signup': function(e){ | ||
// Record a signup event | ||
} | ||
@@ -246,14 +522,31 @@ }); | ||
**Supported events:** | ||
This technique does not return a reference to the listener, but can be deactivated by defining a listener with the same selector and calling the `.off(eventType)` event: | ||
* blur | ||
* click | ||
* dblclick | ||
* error | ||
* focus | ||
* hashchange | ||
```JavaScript | ||
Keen.utils.listener('.nav li > a').off('click'); | ||
Keen.utils.listener('form#signup').off('submit'); | ||
``` | ||
#### Window events | ||
```javascript | ||
var winListener = Keen.utils.listener('window') | ||
.once('scroll', function(e){ | ||
// user is interacting with the page | ||
}) | ||
.on('hashchange', function(e){ | ||
// user clicked an internal anchor (eg: /#some-heading) | ||
}) | ||
.on('resize', function(e){ | ||
// ... | ||
}); | ||
``` | ||
**Generally supported events:** | ||
* click (see below for `<a>` clicks) | ||
* submit (see below for `<form>` submits) | ||
* keydown | ||
* keypress | ||
* keyup | ||
* onload | ||
* mousedown | ||
@@ -264,35 +557,44 @@ * mousemove | ||
* mouseup | ||
**Important note about `<a>` and `<form>` elements:** `<a>` tag **clicks** (when navigating away from the current page) and `<form>` **submits** are deferred for 500ms to allow for quick, asynchronous API calls. | ||
**`window` events:** | ||
* blur | ||
* focus | ||
* hashchange | ||
* resize | ||
* unload | ||
* scroll | ||
**Not currently supported:** | ||
``` | ||
/* Alternate interface | ||
Pass in DOM elements or CSS selectors (sizzle.js) */ | ||
var form = document.getElementById('my-fancy-form'); | ||
client.listenTo(form, "submit", function(e){ ... }); | ||
client.listenTo(".nav > a.login", "click", function(e){ ... }); | ||
``` | ||
* dblclick | ||
* error | ||
* onload | ||
* unload | ||
### Cookies | ||
``` | ||
var session = Keen.utils.cookie("visitor-stats"); | ||
session.set("user_id", "222323843234"); | ||
session.get("user_id"); // "222323843234" | ||
session.get(); // { user_id: "222323843234" } | ||
session.clear(); | ||
``` | ||
### Timers | ||
``` | ||
`Keen.utils.timer()` creates an object that tracks time, and can be paused, restarted, or initialized with a known value (seconds). It seems simple, but these little do-dads are excellent for recording the duration of sessions or specific interactions. | ||
```javascript | ||
var userActivity = Keen.utils.timer(); | ||
// Start the timer | ||
userActivity.start(); | ||
// Pause the timer | ||
userActivity.pause(); | ||
userActivity.value(); | ||
// Return the vale of the timer (seconds) | ||
userActivity.value(); // 10 | ||
// Clear the current value of the timer | ||
userActivity.clear(); | ||
// Start from a given number | ||
var historicalActivity = Keen.utils.timer(312413123123).start(); | ||
var historicalActivity = Keen.utils.timer(3132).start(); | ||
historicalActivity.pause(); | ||
@@ -302,88 +604,220 @@ ``` | ||
### Helpers | ||
## Helpers | ||
These helpers can be passed into `client.extendEvent(s)` method(s) to construct and attach common sets of properties. | ||
These helpers are designed to generate useful properties and objects for event data models, and can be used when recording, deferring or extending events. | ||
### Datetime index | ||
`Keen.utils.getDatetimeIndex()` returns a set of properties like "hour_of_day" or "day_of_month". This helper accepts an optional Date object as an argument, otherwise it will construct and return a datetime index object based on "now". | ||
```javascript | ||
var datetimeIndex = Keen.helpers.getDatetimeIndex(); | ||
/* | ||
// Monday, June 29th, 2015 | ||
{ | ||
'hour_of_day': 14, | ||
'day_of_week': 2, | ||
'day_of_month': 29, | ||
'month': 6, | ||
'year': 2015 | ||
} | ||
*/ | ||
``` | ||
Keen.helpers = { | ||
getBrowserProfile: function(){ | ||
return { | ||
"cookies" : navigator.cookieEnabled, | ||
"screen" : Keen.helpers.getScreenProperties(), | ||
"window" : Keen.helpers.getWindowProperties() | ||
}; | ||
### Unique ID | ||
`Keen.helpers.getUniqueId()` returns a UUID. This is useful in conjunction with `Keen.utils.cookie()` for identifying and tracking unauthenticated site visitors. | ||
```javascript | ||
var uniqueId = Keen.helpers.getUniqueId(); | ||
// '150caf6b-ef9f-48cd-ae32-43e2f5bb0fe8' | ||
``` | ||
### DOM node path | ||
`Keen.helpers.getDomNodePath(el)` returns the xPath for a given DOM element. | ||
```javascript | ||
var btn = document.getElementById('signup-button'); | ||
var domNodePath = Keen.helpers.getDomNodePath(btn); | ||
// 'body > div#nav > ul > li:eq(1) > a#signup-button' | ||
``` | ||
### Screen profile | ||
`Keen.utils.getScreenProfile()` returns a set of properties describing the current device screen, like "height", "availHeight", and "orientation". | ||
```javascript | ||
var screenProfile = Keen.helpers.getScreenProfile(); | ||
/* | ||
{ | ||
'height': 900, | ||
'width': 1440, | ||
'colorDepth': 24, | ||
'pixelDepth': 24, | ||
'availHeight': 878, | ||
'availWidth': 1436, | ||
'orientation': { | ||
'angle': 0, | ||
'type': 'landscape' | ||
} | ||
} | ||
*/ | ||
``` | ||
### Window profile | ||
`Keen.utils.getWindowProfile()` returns a set of properties describing the current window, like "height", "scrollHeight", and "ratio" to screen dimensions. | ||
```javascript | ||
var windowProfile = Keen.helpers.getWindowProfile(); | ||
/* | ||
{ | ||
'height': 436, | ||
'width': 1209, | ||
'scrollHeight': 13834, | ||
'ratio': { | ||
'height': 0.5, | ||
'width': 0.84 | ||
} | ||
} | ||
*/ | ||
``` | ||
### Browser profile | ||
`Keen.utils.getBrowserProfile()` returns a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](#screen-profile) and [window](#window-profile) profiles. | ||
```javascript | ||
var browserProfile = Keen.helpers.getBrowserProfile(); | ||
/* | ||
{ | ||
'cookies': true, | ||
'codeName': 'Mozilla', | ||
'language': 'en-US', | ||
'name': 'Netscape', | ||
'online': true, | ||
'platform': 'MacIntel', | ||
'useragent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36', | ||
'version': '5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36', | ||
// includes Keen.helpers.getScreenProfile(); | ||
'screen': { | ||
'height': 900, | ||
'width': 1440, | ||
'colorDepth': 24, | ||
'pixelDepth': 24, | ||
'availHeight': 878, | ||
'availWidth': 1436, | ||
'orientation': { | ||
'angle': 0, | ||
'type': 'landscape' | ||
} | ||
}, | ||
getDatetimeIndex: function(obj){ | ||
var date = obj || new Date(); | ||
return { | ||
"hour_of_day" : date.getHours(), | ||
"day_of_week" : parseInt( 1 + date.getDay() ), | ||
"day_of_month" : date.getDate(), | ||
"month" : parseInt( 1 + date.getMonth() ), | ||
"year" : date.getFullYear() | ||
}; | ||
}, | ||
getDomEventProfile: function(e){ | ||
return { | ||
"innerText": e.target.innerText, | ||
"path": Keen.helpers.getDomPath(e.target).join(' > '), | ||
"tagName": e.target.tagName, | ||
"title": e.target.title | ||
}; | ||
}, | ||
getDomNodePath: function(el){ | ||
// http://stackoverflow.com/a/16742828/2511985 | ||
// returns something like "body > div#nav > ul > a#signup" | ||
}, | ||
getEngagementInfo: function(){}, | ||
getKitchenSink: function(){ | ||
// applies all helpers | ||
}, | ||
getRandomId: function(){}, | ||
getScreenProperties: function(){}, | ||
getWindowProperties: function(){} | ||
}; | ||
// includes Keen.helpers.getWindowProfile(); | ||
'window': { | ||
'height': 436, | ||
'width': 1209, | ||
'scrollHeight': 13834, | ||
'ratio': { | ||
'height': 0.5, | ||
'width': 0.84 | ||
} | ||
} | ||
} | ||
*/ | ||
``` | ||
## Example Setup | ||
``` | ||
var client = new Keen.Client({}); | ||
```javascript | ||
var client = new Keen({ | ||
projectId: 'MY_PROJECT_ID', | ||
writeKey: 'MY_WRITE_KEY' | ||
}); | ||
var sessionCookie = Keen.utils.cookie('keen-example-cookie'); | ||
if (!sessionCookie.get('user_id')) { | ||
sessionCookie.set('user_id', Keen.helpers.getUniqueId()); | ||
} | ||
var sessionTimer = Keen.utils.timer(); | ||
sessionTimer.start(); | ||
Keen.listenTo({ | ||
"submit form#signup": function(e){ | ||
var userEmail = document.getElementById("signup-email").value; | ||
client.recordEvent("user signup", { | ||
"interaction": { | ||
"type": "submit" | ||
}, | ||
"visitor": { | ||
"email": userEmail | ||
'form#signup': function(e){ | ||
// 500ms to record an event | ||
var userEmail = document.getElementById('signup-email').value; | ||
client.recordEvent('user signup', { | ||
visitor: { | ||
email: userEmail | ||
} | ||
}); | ||
}, | ||
"error window": function(e){ | ||
// Report a JavaScript error | ||
'click .nav li > a': function(e){ | ||
// 500ms to record an event | ||
client.recordEvent('leave page'); | ||
} | ||
}); | ||
// THE BIG DATA MODEL! | ||
client.extendEvents(function(){ | ||
return { | ||
"engagement": Keen.helpers.getEngagementInfo(), | ||
"interaction": { | ||
"event": Keen.helpers.getDomEventProfile(), | ||
"target": Keen.helpers.getDomNodePath() | ||
}, | ||
"page": { | ||
page: { | ||
title: document.title, | ||
href: document.href | ||
url: document.href | ||
// info: {} (add-on) | ||
}, | ||
"tech": Keen.helpers.getBrowserProfile(), | ||
"time": Keen.helpers.getDatetimeIndex(), | ||
"visitor": { | ||
"id": Keen.helpers.getRandomId() | ||
referrer: { | ||
url: document.referrer | ||
// info: {} (add-on) | ||
}, | ||
"keen": { | ||
"timestamp": new Date().toISOString() | ||
tech: { | ||
browser: Keen.helpers.getBrowserProfile(), | ||
// info: {} (add-on) | ||
ip: '${keen.ip}', | ||
ua: '${keen.user_agent}' | ||
}, | ||
time: Keen.helpers.getDatetimeIndex(), | ||
visitor: { | ||
id: sessionCookie.get('user_id'), | ||
time_on_page: sessionTimer.value() | ||
}, | ||
// geo: {} (add-on) | ||
keen: { | ||
timestamp: new Date().toISOString(), | ||
addons: [ | ||
{ | ||
name: 'keen:ip_to_geo', | ||
input: { | ||
ip: 'tech.ip' | ||
}, | ||
output: 'geo' | ||
}, | ||
{ | ||
name: 'keen:ua_parser', | ||
input: { | ||
ua_string: 'tech.ua' | ||
}, | ||
output: 'tech.info' | ||
}, | ||
{ | ||
name: 'keen:url_parser', | ||
input: { | ||
url: 'page.url' | ||
}, | ||
output: 'page.info' | ||
}, | ||
{ | ||
name: 'keen:referrer_parser', | ||
input: { | ||
page_url: 'page.url', | ||
referrer_url: 'referrer.url' | ||
}, | ||
output: 'referrer.info' | ||
} | ||
] | ||
} | ||
@@ -393,17 +827,58 @@ }; | ||
client.recordEvent("pageview"); | ||
client.recordEvent('pageview'); | ||
``` | ||
### Inspect event stream | ||
## Debugging | ||
Dev console errors and messages are turned off by default, but can be activated by setting `Keen.debug = true;`. Additionally, you can disable writing events to the API by setting `Keen.enabled = false;`. | ||
```javascript | ||
// Track errors and messages in the dev console | ||
Keen.debug = true; | ||
// Disable event writes to the API | ||
Keen.enabled = false; | ||
// Observe what's happening in each method | ||
client.on('recordEvent', Keen.log); | ||
client.on('recordEvents', Keen.log); | ||
client.on('deferEvent', Keen.log); | ||
client.on('deferEvents', Keen.log); | ||
client.on('recordDeferredEvents', Keen.log); | ||
client.on('extendEvent', Keen.log); | ||
client.on('extendEvents', Keen.log); | ||
``` | ||
Keen.debug(true); | ||
client.on("all", Keen.log); | ||
client.on("recordEvent", Keen.log); | ||
client.on("recordEvents", Keen.log); | ||
client.on("deferEvent", Keen.log); | ||
client.on("deferEvents", Keen.log); | ||
client.on("recordDeferredEvents", Keen.log); | ||
client.on("extendEvent", Keen.log); | ||
client.on("extendEvents", Keen.log); | ||
## Contributing | ||
This is an open source project and we love involvement from the community! Hit us up with pull requests and issues. The more contributions the better! | ||
**TODO:** | ||
* [ ] Validate `Keen.utils.listener()` form submit binding on IE8 | ||
* [ ] Expose `A` element click event and `FORM` element submit event timeouts (default: 500ms) | ||
[Learn more about contributing to this project](./CONTRIBUTING.md). | ||
## Custom builds | ||
Run the following commands to install and build this project: | ||
```ssh | ||
# Clone the repo | ||
$ git clone https://github.com/keen/keen-tracking.js.git && cd keen-tracking.js | ||
# Install project dependencies | ||
$ npm install | ||
# Build project with gulp | ||
# npm install -g gulp | ||
$ gulp | ||
# Build and launch to view test results | ||
$ gulp with-tests | ||
$ open http://localhost:9000 | ||
``` |
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
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
77582
29
1550
878
3
34
2
+ AddedJSON2@^0.1.0
+ Addedcookies-js@^1.2.1
+ AddedJSON2@0.1.0(transitive)
+ Addedcookies-js@1.2.3(transitive)
- Removedbrowserify-versionify@^1.0.4
- Removedbrowserify-versionify@1.0.6(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removedfind-root@0.1.2(transitive)
- Removedinherits@2.0.4(transitive)
- Removedisarray@0.0.1(transitive)
- Removedreadable-stream@1.0.34(transitive)
- Removedstring_decoder@0.10.31(transitive)
- Removedthrough2@0.6.3(transitive)
- Removedxtend@4.0.2(transitive)