Appearance
Custom Events
Any event that could not be accommodated through predefined events, can be created through Custom Events.
Overview
Custom events allow you to track specific user interactions and business events that are unique to your application. These events provide detailed insights into user behavior and help you understand how users interact with your app's features.
Types of Events
Events in Upshot.ai are classified as timed and non-timed events.
Non-Timed Events
An event where the start time and an end time are the same is a non-timed event.
Example: A button has been clicked. It does not matter how long the button has been pressed for, this is a non-timed event, where you are only interested in the fact that the button has been clicked.
Timed Events
An event which has different start and end times is a timed event. Timed events have to be closed for the provided eventId. Timed events can be closed in two ways: Set Data And close the created event or simply close the event for the eventId.
Example: A game level takes 30 seconds to finish. So a "game level played" event starts at X and ends at Y. There's a time component associated with the event here, hence it is considered as a timed event.
Creating Custom Events
Basic Usage
objective-c
// Create a custom event
NSDictionary *eventPayload = @{
@"level": @"level_1",
@"score": @100,
@"difficulty": @"easy"
};
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"game_level_completed" params: eventPayload isTimed: NO];
swift
// Create a custom event
let eventPayload = [
"level": "level_1",
"score": 100,
"difficulty": "easy"
] as [String : Any]
let eventId = BrandKinesis.sharedInstance().createEvent("game_level_completed", params: eventPayload, isTimed:false)
Timed Events
For events that have a duration, use timed events:
objective-c
// Create a timed event
NSDictionary *eventPayload = @{
@"level": @"level_1",
@"difficulty": @"hard"
};
// Start the timed event
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"game_session" params: eventPayload isTimed: YES];
// Later, when the event ends, close it
[[Brandkinesis sharedInstance] closeEventForID:eventId];
swift
// Create a timed event
let eventPayload = [
"level": "level_1",
"difficulty": "hard"
] as [String : Any]
// Start the timed event
let eventId = BrandKinesis.sharedInstance().createEvent("game_session", params: eventPayload, isTimed:true)
// Later, when the event ends, close it
BrandKinesis.sharedInstance(). closeEvent(forID: eventId)
Event Properties
Properties provide context for events and help you understand user behavior better:
objective-c
// Example with multiple property types
NSDictionary *properties = @{
@"string_prop": @"value",
@"number_prop": @42,
@"bool_prop": @YES,
@"date_prop": @([[NSDate date] timeIntervalSince1970] * 1000), // Timestamp in milliseconds
@"user_level": @5,
@"category": @"gaming"
};
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"custom_event" params: properties isTimed: NO];
swift
// Example with multiple property types
let properties = [
"string_prop": "value",
"number_prop": 42,
"bool_prop": true,
"date_prop": Date().timeIntervalSince1970 * 1000, // Timestamp in milliseconds
"user_level": 5,
"category": "gaming"
] as [String : Any]
let *eventId = BrandKinesis.sharedInstance().createEvent("custom_event", params: properties, isTimed:false)
Best Practices
- Use descriptive event names - Make event names clear and consistent
- Include relevant properties - Add context that helps with analysis
- Handle timed events properly - Always close timed events to avoid memory leaks
- Use consistent data types - Maintain consistency across similar events
- Don't over-track - Focus on meaningful events that provide business value
Advanced Examples
E-commerce Events
objective-c
// Track product purchase
- (void)trackProductPurchase:(NSString *)productId price:(NSDecimalNumber *)price currency:(NSString *)currency {
NSDictionary *purchaseData = @{
@"product_id": productId,
@"price": price,
@"currency": currency,
@"purchase_timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
};
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"product_purchased" params: purchaseData isTimed: NO];
}
// Track product view (timed)
- (void)startProductView:(NSString *)productId {
NSDictionary *viewData = @{
@"product_id": productId,
@"category": @"electronics",
@"view_start_time": @([[NSDate date] timeIntervalSince1970] * 1000)
};
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"product_viewed" params: viewData isTimed: YES];
}
// Close product view
- (void)endProductView {
NSString *eventId = [self getEventIdForKey:@"product_view"];
if (eventId) {
[[Brandkinesis sharedInstance] closeEventForID:eventId];
}
}
swift
// Track product purchase
func trackProductPurchase(productId: String, price: Decimal, currency: String) {
let purchaseData: [String: Any] = [
"product_id": productId,
"price": price,
"currency": currency,
"purchase_timestamp": Date().timeIntervalSince1970 * 1000
]
let eventId = BrandKinesis.sharedInstance().createEvent("product_purchased", params: purchaseData, isTimed:false)
}
// Track product view (timed)
func startProductView(productId: String) {
let viewData: [String: Any] = [
"product_id": productId,
"category": "electronics",
"view_start_time": Date().timeIntervalSince1970 * 1000
]
let eventId = BrandKinesis.sharedInstance().createEvent("product_viewed", params: purchaseData, isTimed:true)
}
// Close product view
func endProductView() {
if let eventId = getEventId(forKey: "product_view") {
BrandKinesis.sharedInstance(). closeEvent(forID: eventId)
}
}
Gaming Events
objective-c
// Track game session
- (void)startGameSession:(NSString *)gameMode {
NSDictionary *sessionData = @{
@"game_mode": gameMode,
@"session_start_time": @([[NSDate date] timeIntervalSince1970] * 1000),
@"player_level": @([[NSUserDefaults standardUserDefaults] integerForKey:@"player_level"])
};
NSString *eventId = [[BrandKinesis sharedInstance] createEvent:@"game_session" params: sessionData isTimed: YES];
[self storeEventId:eventId forKey:@"game_session"];
}
// End game session with results
- (void)endGameSession:(NSInteger)score duration:(NSTimeInterval)duration {
NSString *eventId = [self getEventIdForKey:@"game_session"];
if (eventId) {
NSDictionary *endData = @{
@"final_score": @(score),
@"session_duration": @(duration),
@"achievements_unlocked": @2,
@"session_end_time": @([[NSDate date] timeIntervalSince1970] * 1000)
};
[[BrandKinesis sharedInstance] setValueAndClose:endData forEvent: eventId];
}
}
swift
// Track game session
func startGameSession(gameMode: String) {
let sessionData: [String: Any] = [
"game_mode": gameMode,
"session_start_time": Date().timeIntervalSince1970 * 1000,
"player_level": UserDefaults.standard.integer(forKey: "player_level")
]
let eventId = BrandKinesis.sharedInstance().createEvent("game_session", params: sessionData, isTimed:true)
self.storeEventId(eventId, forKey: "game_session")
}
// End game session with results
func endGameSession(score: Int, duration: TimeInterval) {
if let eventId = getEventId(forKey: "game_session") {
let endData: [String: Any] = [
"final_score": score,
"session_duration": duration,
"achievements_unlocked": 2,
"session_end_time": Date().timeIntervalSince1970 * 1000
]
BrandKinesis.sharedInstance().setValueAndClose(endData, forEvent: eventId)
}
}
Event Validation
You can validate your custom events in the Upshot.ai dashboard under the Live Events section to ensure they are being tracked correctly.
Best Practices
- Use descriptive event names - Choose clear, consistent naming conventions
- Include relevant properties - Add context that helps with analysis
- Follow naming conventions - Use snake_case for event names and properties
- Validate event data - Check data types and required fields before sending
- Document event taxonomy - Maintain a list of all custom events and their properties
- Use timed events appropriately - Only for events with meaningful duration
- Keep property values simple - Use primitive types when possible
- Handle timed events properly - Always close timed events to avoid memory leaks