Pricing Solution
The wappier Optimization SDK can provide you the in-app products with optimized prices. Promotional Pricing is based on specific end-user attributes and mainly optimizes promo offers, while the Global Pricing using Control Group is based on the end-user country.
Promotional Pricing
Our platform allows you to support promotional pricing, by offering a given in-app product with an ML-based optimized price. Those pricing offers use tagging to be distinguished. You can get the available offer tags on the wappier system by registering the following callback:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().setOfferTagListener(new OfferTagListener() {
@Override
public void onTags(List<String> response) {
...
}
});
[WappierSDK setOfferTagNotificationListener:^(NSArray<NSString *> *tags) {
...
}];
Wappier.Instance.SetOfferTags((tags) =>
{
...
});
WappierSDKWrapper::getInstance()->setOfferTagListener([](std::vector<const char*> tags){
....
});
Whenever this callback is called, you can have a list of tags. These tags point to available pricing offers for the end user.
You can get the pricing offer with the optimized in-app products for a specific tag with the following method:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().getOffers(tags, new StringListener() {
@Override
public void onSuccess(String response) {
...
}
});
[WappierSDK getOffers:@[@"tag1", @"tag2"] callback:^(NSDictionary *response) {
...
}];
string[] offerTags = {"tag1", "tag2"};
Wappier.Instance.GetOffers(offerTags, (offerItems) =>
{
...
});
std::vector<const char*> offerTags{"tag1", "tag2"};
WappierSDKWrapper::getInstance()->getOffers(offerTags, [](const char* response){
....
});
The listener above will be filled with a JSON payload in string format value. In that case, you need to iterate that value in order to display the appropriate SKU to the end user.
For end users in the Pricing Target group, you will receive the following value in string data type. The optimized wappier SKU will be found in the array of the items object. Then, this SKU must be displayed to the end user.
An example response below:
{
"type": "pricing",
"items": {
"tag": ["com.wappier.sku1.wap_abc"]
}
}
For end users in the Pricing Control group, you will receive a similar response as above but the array will be empty. In that case, you must display your original SKU to the end user.
An example response below:
{
"type": "pricing",
"items": {
"tag": []
}
}
You can iterate the listener’s value following a similar logic as we suggest in the following snippet:
HashMap < String, ArrayList < String >> mapping = new HashMap < > ();
try {
JSONObject payload = new JSONObject(response);
if (payload.has("items")) {
JSONObject items = payload.getJSONObject("items");
Iterator keys = items.keys();
while (keys.hasNext()) {
String key = (String) keys.next();
JSONArray array = items.getJSONArray(key);
if (array.length() == 0)
return;
ArrayList<String> skus = new ArrayList <> ();
for (int i = 0; i < array.length(); i++) {
skus.add(array.getString(i));
}
mapping.put(key, skus);
}
}
} catch (JSONException e) {
e.printStackTrace();
} finally {
if (mapping.isEmpty())
return;
ArrayList < String > dynamicSkus = mapping.get(tag);
if (dynamicSkus == null || dynamicSkus.isEmpty())
return;
showDialog("Personalized Pricing", dynamicSkus.get(0));
}
Global Pricing
You can enable dynamic pricing service via the Wappier dashboard by assigning prices to your in-app products. The new prices will be visible to a predefined percentage of the population while the rest of it will belong to a control group that will be used to compare performance.
Users belonging to the control group will notice no differences in price points.
You normally send an SKU ID to Apple/Google In-App Billing API. By using our pricing optimization service, the SKU is no longer a predefined constant but can rather change whenever the application launches. For this reason, you have to fetch the assigned SKU based on the original SKU by using the below method (after the SDK has been initialized):
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().getSkus(List<String> originalSkuList);
NSDictionary<NSString *,NSString *> *skuMap = [WappierSDK getSKUs:skus];
Wappier.Instance.GetSkus(originalSkus);
WappierSDKWrapper::getInstance()->getSkus(originalSkus);
For example, if you have an SKU named ‘com.company.magic_sword’, you should retrieve the name of the dynamically allocated equivalent of that SKU:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Map<String, String> regionalSkuMap;
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<String> skuList = new ArrayList<>();
skuList.add("com.company.magic_sword");
regionalSkuMap = Wappier.getInstance().getSkus(skuList);
//Now you can use the regional sku in Google billing API related methods
}
}
NSArray *skus = @[
@"com.company.magic_sword",
@"com.company.magic_shield"
];
NSDictionary<NSString *,NSString *> *skuMap = [WappierSDK getSKUs:skus];
string[] originalSkus = new string[]{"com.company.magic_sword"};
Dictionary<string, string> skus = Wappier.Instance.GetSkus(originalSkus);
std::vector<const char*> originalSkus{"com.company.magic_sword"};
std::map <const char*, const char*> dynamicSkusMap = WappierSDKWrapper::getInstance()->getSkus(originalSkus);
The method returns a map with an entry for each SKU queried, containing the original SKU as its key and the dynamic SKU as its value. In case of failure (network issue or expired pricing test), the method returns in this SKU entry’s value the original SKU.
To fetch all the original SKUs that correspond to a proxy SKU, you may use the following function:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
Wappier.getInstance().getOriginalSkus(proxySkusList);
NSArray *proxySkusList = @[
@"com.company.magic_sword_wp_1234",
@"com.company.magic_shield_wp_1234"
];
NSDictionary<NSString *,id> *skuMap = [WappierSDK getOriginalSKUs:proxySkusList];
Wappier.Instance.GetOriginalSKUs(proxySkusList);
WappierSDKWrapper::getInstance()->getOriginalSkus(dynamicSkus);
which takes as an argument a list of all the proxy SKUs to be queried.
This function returns a map with a key for each proxy SKU queried and a list of String objects as the value for each key.
- If one or more original SKUs were found for a given proxy SKU, then the value in the map for this proxy SKU entry will be a list containing String objects for each original SKU.
- If no original SKUs were found for a given proxy SKU, then the value in the map for this proxy SKU entry will be a list containing a String object similar to the queried proxy SKU.
Getting User Status
You can get the end-user status for each Wappier service. In the response, you can find if the end-user is included in the control or target group, for the Wappier service that you are asking for.
To get User Status, add the following code:
- Android(Java)
- iOS(obj-C)
- Unity(C#)
- C++
// tags is a List<String> and can take values "all" | "loyalty" | "pricing" | "campaign"
List<String> tags = new ArrayList<>();
tags.add("loyalty");
tags.add("pricing");
tags.add("campaign");
Wappier.getInstance().getUserStatus(tags, new StringListener() {
@Override
public void onSuccess(String response) {
...
}
});
// tags is an Array<NSString> and can take values "all" | "loyalty" | "pricing" | "campaign"
NSArray *tags = @[
@"loyalty",
@"pricing",
@"campaging"
];
[WappierSDK getUserStatus:tags callback:^(NSDictionary * response) {
...
}];
// tags is a string[] and can take values "all" | "loyalty" | "pricing" | "campaign"
string[] tags = new string[] {"loyalty","pricing","campaign"}
Wappier.Instance.GetUserStatus(tags, UserStatusCallback);
void UserStatusCallback(string response)
{
//Handle response json
}
OR
Wappier.Instance.GetUserStatus(tags, response => {
//Handle response json
});
// tags is a std::vector<const char*> and can take values "all" | "loyalty" | "pricing" | "campaign"
std::vector<const char*> tags = {"loyalty","pricing","campaign"};
WappierSDKWrapper::getInstance()->getUserStatus(tags, [](const char* response) {
...
});
which takes a list of tags as an argument and returns a JSON response as a String.
Argument | Service |
---|---|
loyalty | You will get the status of the user for the Loyalty and Retention service |
pricing | You will get the status of the user for the Pricing service |
campaign | You will get the status of the user for the Personalized Interstitials service |
all | You will get the status of the user for all wappier services |
Example Response:
"{
\"loyalty\" : {
\"population\" : 0.67220987,
\"control\" : false,
\"enabled\" : false
},
\"campaign\" : {
\"population\" : 0.36149076,
\"control\" : false,
\"enabled\" : false
},
\"pricing\" : {
\"population\" : 0.34617529,
\"control\" : false,
\"enabled\" : true,
\"billingCountry\": \"GR\",
\"isInScope\": true
}
}"
In the response, you may find if the user is included in the control or target group per each service.
- If the end-user is included in the control group for the requested service if the
{{service}}.control:true
and{{service}}.enabled:false
- If the end-user is included in the target group for the requested service if the
{{service}}.control:false
and{{service}}.enabled:true