a. Analytics Activation Setup your App Delegate
(Only for Objective C code)
#import "R1SDK.h"
#import "R1Emitter.h"
#import "R1Push.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
R1SDK *sdk = [R1SDK sharedInstance];
// Initialize Analytics
sdk.applicationId = @"YOUR APPLICATION ID"; //Ask your RadiumOne contact for an app id
// Start SDK
[sdk start];
return YES;
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sdk = R1SDK.sharedInstance();
// Initialize Anlaytics
sdk.applicationId = "YOUR APPLICATION ID";
// Start SDK
sdk.start();
return true
}
i. Automatic Events
The R1 Connect SDK will automatically capture some generic events in order to get the most meaningful data on how users interact with your app. These events are triggered when the state of the application is changed, and therefore do not require any additional code to work out of the box:
Launch - emitted when the app starts
First Launch - emitted when the app starts for the first time
First Launch After Update - emitted when the app starts for the first time after a version upgrade
Suspend - emitted when the app is put into the background state
Resume - emitted when the app returns from the background state
Application Opened - emitted when the app is opened and can measure when your app is opened after a message is sent
Session Start - emitted when a new session begins
Session End - emitted when a session ends; includes a Session Length attribute with the session length in seconds.
ii. Standard Events
Standard events cover all the main user flows (login, register, share, purchase...) in a standardized format for optimized reporting on the portal, providing a great foundation to your analytics strategy. Once you set them up in your code, they unlock great insights, particularly on user lifetime value.
Note: The last argument in all of the following emitter callbacks, otherInfo, is a dictionary of “key”,”value” pairs or nil, which enables you to customize these events as much as you want.
Login
Tracks a user login within the app
[[R1Emitter sharedInstance] emitLoginWithUserID:@"userId"
userName:@"user_name"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitLoginWithUserID("userId", userName: "user_name", otherInfo: ["custom_key": "value"]);
Registration
Records a user registration within the app
[[R1Emitter sharedInstance] emitRegistrationWithUserID:@"userId"
userName:@"userName"
country:@"country"
state:@"state"
city:@"city"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitRegistrationWithUserID("userId", userName: "userName", country: "country", state: "state", city: "city", otherInfo: ["custom_key": "value"]);
Facebook connect
Allows access to Facebook services
NSArray *permissions = @[[R1EmitterSocialPermission socialPermissionWithName:@"photos" granted:YES]];
[[R1Emitter sharedInstance] emitFBConnectWithPermissions:permissions
otherInfo:@{@"custom_key":@"value"}];
let permissions = [R1EmitterSocialPermission.init(name: "photos", granted: true)];
R1Emitter.sharedInstance()
.emitFBConnectWithPermissions(permissions, otherInfo: ["custom_key": "value"]);
Twitter connect
Allows access to Twitter services
NSArray *permissions = @[[R1EmitterSocialPermission socialPermissionWithName:@"photos" granted:YES]];
[[R1Emitter sharedInstance] emitTConnectWithUserID:@"12345"
userName:@"user_name"
permissions:permissions
otherInfo:@{@"custom_key":@"value"}];
let permissions = [R1EmitterSocialPermission.init(name: "photos", granted: true)];
R1Emitter.sharedInstance()
.emitTConnectWithUserID("12345", userName: "user_name", permissions: permissions, otherInfo: ["custom_key": "value"]);
User Info
Enables you to send user profiles to the backend.
R1EmitterUserInfo *userInfo = [R1EmitterUserInfo userInfoWithUserID:@"userId"
userName:@"userName"
email:@"user@email.com"
firstName:@"first name"
lastName:@"last name"
streetAddress:@"streetAddress"
phone:@"phone"
city:@"city"
state:@"state"
zip:@"zip"];
[[R1Emitter sharedInstance] emitUserInfo:userInfo
otherInfo:@{@"custom_key":@"value"}];
let userInfo = R1EmitterUserInfo.init(userID: "userID", userName: "userName", email: "email", firstName: "firstName", lastName: "lastName", streetAddress: "streetAddress", phone: "phone", city: "city", state: "state", zip: "zip");
R1Emitter.sharedInstance().emitUserInfo(userInfo, otherInfo: ["custom_key": "value"]);
Upgrade
Tracks an application version upgrade
[[R1Emitter sharedInstance] emitUpgradeWithOtherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitUpgradeWithOtherInfo(["custom_key": "value"]);
Trial Upgrade
Tracks an application upgrade from a trial version to a full version
[[R1Emitter sharedInstance] emitTrialUpgradeWithOtherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitTrialUpgradeWithOtherInfo(["custom_key": "value"]);
Screen View
A page view that provides info about that screen
[[R1Emitter sharedInstance] emitScreenViewWithDocumentTitle:@"title"
contentDescription:@"description"
documentLocationUrl:@"http://www.example.com/path"
documentHostName:@"example.com"
documentPath:@"path"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitScreenViewWithDocumentTitle("title", contentDescription: "description", documentLocationUrl: "http://www.example.com/path", documentHostName: "example.com", documentPath: "path", otherInfo:["custom_key": "value"]);
Transaction
[[R1Emitter sharedInstance] emitTransactionWithID:@"transaction_id"
storeID:@"store_id"
storeName:@"store_name"
cartID:@"cart_id"
orderID:@"order_id"
totalSale:1.5
currency:@"USD"
shippingCosts:10.5
transactionTax:12.0
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitTransactionWithID("transaction_id", storeID: "store_id", storeName: "store_name", cartID: "cart_id", orderID: "order_id", totalSale: 1.5, currency: "USD", shippingCosts: 10.5, transactionTax: 12.0, otherInfo:["custom_key": "value"]);
TransactionItem
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitTransactionItemWithTransactionID:@"transaction_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitTransactionItemWithTransactionID("transaction_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
Create Cart
[[R1Emitter sharedInstance] emitCartCreateWithCartID:@"cart_id"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitCartCreateWithCartID("cart_id", otherInfo: ["custom_key": "value"]);
Delete Cart
[[R1Emitter sharedInstance] emitCartDeleteWithCartID:@"cart_id"
otherInfo:@{@"custom_key":@"value"}];
R1Emitter.sharedInstance()
.emitCartDeleteWithCartID("cart_id", otherInfo: ["custom_key": "value"]);
Add To Cart
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitAddToCartWithCartID:@"cart_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitAddToCartWithCartID("cart_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
Delete From Cart
R1EmitterLineItem *lineItem = [R1EmitterLineItem itemWithID:@"product_id"
name:@"product_name"
quantity:5
unitOfMeasure:@"unit"
msrPrice:10
pricePaid:10
currency:@"USD"
itemCategory:@"category"];
[[R1Emitter sharedInstance] emitDeleteFromCartWithCartID:@"cart_id"
lineItem:lineItem
otherInfo:@{@"custom_key":@"value"}];
let lineItem = R1EmitterLineItem.init(
ID: "product_id",
name: "product_name",
quantity: 5,
unitOfMeasure: "unit",
msrPrice: 10,
pricePaid: 10,
currency: "USD",
itemCategory: "category");
R1Emitter.sharedInstance()
.emitDeleteFromCartWithCartID("cart_id", lineItem: lineItem, otherInfo: ["custom_key": "value"]);
iii. Custom Events
Custom events allow you to create and track specific events that are more closely aligned with your app. If planned and structured correctly, custom events can be strong indicators of user intent and behavior. Some examples include pressing the “like” button, playing a song, changing the screen mode from portrait to landscape, and zooming in or out of an image. These are all actions by the user that could be tracked with events.
To include tracking of custom events for the mobile app, the following callbacks need to be included in the application code:
// Emits a custom event without parameters
[[R1Emitter sharedInstance] emitEvent:@"Your custom event name"];
// Emits a custom event with parameters
[[R1Emitter sharedInstance] emitEvent:@"Your custom event name"
withParameters:@{@"key":@"value"}];
// Emits a custom event without parameters
R1Emitter.sharedInstance().emitEvent("Your custom event name");
// Emits a custom event with parameters
R1Emitter.sharedInstance().emitEvent("Your custom event name", withParameters: ["key": "value"]);
iv. In-App Webview Events
By setting up in-app webview events, you can track events that begin inside your native application but are completed in the embedded browser. To do so, you will have to embed some JavaScript in the page that you will want to fire the event, and you need to properly trigger the webview in your application.
JavaScript Setup
To properly fire the event from your webpage, please make the following call:
R1Connect.emitEvent(eventName,eventParameters);
For example, both of the following work. The use of parameters is optional.
R1Connect.emitEvent("Test Event");
R1Connect.emitEvent("Test Event",{"key":"value"});
Additionally, please attach the following r1connect.js file to your webpage:
var R1ConnectBridgePlatforms = {
UNKNOWN: 0,
IOS: 1,
ANDROID: 2
};
window.R1Connect = {
iosBridgeScheme: "r1connectbridge://",
platform: R1ConnectBridgePlatforms.UNKNOWN,
iosURLQueue: [],
iosInProgress: false,
buildIOSUrl: function(eventName, parameters) {
var url = this.iosBridgeScheme + 'emit/?event=' + eventName;
if (parameters)
url += '¶ms='+JSON.stringify(parameters);
return url;
},
sendURLInFrame: function(url) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", encodeURI(url));
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
},
emitEvent: function(eventName, parameters) {
if (this.platform == R1ConnectBridgePlatforms.UNKNOWN) {
if (window.R1ConnectJSInterface && window.R1ConnectJSInterface.emit)
this.platform = R1ConnectBridgePlatforms.ANDROID;
else
this.platform = R1ConnectBridgePlatforms.IOS;
}
if (this.platform == R1ConnectBridgePlatforms.ANDROID) {
window.R1ConnectJSInterface.emit(eventName, parameters ? JSON.stringify(parameters) : '');
return;
}
var iosURL = this.buildIOSUrl(eventName, parameters);
if (this.iosInProgress) {
this.iosURLQueue.push(iosURL);
return;
}
this.iosInProgress = true;
this.sendURLInFrame(iosURL);
},
iosURLReceived: function() {
setTimeout(function() {
window.R1Connect._iosURLReceived();
}, 0);
},
_iosURLReceived: function() {
if (this.iosURLQueue.length == 0) {
this.iosInProgress = false;
return;
}
var iosURL = this.iosURLQueue.shift();
this.sendURLInFrame(iosURL);
},
};
To properly handle the events in your application, you first need to import the R1WebViewHelper header file in your ViewController .m implementation file:
(Only for Objective C code)
#import "R1WebViewHelper.h"
You then should setup the UIWebView delegate from the Interface Builder or from code:
- (void) viewDidLoad {
[super viewDidLoad];
self.webView.delegate = self;
// Your code here
}
override func viewDidLoad() {
super.viewDidLoad();
webView?.delegate = self;
// Your code here
}
Finally, add the delegate method implementation:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (![R1WebViewHelper webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]) return NO; // Your code here return YES; }
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if R1WebViewHelper.webView(webView, shouldStartLoadWithRequest: request, navigationType: navigationType) {
return false;
}
// Your code here
return true;
}
v. Best Practices
Event Naming Convention
One common mistake is to parametrize event names (with user data for example). Event names should be hard-coded values that you use to segement data on a specific category of event.
Example: "ProfileViewing"
Avoid: "Profile Viewing - Lady Gaga's profile"
As you may have thousands of user profiles in your database, it is preferable to keep the event name high level ("ProfileViewing") so you can run interesting anaytics on it. High level events help answer questions like "how many profiles does a user visit every day on average?"
Parameter Variance
Another common mistake is to add parameters to the event that have too many possible values. To follow up on the previous example, one may decide to add the number of profile followers as an event parameter:
[[R1Emitter sharedInstance] emitEvent:@"ProfileViewing"
withParameters:@{@"profileFollowers":profileFollowers}];
R1Emitter.sharedInstance()
.emitEvent("ProfileViewing", withParameters: ["profileFollowers": profileFollowers]);
Again, the problem here is that each profile may have any number of followers. This will fragment your data too much to extract any valuable information.
A good strategy would be to define relevant buckets for high variance parameters. In this case, it might be more relevant to separate traffic on the profiles with a lot of followers from traffic on profiles with very few followers. You could define 3 categories:
- "VERY_INFLUENTIAL" for profiles > 100,000
- "INFLUENTIAL" for profile > 10,000 and <= 100,000
- "NON_INFLUENTIAL" for profile <= 10,000
A proper event could be
[[R1Emitter sharedInstance] emitEvent:@"ProfileViewing"
withParameters:@{@"profileFollowersBucket":@"VERY_INFLUENTIAL"}];
R1Emitter.sharedInstance()
.emitEvent("ProfileViewing", withParameters: ["profileFollowersBucket": "VERY_INFLUENTIAL"]);
This will enable you to create more insightful reports.
0 Comments