Using a Mobile Measurement Partner with Skillz
Mobile Measurement Partners (MMPs) are third-party platforms that allow mobile game developers to track and measure the performance of their advertising campaigns across different advertising channels, such as social media, search, and display networks. MMPs are an essential component of advertising for mobile games. They provide tracking and measurement of advertising campaigns, which helps game developers optimize their campaigns and achieve better results. By tracking user behavior and engagement, MMPs are able to provide valuable insights into how users interact with ads, how they convert, and how they engage with the game after installing it. Skillz utilizes AppsFlyer as its MMP, however, game developers are free to choose other MMP providers such as Adjust, Branch, Kochava, and Singular.
Benefits of using MMP​
Campaign Effectiveness: Advertising for mobile games will inevitably lead to the utilization of a variety of advertising networks such as AppLovin and AdMob in order to drive installs and increase the players engaging with the game. Utilizing an MMP allows a game developer to track campaigns across multiple advertising networks and advertising channels, such as social media, search, and display networks in order to better understand the value of those installs. They provide a comprehensive view of the user's journey from seeing or clicking on the ad to installing the game to additional metrics potentially relevant in modeling predictive Lifetime Value (LTV) (e.g. the number of games played or tutorial completed). This helps mobile developers to understand which channels and networks are most effective in driving installs and user engagement, allowing them to adjust advertising spend to maximize user engagement and achieve better results.
Detecting Fraud: When paying per install, as most mobile advertising is done, detecting fraudulent activity across advertising campaigns is essential. MMPs offer significant protection from fraud utilizing their own advanced algorithms and machine learning technologies for detecting and eliminating different suspicious behavior. As a result, developers are able to protect their advertising budgets and achieve a higher return on investment by allowing them to better allocate spend.
While Skillz is not endorsing nor requiring the use of an MMP, using an MMP in advertising for mobile games can allow developers to better optimize advertising campaigns, provide valuable insights into user behavior, and protect advertising budgets from fraud.Â
Implement MMP with Skillz​
Once an MMP has been selected, it is important to understand how to get the most relevant data, primarily revenue, from Skillz to that MMP. For a Skillz developer, revenue is directly associated with the match entry fees in a given game. This information is available in the MatchInfo Object received client side at the start of every match. Tracking entry fees spent by a user allows game developers to better understand the revenue of that user and overall, the game. Relevant details within the MatchInfo object should be sent to the MMP in order to allow the MMP to provide further insights into a user after install.Â
An MMP will primarily be used to track the attribution on installs; however being able to understand further insights into those users becomes just as important as tracking the install, if not even more so. Gaining insight into the game’s players allows developers to better understand the engagement and revenue potential from those users and better determine which install sources drive the highest quality traffic. Because of this, developers will want to be sure to send revenue to an MMP (example shown below), to help calculate LTV, as well as other potential bottom of the funnel events such as ‘Tutorial Completed’ or ‘Match Played’. Please refer to the preferred MMP provider to learn how best to send this data to the MMP.Â
Skillz’ MatchInfo Object​
- Unity/C#
- iOS/Swift
- iOS/Objective-C
- Android/Java
Match​
Property | Data Type | Description |
---|---|---|
BracketRound | int? | Indicates the round of the bracket tournament if IsBracket is true |
CustomServerConnectionInfo | CustomServerConnectionInfo | The connection info to a custom server that coordinates a real-time match |
Description | string | The description of this tournament type |
EntryCash | float? | If this tournament is being played for real cash, this is the amount of cash required to enter |
EntryPoints | int? | If this tournament is being played for Z, this is the amount of Z required to enter. |
GameParams | Dictionary<string, string> | The custom parameters for this tournament type specified in the developer portal |
ID | ulong? | The unique ID for the match |
IsBracket | bool | Indicates the match is a bracketed tournament |
IsCash | bool? | Indicates the match is for real prizes or for Z |
IsCustomSynchronousMatch | bool | Indicates if the match is a sync match |
IsSynchronous | bool | Deprecated. Indicates if this match is Sync. Note: please use the IsCustomSynchronousMatch property |
IsTieBreaker | bool | Indicates whether the match is a tie-breaker |
IsVideoAdEntry | bool? | Indicates the match entry was through a video ad |
Name | string | Name of the match |
Players | List<Player> | List of players in the match |
SkillzDifficulty | uint? | The difficulty of the game (used with automatic difficulty). Note: only set in production. |
TemplateID | int? | The unique ID for the tournament template this match is based on |
SKZMatchInfo​
Property | Data Type | Description |
---|---|---|
BracketRound | NSNumber | Indicates the round of the bracket tournament if IsBracket is true |
ConnectionInfo | SKZSyncConnectionInfo | The connection info to a Skillz server that coordinates a real-time match. |
Name | NSString | Match name as configured in the Skillz Developer Portal |
EntryCash | NSNumber | Cash entry fee, nil if there is none |
EntryPoints | NSNumber | Z points entry fee, nil if there is none |
ID | NSInteger | The unique ID for the match |
IsBracket | BOOL | Indicates the match is a bracketed tournament |
IsCash | BOOL | Flag indicating cash match |
IsSynchronous | BOOL | Match to be played is a synchronous match, and should use the synchronous game flow |
IsTieBreaker | BOOL | Indicates whether the match is a tie-breaker |
IsVideoAdEntry | BOOL | Indicates the match entry was through a video ad |
MatchDescription | NSString | Match description as configured in the Skillz Developer Portal |
Players | NSArray<SKZPlayer> | Array of SKZPlayers in the match |
TemplateID | NSNumber | The unique ID for the tournament template this match is based on |
SKZMatchInfo​
Property | Data Type | Description |
---|---|---|
BracketRound | NSNumber | Indicates the round of the bracket tournament if IsBracket is true |
ConnectionInfo | SKZSyncConnectionInfo | The connection info to a Skillz server that coordinates a real-time match. |
Name | NSString | Match name as configured in the Skillz Developer Portal |
EntryCash | NSNumber | Cash entry fee, nil if there is none |
EntryPoints | NSNumber | Z points entry fee, nil if there is none |
ID | NSInteger | The unique ID for the match |
IsBracket | BOOL | Indicates the match is a bracketed tournament |
IsCash | BOOL | Flag indicating cash match |
IsSynchronous | BOOL | Match to be played is a synchronous match, and should use the synchronous game flow |
IsTieBreaker | BOOL | Indicates whether the match is a tie-breaker |
IsVideoAdEntry | BOOL | Indicates the match entry was through a video ad |
MatchDescription | NSString | Match description as configured in the Skillz Developer Portal |
Players | NSArray<SKZPlayer> | Array of SKZPlayers in the match |
TemplateID | NSNumber | The unique ID for the tournament template this match is based on |
MatchInfo​
Property | Data Type | Description |
---|---|---|
BracketRound | int | Indicates the round of the bracket tournament if IsBracket is true |
ConnectionInfo | SyncConnectionInfo | The connection info to a Skillz server that coordinates a real-time match. |
ConnectToken | String | |
Name | String | Name of the match |
EntryCash | float | If this tournament is being played for real cash, this is the amount of cash required to enter. |
EntryPoints | int | If this tournament is being played for Z, this is the amount of Z required to enter. |
ID | String | The unique ID for the match |
IsBracket | boolean | Indicates the match is a bracketed tournament |
IsCash | boolean | Indicates the match is for real prizes or for Z |
IsCustomServerSync | boolean | Indicates if the match is a custom server sync match |
IsSkillzServerSync | boolean | Indicates if the match is a Skillz server sync match |
IsSyncBotMatch | boolean | Indicates if the match is a sync bot match |
IsSynchronous | boolean | Indicates if this is a sync match |
IsTieBreaker | boolean | Indicates whether the match is a tie-breaker |
IsVideoAdEntry | boolean | Indicates the match entry was through a video ad |
MatchDescription | String | The description of this tournament type |
Players | List<SkillzPlayer> | List of players in the match |
SkillzDifficulty | String | The difficulty of the game (used with automatic difficulty). Note: only set in production. |
TemplateID | String | The unique ID for the tournament template this match is based on |
From the MatchInfo Object, there are a few values that are most important to keep track of before sending the match revenue information to the preferred MMP.
IsCash - boolean - Indicates whether it is a Pro (true) or Z (false) match
EntryCash - float - For Pro tournaments, EntryCash will contain the entry fee required to join the match
IsBracket - boolean - Indicates the match is a bracketed tournament
BracketRound - int - Indicates the round of the bracket tournament if IsBracket is true
IsTieBreaker - bool - Indicates if the match is a tiebreaker
Sending EntryCash​
EntryCash is equivalent to the entry fees used to calculate the developer revenue share. This value is important to send to an MMP, however a few checks should be performed before sending to ensure there is no over or under reporting.
Check ‘IsCash’ == true. This will ensure that only values associated with Pro matches are calculated.
Next is a two part check designed to check for head-to-head/events or bracketed tournament cases. The overall check should be: if a or b.
- Check ‘IsBracket’ == false AND that ‘IsTieBreaker’ == false – handles head to head and event matches
- Check ‘IsBracket’ == true AND ‘BracketRound’ == 1 – handles bracketed tournaments
If the match clears those two checks, then ‘EntryCash’ can be sent to the preferred MMP.
public void OnMatchWillBegin(Match matchInfo){
    //check for a cash game
    if (matchInfo.IsCash && !matchInfo.IsTieBreaker){
if (!matchInfo.IsBracket || (matchInfo.IsBracket && matchInfo.BracketRound == 1)){
        //Send EntryCash to MMP with the tournament name as the Revenue Event Name
      }
    }
}
When sending the EntryCash value to the preferred MMP there are two options for determining revenue:Â
Multiply ‘EntryCash’ by the developer revenue share and send that calculated value to the MMP orÂ
Account for it later on the MMP or Ad Network end.
One other optional method to consider for SKAdNetwork tracking on iOS would be calculating the sum of all entry fees within the first 24-48 hours and sending that value to SKAdNetwork.Â
Tracking revenue allows for a picture of lifetime value (LTV) to emerge. The goal is to grow LTV to surpass the cost per install (CPI). When this occurs, the user or cohort is profitable for the game, presenting an opportunity for expansion.
Singular​
As we utilize Singular, we will describe the types of Singular SDK calls that may be useful with a Skillz integration.There are two primary mechanisms for sending events that should be utilized: Event and CustomRevenue (Singular Documentation).Â
Event Method​
The Event calls are focused on sending other information that generally does not have revenue information. This is the opportunity to send events such as ‘Tutorial Started’, or ‘Match Completed’. There is a lot of flexibility with these events, so developers should feel free to send any that make sense in the context of any predictive modeling that may be done.
Custom Revenue Method​
CustomRevenue events are a subset of revenue events that are able to be sent to Singular. This particular function provides added flexibility to allow game developers to include additional revenue details beyond just the entry fee. Additional details that may be worth tracking are the different tournaments (track by ‘Name’), tiebreakers (IsTieBreaker), and synchronous gameplay (IsSynchronous).
public void OnMatchWillBegin(Match matchInfo){
//check for a cash game
    if (matchInfo.IsCash && !matchInfo.IsTieBreaker){
      if (!matchInfo.IsBracket || (matchInfo.IsBracket && matchInfo.BracketRound == 1)){
        //Send EntryCash to MMP with the tournament name as the Revenue Event Name
//NOTE::This is for Singular only - just an example
SingularSDK.CustomRevenue(matchInfo.Name, "USD", matchInfo.EntryCash);
      }
    }
}
Once the revenue or event data is within the chosen MMP, in this case Singular, it should be accessible to utilize in reporting and other modeling such as SKAdNetwork.
Because this data is sent real time, there may occasionally be discrepancies related to match refunds, however, it should still be an accurate predictor of revenue.
SKAdNetwork (Applicable for iOS games)​
SKAdNetwork is Apple's attribution framework for mobile apps. It provides advertisers with a means to measure campaign effectiveness without violating user privacy. A model needs to be defined through an MMP to allow for proper tracking. The values in the SKAdNetwork model are sent directly to Apple from the iOS client and then sent back to ad networks from Apple directly rather than through the iOS client. Through this model, advertisers get some install data, but users' identities are kept anonymous, striking a balance between privacy and advertising efficiency. For more detailed information on SKAdNewtork, the MMPs have extensive documentation around the different versions and current status of SKAdNetwork.