codecombat/app/core/Tracker.coffee
Matt Lott c4620a7b2d Refactor analytics event logging
Clean up property slimming.
Save explicit identity traits in properties.
2015-02-09 15:03:04 -08:00

105 lines
4.9 KiB
CoffeeScript

{me} = require 'core/auth'
SuperModel = require 'models/SuperModel'
debugAnalytics = false
module.exports = class Tracker
constructor: ->
if window.tracker
console.error 'Overwrote our Tracker!', window.tracker
window.tracker = @
@isProduction = document.location.href.search('codecombat.com') isnt -1
@identify()
@supermodel = new SuperModel()
identify: (traits={}) ->
# Save explicit traits for internal tracking
@explicitTraits ?= {}
@explicitTraits[key] = value for key, value of traits
console.log 'Would identify', traits if debugAnalytics
return unless me and @isProduction and analytics? and not me.isAdmin()
# https://segment.io/docs/methods/identify
for userTrait in ['email', 'anonymous', 'dateCreated', 'name', 'wizardColor1', 'testGroupNumber', 'gender', 'lastLevel']
traits[userTrait] ?= me.get(userTrait)
analytics.identify me.id, traits
trackPageView: (virtualName=null, includeIntegrations=null) ->
# console.log 'trackPageView', virtualName, includeIntegrations
# Google Analytics does not support event-based funnels, so we have to use virtual pageviews instead
# https://support.google.com/analytics/answer/1032720?hl=en
name = virtualName ? Backbone.history.getFragment()
properties = {}
if virtualName?
# Override title and path properties for virtual page view
# https://segment.com/docs/libraries/analytics.js/#page
properties =
title: name
path: "/#{name}"
options = {}
if includeIntegrations?
options = integrations: {'All': false}
for integration in includeIntegrations
options.integrations[integration] = true
console.log "Would track analytics pageview: '/#{name}'", properties, options, includeIntegrations if debugAnalytics
return unless @isProduction and analytics? and not me.isAdmin()
# Ok to pass empty properties, but maybe not options
# TODO: What happens when we pass empty options?
if _.isEmpty options
# console.log "trackPageView without options '/#{name}'", properties, options
analytics.page "/#{name}"
else
# console.log "trackPageView with options '/#{name}'", properties, options
analytics.page "/#{name}", properties, options
trackEvent: (action, properties, includeIntegrations=null) =>
# 'action' is a string
# Google Analytics properties format: {category: 'Account', label: 'Premium', value: 50 }
# https://segment.com/docs/integrations/google-analytics/#track
# https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#Anatomy
# Mixpanel properties format: whatever you want unlike GA
# https://segment.com/docs/integrations/mixpanel/
properties = properties or {}
@trackEventInternal action, _.cloneDeep properties unless me?.isAdmin() and @isProduction
console.log 'Would track analytics event:', action, properties, includeIntegrations if debugAnalytics
return unless me and @isProduction and analytics? and not me.isAdmin()
context = {}
if includeIntegrations
# https://segment.com/docs/libraries/analytics.js/#selecting-integrations
context.integrations = {'All': false}
for integration in includeIntegrations
context.integrations[integration] = true
analytics?.track action, properties, context
trackEventInternal: (event, properties) =>
# Skipping heavily logged actions we don't use internally
unless event in ['Simulator Result', 'Started Level Load', 'Finished Level Load']
# Trimming properties we don't use internally
# TODO: delete properites.level for 'Saw Victory' after 2/8/15. Should be using levelID instead.
if event in ['Clicked Start Level', 'Inventory Play', 'Heard Sprite', 'Started Level', 'Saw Victory', 'Click Play', 'Choose Inventory', 'Loaded World Map', 'Homepage Loaded', 'Change Hero']
delete properties.category
delete properties.label
else if event in ['Started Signup', 'Finished Signup', 'Login', 'Facebook Login', 'Google Login', 'Show subscription modal']
delete properties.category
properties[key] = value for key, value of @explicitTraits if @explicitTraits?
console.log 'Tracking internal analytics event:', event, properties if debugAnalytics
request = @supermodel.addRequestResource 'log_event', {
url: '/db/analytics_log_event/-/log_event'
data: {event: event, properties: properties}
method: 'POST'
}, 0
request.load()
trackTiming: (duration, category, variable, label, samplePercentage=5) ->
# https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTiming
return console.warn "Duration #{duration} invalid for trackTiming call." unless duration >= 0 and duration < 60 * 60 * 1000
console.log 'Would track timing event:', arguments if debugAnalytics
window._gaq?.push ['_trackTiming', category, variable, duration, label, samplePercentage]