2014-11-28 20:49:41 -05:00
|
|
|
{me} = require 'core/auth'
|
2015-01-14 20:51:04 -05:00
|
|
|
SuperModel = require 'models/SuperModel'
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2015-01-31 17:38:54 -05:00
|
|
|
debugAnalytics = false
|
2014-04-13 23:31:23 -04:00
|
|
|
|
2014-01-03 13:32:13 -05:00
|
|
|
module.exports = class Tracker
|
|
|
|
constructor: ->
|
|
|
|
if window.tracker
|
2014-06-30 22:16:26 -04:00
|
|
|
console.error 'Overwrote our Tracker!', window.tracker
|
2014-01-03 13:32:13 -05:00
|
|
|
window.tracker = @
|
2014-06-30 22:16:26 -04:00
|
|
|
@isProduction = document.location.href.search('codecombat.com') isnt -1
|
2014-01-03 13:32:13 -05:00
|
|
|
@identify()
|
2015-01-14 20:51:04 -05:00
|
|
|
@supermodel = new SuperModel()
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2015-02-09 18:02:45 -05:00
|
|
|
identify: (traits={}) ->
|
|
|
|
# Save explicit traits for internal tracking
|
|
|
|
@explicitTraits ?= {}
|
|
|
|
@explicitTraits[key] = value for key, value of traits
|
|
|
|
|
2014-06-30 22:16:26 -04:00
|
|
|
console.log 'Would identify', traits if debugAnalytics
|
2014-11-27 23:55:28 -05:00
|
|
|
return unless me and @isProduction and analytics? and not me.isAdmin()
|
2014-01-03 13:32:13 -05:00
|
|
|
# https://segment.io/docs/methods/identify
|
2015-01-28 20:58:56 -05:00
|
|
|
for userTrait in ['email', 'anonymous', 'dateCreated', 'name', 'wizardColor1', 'testGroupNumber', 'gender', 'lastLevel']
|
2014-01-03 13:32:13 -05:00
|
|
|
traits[userTrait] ?= me.get(userTrait)
|
|
|
|
analytics.identify me.id, traits
|
|
|
|
|
2014-12-02 16:25:12 -05:00
|
|
|
trackPageView: (virtualName=null, includeIntegrations=null) ->
|
|
|
|
# console.log 'trackPageView', virtualName, includeIntegrations
|
2014-11-30 17:14:44 -05:00
|
|
|
# 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
|
2014-12-02 16:25:12 -05:00
|
|
|
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
|
2014-12-18 00:53:59 -05:00
|
|
|
properties =
|
2014-12-02 16:25:12 -05:00
|
|
|
title: name
|
|
|
|
path: "/#{name}"
|
|
|
|
|
|
|
|
options = {}
|
|
|
|
if includeIntegrations?
|
2014-11-30 18:27:12 -05:00
|
|
|
options = integrations: {'All': false}
|
2014-11-30 17:14:44 -05:00
|
|
|
for integration in includeIntegrations
|
|
|
|
options.integrations[integration] = true
|
2014-12-02 16:25:12 -05:00
|
|
|
|
2014-12-08 14:34:39 -05:00
|
|
|
console.log "Would track analytics pageview: '/#{name}'", properties, options, includeIntegrations if debugAnalytics
|
2014-12-02 16:25:12 -05:00
|
|
|
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
|
2014-12-18 00:53:59 -05:00
|
|
|
# console.log "trackPageView without options '/#{name}'", properties, options
|
2014-11-30 17:14:44 -05:00
|
|
|
analytics.page "/#{name}"
|
2014-12-02 16:25:12 -05:00
|
|
|
else
|
2014-12-18 00:53:59 -05:00
|
|
|
# console.log "trackPageView with options '/#{name}'", properties, options
|
2014-12-02 16:25:12 -05:00
|
|
|
analytics.page "/#{name}", properties, options
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2014-11-30 01:16:18 -05:00
|
|
|
trackEvent: (action, properties, includeIntegrations=null) =>
|
2014-11-28 15:05:34 -05:00
|
|
|
# '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/
|
2015-01-09 12:27:29 -05:00
|
|
|
properties = properties or {}
|
|
|
|
|
2015-01-20 17:08:19 -05:00
|
|
|
@trackEventInternal action, _.cloneDeep properties unless me?.isAdmin() and @isProduction
|
2015-01-09 12:27:29 -05:00
|
|
|
|
2014-12-08 14:34:39 -05:00
|
|
|
console.log 'Would track analytics event:', action, properties, includeIntegrations if debugAnalytics
|
2014-11-27 23:55:28 -05:00
|
|
|
return unless me and @isProduction and analytics? and not me.isAdmin()
|
2014-01-03 13:32:13 -05:00
|
|
|
context = {}
|
2014-11-30 01:16:18 -05:00
|
|
|
if includeIntegrations
|
|
|
|
# https://segment.com/docs/libraries/analytics.js/#selecting-integrations
|
|
|
|
context.integrations = {'All': false}
|
|
|
|
for integration in includeIntegrations
|
|
|
|
context.integrations[integration] = true
|
2014-11-28 15:05:34 -05:00
|
|
|
analytics?.track action, properties, context
|
2014-12-18 00:53:59 -05:00
|
|
|
|
2015-01-14 20:51:04 -05:00
|
|
|
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
|
2015-02-09 18:02:45 -05:00
|
|
|
# TODO: delete properites.level for 'Saw Victory' after 2/8/15. Should be using levelID instead.
|
2015-02-10 17:20:14 -05:00
|
|
|
if event in ['Clicked Start Level', 'Inventory Play', 'Heard Sprite', 'Started Level', 'Saw Victory', 'Click Play', 'Choose Inventory', 'Homepage Loaded', 'Change Hero']
|
2015-01-28 20:58:56 -05:00
|
|
|
delete properties.category
|
2015-01-14 20:51:04 -05:00
|
|
|
delete properties.label
|
2015-02-10 17:20:14 -05:00
|
|
|
else if event in ['Loaded World Map', 'Started Signup', 'Finished Signup', 'Login', 'Facebook Login', 'Google Login', 'Show subscription modal']
|
2015-01-28 20:58:56 -05:00
|
|
|
delete properties.category
|
2015-01-15 14:04:48 -05:00
|
|
|
|
2015-02-09 18:02:45 -05:00
|
|
|
properties[key] = value for key, value of @explicitTraits if @explicitTraits?
|
2015-02-27 13:45:08 -05:00
|
|
|
eventObject = {}
|
|
|
|
eventObject["event"] = event
|
|
|
|
eventObject["properties"] = properties unless _.isEmpty properties
|
|
|
|
eventObject["user"] = me.id
|
2015-01-14 20:51:04 -05:00
|
|
|
console.log 'Tracking internal analytics event:', event, properties if debugAnalytics
|
2015-02-27 13:45:08 -05:00
|
|
|
dataToSend = JSON.stringify eventObject
|
|
|
|
console.log dataToSend if debugAnalytics
|
|
|
|
$.post("http://analytics.codecombat.com/analytics", dataToSend).fail ->
|
|
|
|
console.error "Analytics post failed!"
|
2014-04-13 23:31:23 -04:00
|
|
|
|
|
|
|
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
|
2014-06-30 22:16:26 -04:00
|
|
|
console.log 'Would track timing event:', arguments if debugAnalytics
|
2014-04-13 23:31:23 -04:00
|
|
|
window._gaq?.push ['_trackTiming', category, variable, duration, label, samplePercentage]
|