SlideShare a Scribd company logo
1 of 36
Download to read offline
Seeking the truth from
MOBILE ANALYTICSMouhcine El Amine
@moxy85
PAGE VIEW COUNTING
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-12345678-9', 'auto');
ga('send', 'pageview');
</script>
PAGE VIEW COUNTING MODEL IS
OBSOLETE
EVENT BASED
ANALYTICS
TOOLBOX
NSDictionary *parameters = @{@"Source": @"List"};
[analyticsProvider logEvent:@"Premium feature button tapped"
parameters:parameters];
Experiment &
MEASURE
The purpose of an experiment is to find
the truth.
Not to prove that you are right.
— Joel Marsh (UX Architect)
WELL DESIGNED ANALYTICS
1. Outline business and UX goals
2. Decide the questions you want to answer
3. Map the events to answer your questions
4. Build user paths and conversion funnels from collected data
EXAMPLE
EXPERIMENT
1. Outline business and UX goals
Increase premium features selling
2. Decide the questions you want to answer
Is the "Gallery" label an efficient selling driver ?
3.Map the events to answer your questions
Gallery button tap (List|Grid|Large)
Gallery premium feature invite refusal
Gallery premium feature invite acceptance
Premium feature button tap (List|Detail)
Premium feature buying intent (x€)
Funnel abort (No Ads|User not logged)
4.Build user paths and conversion funnels from collected data
EXPERIMENTS
cannot FAIL!
The only way an experiment can fail is if
the result teaches you nothing.
— Joel Marsh (UX Architect)
BUILDING A ROBUST
TRACKING SOLUTION
SETUP
Objective C
Kiwi + KIF
Private Cocoapods
Flurry
@interface SBTAnalyticsEvent : NSObject
@property (nonatomic, copy, readonly) NSString *name;
@property (nonatomic, copy, readonly) NSDictionary *parameters;
- (instancetype)initWithName:(NSString *)name
parameters:(NSDictionary *)parameters;
//...
@end
NSDictionary *parameters = @{SBTEventParameterLayoutKey: SBTEventParameterLayoutGrid};
SBTAnalyticsEvent *event = [[SBTAnalyticsEvent alloc] initWithName:SBTEventGalleryButtonTap
parameters:parameters];
@interface SBTAnalyticsTracker : NSObject
//...
- (void)trackEvent:(SBTAnalyticsEvent *)event;
//...
@end
@implementation SBTAnalyticsTracker
//...
- (void)trackEvent:(SBTAnalyticsEvent *)event
{
NSCParameterAssert(event);
#ifndef DEBUG
[Flurry logEvent:event.name withParameters:event.parameters];
#endif
}
//...
@end
FAST
FEEDBACK
TAXILOG()
Xcode colors plugin
C Macro
#define XCODE_COLORS_ESCAPE @"033["
// Clear any background and foreground color
#define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE @";"
#define TAXI_COLOR_ESCAPE 
XCODE_COLORS_ESCAPE @"fg0,0,0;"
XCODE_COLORS_ESCAPE @"bg255,204,0;"
#ifdef DEBUG
#define TAXILog(fmt, ...)
NSLog((TAXI_COLOR_ESCAPE fmt XCODE_COLORS_RESET), ##__VA_ARGS__);
#else
#define TAXILog(...)
#endif
BONJOURLOG()
NSLogger
NSLogger Mac client
C Macro
#ifdef DEBUG
#define LOGGER_DEFAULT_OPTIONS(kLoggerOption_BufferLogsUntilConnection | 
kLoggerOption_BrowseBonjour | 
kLoggerOption_BrowseOnlyLocalDomain | 
kLoggerOption_UseSSL)
#define BONJOURLog(fmt, ...) 
LogMessageTo(LoggerGetDefaultLogger(), @"Analytics", 0, fmt, ##__VA_ARGS__);
#else
#define BONJOURLog(...)
#endif
- (void)trackEvent:(SBTAnalyticsEvent *)event
{
NSCParameterAssert(event);
#ifndef DEBUG
[Flurry logEvent:event.name withParameters:event.parameters];
#endif
#ifdef DEBUG
NSString *log = [self logStringForTrackedEvent:event];
TAXILog(@"%@", log);
BONJOURLog(@"%@", log);
#endif
}
AVOIDING REGRESSION WITH
AUTOMATED TESTING
INTEGRATION TESTING WITH KIF
[tester tapViewWithAccessibilityLabel:@"Gallery"];
[tester waitForViewWithAccessibilityLabel:@"This ad is featured"];
[tester tapViewWithAccessibilityLabel:@"No, continue"];
TRACKING EXTENSION FOR KIF
NSDictionary *parameters = @{@"Layout": @"Grid"};
SBTAnalyticsEvent *event = [[SBTAnalyticsEvent alloc] initWithName:@"Gallery button tap"
parameters:@{@"Layout": @"Grid"}];
[tester tapViewWithAccessibilityLabel:@"Gallery"];
[tester checkTrackedAnalyticsEvent:event];
TRACKING EXTENSION FOR KIF
1. Proxy events to a stack
2. Intercept events before test suite begins
3. Answer if an event is in the stack with YES or NO
4. Transform the boolean answer in a test result
1. Proxy events to a stack
@protocol SBTAnalyticsTrackerDelegate <NSObject>
- (void)analyticsTracker:(SBTAnalyticsTracker *)tracker
didTrackEvent:(SBTAnalyticsEvent *)event;
@end
@interface SBTAnalyticsTracker : NSObject
@property (nonatomic, weak) id<SBTAnalyticsTrackerDelegate> delegate;
- (void)trackEvent:(SBTAnalyticsEvent *)event;
//...
@end
- (void)trackEvent:(SBTAnalyticsEvent *)event
{
NSCParameterAssert(event);
#ifndef DEBUG
[Flurry logEvent:event.name withParameters:event.parameters];
#endif
[self.delegate analyticsTracker:self didTrackEvent:event];
#ifdef DEBUG
NSString *log = [self logStringForTrackedEvent:event];
TAXILog(@"%@", log);
BONJOURLog(@"%@", log);
#endif
}
2.Intercept events before test suite begins
CONFIG_START
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SBTAnalyticsEventsStack *stack = [SBTAnalyticsEventsStack sharedAnalyticsEventsStack];
[[SBTAnalyticsTracker sharedTracker] setDelegate:stack];
});
CONFIG_END
3.Answer if an event is in the stack with YES or NO
- (BOOL)popAnalyticsEvent:(SBTAnalyticsEvent *)event
{
__block SBTAnalyticsEvent *expectedEvent;
[self.events enumerateObjectsWithOptions:NSEnumerationReverse
usingBlock:
^(SBTAnalyticsEvent *stackEvent, NSUInteger idx, BOOL *stop) {
if ([stackEvent isEqualToEvent:event]) {
expectedEvent = stackEvent;
*stop = YES;
}
}];
if (!expectedEvent) {
return NO;
}
[self.events removeObject:expectedEvent];
return YES;
}
4.Transform the boolean answer in a test result
@implementation KIFUITestActor (SBTAnalyticsTracking)
- (void)checkTrackedAnalyticsEvent:(SBTAnalyticsEvent *)event
{
[self runBlock:^KIFTestStepResult(NSError *__autoreleasing *error) {
SBTAnalyticsEventsStack *stack = [SBTAnalyticsEventsStack sharedAnalyticsEventsStack];
BOOL eventWasTracked = [stack popAnalyticsEvent:event];
if (eventWasTracked) {
return KIFTestStepResultSuccess;
}
*error = [NSError KIFErrorWithFormat:@"Event not tracked %@", event];
return KIFTestStepResultFailure;
}
timeout:1.0];
}
/...
@end
Q&A
THANKSMouhcine El Amine - @moxy85
mouhcine.elamine@scmitaly.it

More Related Content

What's hot

Let it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive ProgrammingLet it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive ProgrammingArtur Skowroński
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the AirAvitoTech
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSphilogb
 
Do something in 5 with gas 9-copy between databases with oauth2
Do something in 5 with gas 9-copy between databases with oauth2Do something in 5 with gas 9-copy between databases with oauth2
Do something in 5 with gas 9-copy between databases with oauth2Bruce McPherson
 
02 Introduction to Javascript
02 Introduction to Javascript02 Introduction to Javascript
02 Introduction to Javascriptcrgwbr
 
JavaScript Patterns to Cleanup your Code
JavaScript Patterns to Cleanup your CodeJavaScript Patterns to Cleanup your Code
JavaScript Patterns to Cleanup your CodeDan Wahlin
 
Synapse india reviews sharing chapter 23 – asp.net-part2
Synapse india reviews sharing  chapter 23 – asp.net-part2Synapse india reviews sharing  chapter 23 – asp.net-part2
Synapse india reviews sharing chapter 23 – asp.net-part2Synapseindiappsdevelopment
 
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your DataMongoDB
 
Implementation of c string functions
Implementation of c string functionsImplementation of c string functions
Implementation of c string functionsmohamed sikander
 
Scaling up data science applications
Scaling up data science applicationsScaling up data science applications
Scaling up data science applicationsKexin Xie
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScriptersgerbille
 
VBA API for scriptDB primer
VBA API for scriptDB primerVBA API for scriptDB primer
VBA API for scriptDB primerBruce McPherson
 
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...Dan Wahlin
 
Ass day2 1_checkerboard...copy in cpp
Ass day2 1_checkerboard...copy in cppAss day2 1_checkerboard...copy in cpp
Ass day2 1_checkerboard...copy in cppRobi Parvez
 

What's hot (20)

Goa tutorial
Goa tutorialGoa tutorial
Goa tutorial
 
C questions
C questionsC questions
C questions
 
Let it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive ProgrammingLet it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive Programming
 
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
“iOS 11 в App in the Air”, Пронин Сергей, App in the Air
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
 
Include
IncludeInclude
Include
 
Do something in 5 with gas 9-copy between databases with oauth2
Do something in 5 with gas 9-copy between databases with oauth2Do something in 5 with gas 9-copy between databases with oauth2
Do something in 5 with gas 9-copy between databases with oauth2
 
02 Introduction to Javascript
02 Introduction to Javascript02 Introduction to Javascript
02 Introduction to Javascript
 
Final ds record
Final ds recordFinal ds record
Final ds record
 
JavaScript Patterns to Cleanup your Code
JavaScript Patterns to Cleanup your CodeJavaScript Patterns to Cleanup your Code
JavaScript Patterns to Cleanup your Code
 
C program to implement linked list using array abstract data type
C program to implement linked list using array abstract data typeC program to implement linked list using array abstract data type
C program to implement linked list using array abstract data type
 
Synapse india reviews sharing chapter 23 – asp.net-part2
Synapse india reviews sharing  chapter 23 – asp.net-part2Synapse india reviews sharing  chapter 23 – asp.net-part2
Synapse india reviews sharing chapter 23 – asp.net-part2
 
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
[MongoDB.local Bengaluru 2018] Using Change Streams to Keep Up With Your Data
 
Implementation of c string functions
Implementation of c string functionsImplementation of c string functions
Implementation of c string functions
 
Scaling up data science applications
Scaling up data science applicationsScaling up data science applications
Scaling up data science applications
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScripters
 
VBA API for scriptDB primer
VBA API for scriptDB primerVBA API for scriptDB primer
VBA API for scriptDB primer
 
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
Building the an End-to-End ASP.NET MVC 4, Entity Framework, HTML5, jQuery app...
 
FSB Get On Google October 2014
FSB Get On Google October 2014FSB Get On Google October 2014
FSB Get On Google October 2014
 
Ass day2 1_checkerboard...copy in cpp
Ass day2 1_checkerboard...copy in cppAss day2 1_checkerboard...copy in cpp
Ass day2 1_checkerboard...copy in cpp
 

Viewers also liked

портфоліо презентація куніц о.м. нова ортопед.
портфоліо презентація  куніц о.м. нова ортопед.портфоліо презентація  куніц о.м. нова ортопед.
портфоліо презентація куніц о.м. нова ортопед.Елена Кен
 
ґендерне виховання дітей молодшого віку засобами ігор
ґендерне виховання дітей молодшого віку засобами ігорґендерне виховання дітей молодшого віку засобами ігор
ґендерне виховання дітей молодшого віку засобами ігорЕлена Кен
 
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...Елена Кен
 
портфоліо голик н.м.
портфоліо голик н.м.портфоліо голик н.м.
портфоліо голик н.м.Елена Кен
 
портфоліо презентація куніц о.м.
портфоліо презентація  куніц о.м. портфоліо презентація  куніц о.м.
портфоліо презентація куніц о.м. Елена Кен
 
Employee Compensation and Benefits
Employee Compensation and BenefitsEmployee Compensation and Benefits
Employee Compensation and BenefitsMuhammad Adeel
 
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014Max Westphal
 
презентація сталий розвиток міський семінар
презентація сталий розвиток міський семінарпрезентація сталий розвиток міський семінар
презентація сталий розвиток міський семінарЕлена Кен
 

Viewers also liked (13)

новий год
новий годновий год
новий год
 
001
001001
001
 
App Store Optimisation
App Store OptimisationApp Store Optimisation
App Store Optimisation
 
iOS Ecosystem
iOS EcosystemiOS Ecosystem
iOS Ecosystem
 
портфоліо презентація куніц о.м. нова ортопед.
портфоліо презентація  куніц о.м. нова ортопед.портфоліо презентація  куніц о.м. нова ортопед.
портфоліо презентація куніц о.м. нова ортопед.
 
ґендерне виховання дітей молодшого віку засобами ігор
ґендерне виховання дітей молодшого віку засобами ігорґендерне виховання дітей молодшого віку засобами ігор
ґендерне виховання дітей молодшого віку засобами ігор
 
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...
Презентація спеціальної групи для дітей з вадами опрорно-рухового апарату № 8...
 
портфоліо голик н.м.
портфоліо голик н.м.портфоліо голик н.м.
портфоліо голик н.м.
 
гр.№6
гр.№6гр.№6
гр.№6
 
портфоліо презентація куніц о.м.
портфоліо презентація  куніц о.м. портфоліо презентація  куніц о.м.
портфоліо презентація куніц о.м.
 
Employee Compensation and Benefits
Employee Compensation and BenefitsEmployee Compensation and Benefits
Employee Compensation and Benefits
 
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014
Share this image. Das #museumselfie – Workshop KSK Heidelberg 2014, 28.11.2014
 
презентація сталий розвиток міський семінар
презентація сталий розвиток міський семінарпрезентація сталий розвиток міський семінар
презентація сталий розвиток міський семінар
 

Similar to Seeking the truth from mobile analytics

Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Nico Miceli
 
MongoDB dla administratora
MongoDB dla administratora MongoDB dla administratora
MongoDB dla administratora 3camp
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsLudmila Nesvitiy
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesElectronic Arts / DICE
 
Personas: Understanding the User Behind the Visit
Personas: Understanding the User Behind the VisitPersonas: Understanding the User Behind the Visit
Personas: Understanding the User Behind the VisitMichael King
 
Why you should be using structured logs
Why you should be using structured logsWhy you should be using structured logs
Why you should be using structured logsStefan Krawczyk
 
Integrating Angular js & three.js
Integrating Angular js & three.jsIntegrating Angular js & three.js
Integrating Angular js & three.jsJosh Staples
 
Running Intelligent Applications inside a Database: Deep Learning with Python...
Running Intelligent Applications inside a Database: Deep Learning with Python...Running Intelligent Applications inside a Database: Deep Learning with Python...
Running Intelligent Applications inside a Database: Deep Learning with Python...Miguel González-Fierro
 
Google
GoogleGoogle
Googlesoon
 
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Dan Robinson
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQueryPhDBrown
 
Knockoutjs UG meeting presentation
Knockoutjs UG meeting presentationKnockoutjs UG meeting presentation
Knockoutjs UG meeting presentationValdis Iljuconoks
 

Similar to Seeking the truth from mobile analytics (20)

FSB Get on Google - May 2015
FSB Get on Google - May 2015FSB Get on Google - May 2015
FSB Get on Google - May 2015
 
FSB Get on Google March 2015
FSB Get on Google March 2015FSB Get on Google March 2015
FSB Get on Google March 2015
 
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
 
Cómo usar google analytics
Cómo usar google analyticsCómo usar google analytics
Cómo usar google analytics
 
MongoDB dla administratora
MongoDB dla administratora MongoDB dla administratora
MongoDB dla administratora
 
Mongo db dla administratora
Mongo db dla administratoraMongo db dla administratora
Mongo db dla administratora
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applications
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield Heroes
 
Personas: Understanding the User Behind the Visit
Personas: Understanding the User Behind the VisitPersonas: Understanding the User Behind the Visit
Personas: Understanding the User Behind the Visit
 
Why you should be using structured logs
Why you should be using structured logsWhy you should be using structured logs
Why you should be using structured logs
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 
Integrating Angular js & three.js
Integrating Angular js & three.jsIntegrating Angular js & three.js
Integrating Angular js & three.js
 
Running Intelligent Applications inside a Database: Deep Learning with Python...
Running Intelligent Applications inside a Database: Deep Learning with Python...Running Intelligent Applications inside a Database: Deep Learning with Python...
Running Intelligent Applications inside a Database: Deep Learning with Python...
 
Google
GoogleGoogle
Google
 
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
 
JQuery Flot
JQuery FlotJQuery Flot
JQuery Flot
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQuery
 
Knockoutjs UG meeting presentation
Knockoutjs UG meeting presentationKnockoutjs UG meeting presentation
Knockoutjs UG meeting presentation
 

Recently uploaded

Abortion pills in Riyadh+966572737505 cytotec jeddah
Abortion pills in Riyadh+966572737505 cytotec jeddahAbortion pills in Riyadh+966572737505 cytotec jeddah
Abortion pills in Riyadh+966572737505 cytotec jeddahsamsungultra782445
 
Mobile Application Development- Configuration and Android Installation
Mobile Application Development- Configuration and Android InstallationMobile Application Development- Configuration and Android Installation
Mobile Application Development- Configuration and Android InstallationChandrakantDivate1
 
Mobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsMobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsChandrakantDivate1
 
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样原版定制英国伦敦大学金史密斯学院毕业证原件一模一样
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样AS
 
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pure
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pureBromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pure
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pureamy56318795
 
Mobile App Penetration Testing Bsides312
Mobile App Penetration Testing Bsides312Mobile App Penetration Testing Bsides312
Mobile App Penetration Testing Bsides312wphillips114
 
Mobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsMobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsChandrakantDivate1
 
Android Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesAndroid Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesChandrakantDivate1
 

Recently uploaded (9)

Abortion pills in Riyadh+966572737505 cytotec jeddah
Abortion pills in Riyadh+966572737505 cytotec jeddahAbortion pills in Riyadh+966572737505 cytotec jeddah
Abortion pills in Riyadh+966572737505 cytotec jeddah
 
Mobile Application Development- Configuration and Android Installation
Mobile Application Development- Configuration and Android InstallationMobile Application Development- Configuration and Android Installation
Mobile Application Development- Configuration and Android Installation
 
Mobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsMobile Application Development-Components and Layouts
Mobile Application Development-Components and Layouts
 
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样原版定制英国伦敦大学金史密斯学院毕业证原件一模一样
原版定制英国伦敦大学金史密斯学院毕业证原件一模一样
 
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
 
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pure
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pureBromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pure
Bromazolam CAS 71368-80-4 high quality opiates, Safe transportation, 99% pure
 
Mobile App Penetration Testing Bsides312
Mobile App Penetration Testing Bsides312Mobile App Penetration Testing Bsides312
Mobile App Penetration Testing Bsides312
 
Mobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsMobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s Tools
 
Android Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesAndroid Application Components with Implementation & Examples
Android Application Components with Implementation & Examples
 

Seeking the truth from mobile analytics

  • 1. Seeking the truth from MOBILE ANALYTICSMouhcine El Amine @moxy85
  • 2. PAGE VIEW COUNTING <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-12345678-9', 'auto'); ga('send', 'pageview'); </script>
  • 3.
  • 4. PAGE VIEW COUNTING MODEL IS OBSOLETE
  • 6. TOOLBOX NSDictionary *parameters = @{@"Source": @"List"}; [analyticsProvider logEvent:@"Premium feature button tapped" parameters:parameters];
  • 8. The purpose of an experiment is to find the truth. Not to prove that you are right. — Joel Marsh (UX Architect)
  • 9. WELL DESIGNED ANALYTICS 1. Outline business and UX goals 2. Decide the questions you want to answer 3. Map the events to answer your questions 4. Build user paths and conversion funnels from collected data
  • 11. 1. Outline business and UX goals Increase premium features selling 2. Decide the questions you want to answer Is the "Gallery" label an efficient selling driver ?
  • 12. 3.Map the events to answer your questions Gallery button tap (List|Grid|Large) Gallery premium feature invite refusal Gallery premium feature invite acceptance Premium feature button tap (List|Detail) Premium feature buying intent (x€) Funnel abort (No Ads|User not logged)
  • 13. 4.Build user paths and conversion funnels from collected data
  • 15. The only way an experiment can fail is if the result teaches you nothing. — Joel Marsh (UX Architect)
  • 17. SETUP Objective C Kiwi + KIF Private Cocoapods Flurry
  • 18. @interface SBTAnalyticsEvent : NSObject @property (nonatomic, copy, readonly) NSString *name; @property (nonatomic, copy, readonly) NSDictionary *parameters; - (instancetype)initWithName:(NSString *)name parameters:(NSDictionary *)parameters; //... @end
  • 19. NSDictionary *parameters = @{SBTEventParameterLayoutKey: SBTEventParameterLayoutGrid}; SBTAnalyticsEvent *event = [[SBTAnalyticsEvent alloc] initWithName:SBTEventGalleryButtonTap parameters:parameters];
  • 20. @interface SBTAnalyticsTracker : NSObject //... - (void)trackEvent:(SBTAnalyticsEvent *)event; //... @end
  • 21. @implementation SBTAnalyticsTracker //... - (void)trackEvent:(SBTAnalyticsEvent *)event { NSCParameterAssert(event); #ifndef DEBUG [Flurry logEvent:event.name withParameters:event.parameters]; #endif } //... @end
  • 23. TAXILOG() Xcode colors plugin C Macro #define XCODE_COLORS_ESCAPE @"033[" // Clear any background and foreground color #define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE @";" #define TAXI_COLOR_ESCAPE XCODE_COLORS_ESCAPE @"fg0,0,0;" XCODE_COLORS_ESCAPE @"bg255,204,0;" #ifdef DEBUG #define TAXILog(fmt, ...) NSLog((TAXI_COLOR_ESCAPE fmt XCODE_COLORS_RESET), ##__VA_ARGS__); #else #define TAXILog(...) #endif
  • 24. BONJOURLOG() NSLogger NSLogger Mac client C Macro #ifdef DEBUG #define LOGGER_DEFAULT_OPTIONS(kLoggerOption_BufferLogsUntilConnection | kLoggerOption_BrowseBonjour | kLoggerOption_BrowseOnlyLocalDomain | kLoggerOption_UseSSL) #define BONJOURLog(fmt, ...) LogMessageTo(LoggerGetDefaultLogger(), @"Analytics", 0, fmt, ##__VA_ARGS__); #else #define BONJOURLog(...) #endif
  • 25. - (void)trackEvent:(SBTAnalyticsEvent *)event { NSCParameterAssert(event); #ifndef DEBUG [Flurry logEvent:event.name withParameters:event.parameters]; #endif #ifdef DEBUG NSString *log = [self logStringForTrackedEvent:event]; TAXILog(@"%@", log); BONJOURLog(@"%@", log); #endif }
  • 27. INTEGRATION TESTING WITH KIF [tester tapViewWithAccessibilityLabel:@"Gallery"]; [tester waitForViewWithAccessibilityLabel:@"This ad is featured"]; [tester tapViewWithAccessibilityLabel:@"No, continue"];
  • 28. TRACKING EXTENSION FOR KIF NSDictionary *parameters = @{@"Layout": @"Grid"}; SBTAnalyticsEvent *event = [[SBTAnalyticsEvent alloc] initWithName:@"Gallery button tap" parameters:@{@"Layout": @"Grid"}]; [tester tapViewWithAccessibilityLabel:@"Gallery"]; [tester checkTrackedAnalyticsEvent:event];
  • 29. TRACKING EXTENSION FOR KIF 1. Proxy events to a stack 2. Intercept events before test suite begins 3. Answer if an event is in the stack with YES or NO 4. Transform the boolean answer in a test result
  • 30. 1. Proxy events to a stack @protocol SBTAnalyticsTrackerDelegate <NSObject> - (void)analyticsTracker:(SBTAnalyticsTracker *)tracker didTrackEvent:(SBTAnalyticsEvent *)event; @end @interface SBTAnalyticsTracker : NSObject @property (nonatomic, weak) id<SBTAnalyticsTrackerDelegate> delegate; - (void)trackEvent:(SBTAnalyticsEvent *)event; //... @end
  • 31. - (void)trackEvent:(SBTAnalyticsEvent *)event { NSCParameterAssert(event); #ifndef DEBUG [Flurry logEvent:event.name withParameters:event.parameters]; #endif [self.delegate analyticsTracker:self didTrackEvent:event]; #ifdef DEBUG NSString *log = [self logStringForTrackedEvent:event]; TAXILog(@"%@", log); BONJOURLog(@"%@", log); #endif }
  • 32. 2.Intercept events before test suite begins CONFIG_START static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SBTAnalyticsEventsStack *stack = [SBTAnalyticsEventsStack sharedAnalyticsEventsStack]; [[SBTAnalyticsTracker sharedTracker] setDelegate:stack]; }); CONFIG_END
  • 33. 3.Answer if an event is in the stack with YES or NO - (BOOL)popAnalyticsEvent:(SBTAnalyticsEvent *)event { __block SBTAnalyticsEvent *expectedEvent; [self.events enumerateObjectsWithOptions:NSEnumerationReverse usingBlock: ^(SBTAnalyticsEvent *stackEvent, NSUInteger idx, BOOL *stop) { if ([stackEvent isEqualToEvent:event]) { expectedEvent = stackEvent; *stop = YES; } }]; if (!expectedEvent) { return NO; } [self.events removeObject:expectedEvent]; return YES; }
  • 34. 4.Transform the boolean answer in a test result @implementation KIFUITestActor (SBTAnalyticsTracking) - (void)checkTrackedAnalyticsEvent:(SBTAnalyticsEvent *)event { [self runBlock:^KIFTestStepResult(NSError *__autoreleasing *error) { SBTAnalyticsEventsStack *stack = [SBTAnalyticsEventsStack sharedAnalyticsEventsStack]; BOOL eventWasTracked = [stack popAnalyticsEvent:event]; if (eventWasTracked) { return KIFTestStepResultSuccess; } *error = [NSError KIFErrorWithFormat:@"Event not tracked %@", event]; return KIFTestStepResultFailure; } timeout:1.0]; } /... @end
  • 35. Q&A
  • 36. THANKSMouhcine El Amine - @moxy85 mouhcine.elamine@scmitaly.it