This is a little CommonJS library I put together for adding Mixpanel tracking to an iOS and Android Appcelerator Titanium app I built. YMMV. I'm sharing it since I hadn't seen anything similar, and Mixpanel rocks. There are no native dependencies. All Mixpanel API calls are made by using the HTTP specification (https://mixpanel.com/docs/api-documentation/http-specification-insert-data) when the network is available. Event tracking, people properties and aliasing are supported.
It pulls the Mixpanel token from tiapp.xml: your-token-here
// The currentUser lib stores a model representing the logged in user, and other login state information
var currentUser = require('currentUser');
// Logger is a Ti.API.info() wrapper with a bit more flexibility
var logger = require('logger');
var messageQueue = []; // put this into local storage at some point to retain recent offline events before crashes
var messageInTransit = null;
var token = Ti.App.Properties.getString('mixpanel.token');
var systemProperties = {
mobile_osname: Ti.Platform.osname,
mobile_ostype: Ti.Platform.ostype,
mobile_osversion: Ti.Platform.version,
mobile_device_mfg: Ti.Platform.manufacturer,
mobile_device_model: Ti.Platform.model,
mobile_locale: Ti.Platform.locale
};
var uuid = Ti.Platform.createUUID();
exports.track = function(event, properties) {
logger.info('mixpanel track ' + event);
properties = properties || {};
properties = _.extend(properties, systemProperties);
properties.time = (new Date()).getTime();
properties.token = token;
properties.distinct_id = currentUser.isLoggedIn ? currentUser.user.get('email') : uuid;
event = "(App) " + event;
messageQueue.push({
payload: {
event: event,
properties: properties
},
type: 'event'
});
sendNextMessage();
};
exports.alias = function() {
if(currentUser.isLoggedIn) {
logger.info('mixpanel alias');
messageQueue.push({
payload: {
event: '$create_alias',
properties: {
"alias": currentUser.user.get('email'),
"distinct_id": uuid,
"time": (new Date()).getTime(),
"token": token
}
},
type: 'event'
});
sendNextMessage();
}
};
exports.people = {
set: function(properties) {
properties = properties || {};
logger.info('mixpanel people.set ' + properties);
if(!currentUser.isLoggedIn) {
console.log('mixpanel people.set skipped - user not logged in');
return false;
}
properties = _.extend(properties, systemProperties);
properties = _.extend(properties, {
'$first_name': currentUser.user.get('first_name'),
'$last_name': currentUser.user.get('last_name'),
'$username': currentUser.user.get('username'),
'$email': currentUser.user.get('email'),
});
var payload = {
'$set': properties,
'$token': token,
'$distinct_id': currentUser.user.get('email')
};
messageQueue.push({
payload: payload,
type: 'people.set'
});
sendNextMessage();
}
};
function sendMessage(message) {
var url = '';
if(message.type == 'event') {
url = "http://api.mixpanel.com/track/?data=" + Titanium.Utils.base64encode(JSON.stringify(message.payload)) + "&ip=1";
} else if(message.type == 'people.set') {
url = "http://api.mixpanel.com/engage/?data=" + Titanium.Utils.base64encode(JSON.stringify(message.payload));
}
xhr = Titanium.Network.createHTTPClient({
onload : function(e) {
messageInTransit = false;
messageQueue.shift();
sendNextMessage();
},
onerror: function(e){
messageInTransit = false;
logger.info('Failed mixpanel event with status ' + this.status + ' and error : ' + JSON.stringify(e));
setTimeout(function() {
sendNextMessage();
}, 2000); // wait a couple of seconds before we try this again
},
timeout: config.imageUploadTimeout
});
xhr.open('POST', url);
xhr.send();
}
function sendNextMessage() {
if(!Ti.Network.online) {
setTimeout(sendNextMessage, 10000);
return false;
}
if(messageInTransit)
return false;
if(messageQueue.length > 0) {
messageInTransit = messageQueue[0]; // FIFO
sendMessage(messageInTransit);
}
}