Skip to content

Commit

Permalink
add kissmetrics integration
Browse files Browse the repository at this point in the history
  • Loading branch information
sayan-rudder committed Feb 17, 2020
1 parent 11e6a51 commit afdc0d9
Show file tree
Hide file tree
Showing 3 changed files with 319 additions and 5 deletions.
49 changes: 44 additions & 5 deletions analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,32 @@ class Analytics {
this.processIdentify(userId, traits, options, callback);
}

/**
*
* @param {*} to
* @param {*} from
* @param {*} options
* @param {*} callback
*/
alias(to, from, options, callback) {
if (typeof options == "function") (callback = options), (options = null);
if (typeof from == "function")
(callback = from), (options = null), (from = null);
if (typeof from == "object") (options = from), (from = null);

let rudderElement = new RudderElementBuilder().setType("alias").build();
rudderElement.message.previousId =
from || this.userId ? this.userId : this.getAnonymousId();
rudderElement.message.userId = to;

this.processAndSendDataToDestinations(
"alias",
rudderElement,
options,
callback
);
}

/**
* Send page call to Rudder BE and to initialized integrations
*
Expand Down Expand Up @@ -409,7 +435,9 @@ class Analytics {
);
logger.debug("anonymousId: ", this.anonymousId);
rudderElement["message"]["anonymousId"] = this.anonymousId;
rudderElement["message"]["userId"] = this.userId;
rudderElement["message"]["userId"] = rudderElement["message"]["userId"]
? rudderElement["message"]["userId"]
: this.userId;

if (options) {
this.processOptionsParam(rudderElement, options);
Expand Down Expand Up @@ -498,15 +526,15 @@ class Analytics {
this.storage.clear();
}

getAnonymousId(){
getAnonymousId() {
this.anonymousId = this.storage.getAnonymousId();
if(!this.anonymousId){
if (!this.anonymousId) {
this.setAnonymousId();
}
return this.anonymousId;
}

setAnonymousId(anonymousId){
setAnonymousId(anonymousId) {
this.anonymousId = anonymousId ? anonymousId : generateUUID();
this.storage.setAnonymousId(this.anonymousId);
}
Expand Down Expand Up @@ -578,10 +606,21 @@ if (process.browser) {
let identify = instance.identify.bind(instance);
let page = instance.page.bind(instance);
let track = instance.track.bind(instance);
let alias = instance.alias.bind(instance);
let reset = instance.reset.bind(instance);
let load = instance.load.bind(instance);
let initialized = (instance.initialized = true);
let getAnonymousId = instance.getAnonymousId.bind(instance);
let setAnonymousId = instance.setAnonymousId.bind(instance);

export { initialized, page, track, load, identify, reset, getAnonymousId, setAnonymousId };
export {
initialized,
page,
track,
load,
identify,
reset,
alias,
getAnonymousId,
setAnonymousId
};
272 changes: 272 additions & 0 deletions integrations/Kissmetrics/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
import logger from "../../utils/logUtil";
import { getRevenue } from "../../utils/utils";
import is from "is";
import extend from "@ndhoule/extend";
import { del } from "obj-case";
import each from "component-each";

class Kissmetrics {
constructor(config) {
this.apiKey = config.apiKey;
this.prefixProperties = config.prefixProperties;
this.name = "KISSMETRICS";
}

init() {
logger.debug("===in init Kissmetrics===");
window._kmq = window._kmq || [];

var _kmk = window._kmk || this.apiKey;
function _kms(u) {
setTimeout(function() {
var d = document,
f = d.getElementsByTagName("script")[0],
s = d.createElement("script");
s.type = "text/javascript";
s.async = true;
s.src = u;
f.parentNode.insertBefore(s, f);
}, 1);
}
_kms("//i.kissmetrics.com/i.js");
_kms("//scripts.kissmetrics.com/" + _kmk + ".2.js");

if (this.isEnvMobile()) {
window._kmq.push(["set", { "Mobile Session": "Yes" }]);
}
}

isEnvMobile() {
return (
navigator.userAgent.match(/Android/i) ||
navigator.userAgent.match(/BlackBerry/i) ||
navigator.userAgent.match(/IEMobile/i) ||
navigator.userAgent.match(/Opera Mini/i) ||
navigator.userAgent.match(/iPad/i) ||
navigator.userAgent.match(/iPhone|iPod/i)
);
}

// source :
//https://github.com/segment-integrations/analytics.js-integration-kissmetrics/blob/4213ea776b03fac22dc743c4363dda5ef421137f/lib/index.js#L208
toUnixTimestamp(date) {
date = new Date(date);
return Math.floor(date.getTime() / 1000);
}

// source :
//https://github.com/segment-integrations/analytics.js-integration-kissmetrics/blob/4213ea776b03fac22dc743c4363dda5ef421137f/lib/index.js#L208
clean(obj) {
var ret = {};

for (var k in obj) {
if (obj.hasOwnProperty(k)) {
var value = obj[k];
if (value === null || typeof value === "undefined") continue;

// convert date to unix
if (is.date(value)) {
ret[k] = this.toUnixTimestamp(value);
continue;
}

// leave boolean as is
if (is.bool(value)) {
ret[k] = value;
continue;
}

// leave numbers as is
if (is.number(value)) {
ret[k] = value;
continue;
}

// convert non objects to strings
logger.debug(value.toString());
if (value.toString() !== "[object Object]") {
ret[k] = value.toString();
continue;
}

// json
// must flatten including the name of the original trait/property
var nestedObj = {};
nestedObj[k] = value;
var flattenedObj = this.flatten(nestedObj, { safe: true });

// stringify arrays inside nested object to be consistent with top level behavior of arrays
for (var key in flattenedObj) {
if (is.array(flattenedObj[key])) {
flattenedObj[key] = flattenedObj[key].toString();
}
}

ret = extend(ret, flattenedObj);
delete ret[k];
}
}
return ret;
}

// source :
//https://github.com/segment-integrations/analytics.js-integration-kissmetrics/blob/4213ea776b03fac22dc743c4363dda5ef421137f/lib/index.js#L208
flatten(target, opts) {
opts = opts || {};

var delimiter = opts.delimiter || ".";
var maxDepth = opts.maxDepth;
var currentDepth = 1;
var output = {};

function step(object, prev) {
for (var key in object) {
if (object.hasOwnProperty(key)) {
var value = object[key];
var isarray = opts.safe && is.array(value);
var type = Object.prototype.toString.call(value);
var isobject =
type === "[object Object]" || type === "[object Array]";
var arr = [];

var newKey = prev ? prev + delimiter + key : key;

if (!opts.maxDepth) {
maxDepth = currentDepth + 1;
}

for (var keys in value) {
if (value.hasOwnProperty(keys)) {
arr.push(keys);
}
}

if (!isarray && isobject && arr.length && currentDepth < maxDepth) {
++currentDepth;
return step(value, newKey);
}

output[newKey] = value;
}
}
}

step(target);

return output;
}

// source :
//https://github.com/segment-integrations/analytics.js-integration-kissmetrics/blob/4213ea776b03fac22dc743c4363dda5ef421137f/lib/index.js#L208
prefix(event, properties) {
var prefixed = {};
each(properties, function(key, val) {
if (key === "Billing Amount") {
prefixed[key] = val;
} else if (key === "revenue") {
prefixed[event + " - " + key] = val;
prefixed["Billing Amount"] = val;
} else {
prefixed[event + " - " + key] = val;
}
});
return prefixed;
}

identify(rudderElement) {
logger.debug("in Kissmetrics identify");
let traits = this.clean(rudderElement.message.context.traits);
let userId =
rudderElement.message.userId && rudderElement.message.userId != ""
? rudderElement.message.userId
: undefined;

if (userId) {
window._kmq.push(["identify", userId]);
}
if (traits) {
window._kmq.push(["set", traits]);
}
}

track(rudderElement) {
logger.debug("in Kissmetrics track");

let event = rudderElement.message.event;
let properties = JSON.parse(
JSON.stringify(rudderElement.message.properties)
);
let timestamp = this.toUnixTimestamp(new Date());

let revenue = getRevenue(properties);
if (revenue) {
properties.revenue = revenue;
}

let products = properties.products;
if (products) {
delete properties.products;
}

properties = this.clean(properties);
logger.debug(JSON.stringify(properties));

if (this.prefixProperties) {
properties = this.prefix(event, properties);
}
window._kmq.push(["record", event, properties]);

let iterator = function pushItem(product, i) {
let item = product;
if (this.prefixProperties) item = this.prefix(event, item);
item._t = timestamp + i;
item._d = 1;
window.KM.set(item);
}.bind(this);

if (products) {
window._kmq.push(() => {
each(products, iterator);
});
}
}

page(rudderElement) {
logger.debug("in Kissmetrics page");
const pageName = rudderElement.message.name;
const pageCategory = rudderElement.message.properties
? rudderElement.message.properties.category
: undefined;
var name = "Loaded a Page";
if (pageName) {
name = "Viewed " + pageName + " page";
}
if (pageCategory && pageName) {
name = "Viewed " + pageCategory + " " + pageName + " page";
}

var properties = rudderElement.message.properties;
if (this.prefixProperties) {
properties = this.prefix("Page", properties);
}

window._kmq.push(["record", name, properties]);
}

alias(rudderElement) {
var prev = rudderElement.message.previousId;
var userId = rudderElement.message.userId;
window._kmq.push(["alias", userId, prev]);
}

group(rudderElement) {
logger.debug("group not supported");
}

isLoaded() {
logger.debug("in Kissmetrics isLoaded");
return is.object(window.KM);
}
}

export { Kissmetrics };
3 changes: 3 additions & 0 deletions integrations/Kissmetrics/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Kissmetrics } from "./browser";

export default Kissmetrics;

0 comments on commit afdc0d9

Please sign in to comment.