2014-12-15 13:19:20 -08:00
# Parse subscription conversion rates via Mixpanel raw export API
import sys
from datetime import tzinfo , timedelta , datetime
from mixpanel import Mixpanel
try :
import json
except ImportError :
import simplejson as json
# NOTE: mixpanel dates are by day and inclusive
# E.g. '2014-12-08' is any date that day, up to 2014-12-09 12am
def printPriceConversionRates ( api_key , api_secret , startDate , endDate ) :
# dateCreated is in UTC
# Dec 8th subscribe copy A/B test added
# 599 - 1st HoC 599 sale started: Dec 9 6:23am PST
# 999 - 1st HoC 599 sale ended: Dec 10 4:34pm PST
# 1499 - sub price test starts: Dec 10 5:00pm PST
# Only for dateCreated >= 5pm PST
# 399 - 2nd HoC 399 sale started: Dec 11 7:21pm PST
# 999 - 2nd HoC sale ended: Dec 13 9:30am PST
# UTC is +8 hrs
api = Mixpanel (
api_key = api_key ,
api_secret = api_secret
)
print ' Requesting Mixpanel data '
# data = api.request(['events'], {
# 'event' : ['Finished subscription purchase',],
# 'unit' : 'hour',
# 'interval' : 24,
# 'type': 'general'
# })
# data = api.request(['funnels', 'list'], {})
data = api . request ( [ ' export ' ] , {
' event ' : [ ' Show subscription modal ' , ' Finished subscription purchase ' , ] ,
# 'event' : ['Finished subscription purchase',],
# 'event' : ['Show subscription modal',],
' from_date ' : startDate ,
' to_date ' : endDate
} )
prices = {
' 399 ' : {
' start ' : datetime ( 2014 , 12 , 12 , 3 , 21 ) ,
' end ' : datetime ( 2014 , 12 , 13 , 17 , 30 )
} ,
' 599 ' : {
' start ' : datetime ( 2014 , 12 , 9 , 14 , 23 ) ,
' end ' : datetime ( 2014 , 12 , 11 , 0 , 34 )
} ,
' 999 ' : {
' start ' : datetime ( 2014 , 9 , 1 ) ,
' end ' : datetime ( 2014 , 12 , 9 , 14 , 23 ) ,
' start2 ' : datetime ( 2014 , 12 , 11 , 0 , 34 ) ,
' end2 ' : datetime ( 2014 , 12 , 12 , 3 , 21 ) ,
' start3 ' : datetime ( 2014 , 12 , 13 , 17 , 30 )
} ,
' 1499 ' : {
' start ' : datetime ( 2014 , 12 , 11 , 1 ) ,
' end ' : datetime ( 2014 , 12 , 12 , 3 , 21 )
}
}
# id vs distinct_id ?
def addEvent ( price , event , id ) :
if not event in price :
price [ event ] = { }
price [ event ] [ id ] = True
elif not id in price [ event ] :
price [ event ] [ id ] = True
def getPriceStr ( eventDateStr , userDateStr ) :
priceStr = ' 999 '
eventCreated = datetime . utcfromtimestamp ( int ( eventDateStr ) )
# Put events in buckets based on creation times
if eventCreated > = prices [ ' 599 ' ] [ ' start ' ] and eventCreated < prices [ ' 599 ' ] [ ' end ' ] :
priceStr = ' 599 '
elif eventCreated > = prices [ ' 999 ' ] [ ' start2 ' ] and eventCreated < prices [ ' 999 ' ] [ ' end2 ' ] :
# In 999/1499 zone
# Create a datetime from: 2014-12-11T12:37:59
userCreated = datetime ( int ( userDateStr [ 0 : 4 ] ) , int ( userDateStr [ 5 : 7 ] ) , int ( userDateStr [ 8 : 10 ] ) , int ( userDateStr [ 11 : 13 ] ) , int ( userDateStr [ 14 : 16 ] ) , int ( userDateStr [ 17 : 19 ] ) )
if userCreated > = prices [ ' 1499 ' ] [ ' start ' ] :
priceStr = ' 1499 '
elif eventCreated > = prices [ ' 399 ' ] [ ' start ' ] and eventCreated < prices [ ' 399 ' ] [ ' end ' ] :
priceStr = ' 399 '
return priceStr
lines = data . split ( ' \n ' )
print " Received %d entries " % len ( lines )
for line in lines :
try :
if len ( line ) is 0 : continue
event = json . loads ( line )
properties = event [ ' properties ' ]
if not event [ ' event ' ] in [ ' Show subscription modal ' , ' Finished subscription purchase ' ] :
print ' Unexpected event ' + event [ ' event ' ]
break
# print 'Processing', event['event'], properties['time'], properties['dateCreated']
if ' dateCreated ' in properties and ' time ' in properties and ' distinct_id ' in properties :
# NOTE: mixpanel conversions don't account for refunds
# NOTE: So we have an extra 1499 hit for mattcc4021@gmaIl.com / 5488ee8a600bc8b206771ba3
if properties [ ' distinct_id ' ] == ' 5488ee8a600bc8b206771ba3 ' :
# ch_155tz8KaReE7xLUdQpsa9aqe, cus_5GQqAosNHuRQCQ
# print 'Skipping mattcc4021@gmaIl.com / 5488ee8a600bc8b206771ba3'
# print event['event'], properties['distinct_id']
continue
# if properties['distinct_id'] == '54790dacfd5b8f550584aaf3':
# print 'Found a time example 54790dacfd5b8f550584aaf3'
# print properties['time'], datetime.utcfromtimestamp(int(properties['time']))
priceStr = getPriceStr ( properties [ ' time ' ] , properties [ ' dateCreated ' ] )
# if priceStr == '1499' and event['event'] == 'Finished subscription purchase':
# print 'Found a 1499 payment', properties['distinct_id']
addEvent ( prices [ priceStr ] , event [ ' event ' ] , properties [ ' distinct_id ' ] )
except :
print " Unexpected error: " , sys . exc_info ( ) [ 0 ]
print line
break
print ' Price, converted, shown, conversion rate, value per user '
for key , item in prices . iteritems ( ) :
# 'Show subscription modal', 'Finished subscription purchase'
converted = shown = 0
if ' Finished subscription purchase ' in item :
converted = len ( item [ ' Finished subscription purchase ' ] . keys ( ) )
if ' Show subscription modal ' in item :
shown = len ( item [ ' Show subscription modal ' ] . keys ( ) )
if shown > 0 :
print key , converted , shown , " %.4f %% " % ( float ( converted ) / shown * 100 ) , " %.4f cents " % ( float ( converted ) / shown * int ( key ) )
else :
print key , converted , shown
def getShownSubModal ( api_key , api_secret , startDate , endDate ) :
# print 'Requesting Mixpanel data'
api = Mixpanel (
api_key = api_key ,
api_secret = api_secret
)
data = api . request ( [ ' export ' ] , {
' event ' : [ ' Show subscription modal ' , ] ,
' from_date ' : startDate ,
' to_date ' : endDate
} )
uniques = set ( )
# biggestDate = 0
lines = data . split ( ' \n ' )
# print "Received %d entries" % len(lines)
for line in lines :
try :
if len ( line ) is 0 : continue
event = json . loads ( line )
properties = event [ ' properties ' ]
if not event [ ' event ' ] in [ ' Show subscription modal ' ] :
print ' Unexpected event ' + event [ ' event ' ]
break
# print 'Processing', event['event'], properties['time'], properties['dateCreated']
if ' distinct_id ' in properties and not properties [ ' distinct_id ' ] in uniques :
uniques . add ( properties [ ' distinct_id ' ] )
# if int(properties['time']) > biggestDate:
# biggestDate = int(properties['time'])
except :
print " Unexpected error: " , sys . exc_info ( ) [ 0 ]
print line
break
# print 'Biggest date:', datetime.utcfromtimestamp(int(properties['time']))
return len ( uniques )
if __name__ == ' __main__ ' :
if not len ( sys . argv ) is 3 :
print " Script format: <script> <api_key> <api_secret> "
else :
api_key = sys . argv [ 1 ]
api_secret = sys . argv [ 2 ]
# HoC
2015-01-05 11:23:42 -08:00
printPriceConversionRates ( api_key , api_secret , ' 2014-12-08 ' , ' 2014-12-19 ' )
2014-12-15 13:19:20 -08:00
# Use these to feed numbers into Stripe parsing script, since Stripe knows better about conversions than Mixpanel
print ' Pre-HoC shown ' , getShownSubModal ( api_key , api_secret , ' 2014-12-06 ' , ' 2014-12-07 ' )
2015-01-05 11:23:42 -08:00
print ' Post-HoC shown ' , getShownSubModal ( api_key , api_secret , ' 2014-12-20 ' , ' 2015-01-04 ' )