Skip to content

Unity Usage

This page explains how to use Context Decision to calibrate your custom model, and how to make decisions based on the predictions

  • Step 1: Add ContextSDK to your app
  • Step 2: Ship app into production in Calibration Mode
  • Step 3: Once enough data is collected, you can start making decisions based on the SDK's predictions


  • Use a different, unique flowName for each upsell funnel (e.g. upsell_prompt, upsell_onboarding, etc.)
    • If you have the same purchase flow, but from different parts of your app, please use different a different flowName for each.
    • We automatically analyze the overlap between different flows, to decide if there should be one, or more models.
  • The timing is crucial: You need to create the context object right before showing your prompt, and then log the outcome of the user interaction after the user has either accepted or dismissed the prompt.
  • For each context object you create, be sure to log an outcome, even if the user dismisses the prompt.

In most cases, ContextSDK will execute your block instantly. Only if your game was recently launched, or resumed from the background, it will take up to a few seconds to get a full context.

ContextSDKBinding.Optimize("upsell", delegate (Context context) {
    // Show the upgrade prompt here right after fetching the context
    // Once you know if the user purchased or dismissed the upsell, log the outcome:
    context.Log(Outcome.Positive); // or Outcome.Negative

It's critical you trigger your prompt inside the block, which behaves as follows:

  • The callback is instantly executed if your game has been running for at least 3 seconds
  • The callback being executed within 3 seconds if your game was just put into the foreground recently

This way, ContextSDK guarantees to always have a full context ready, therefore increasing its accuracy in those cases.

There are cases where you may prefer to always instantly have your callback executed. For example, when you want to show a prompt right after a certain user-action, to prevent the prompt showing up when the user already left the screen.

ContextSDKBinding.Optimize("upsell", delegate (Context context) {
    // Setting maxDelay to 0 causes the callback to be called immediately.

    // Show the upgrade prompt here right after fetching the context
    // Once you know if the user purchased or dismissed the upsell, log the outcome:
    context.Log(Outcome.Positive); // or Outcome.Negative
}, null, 0);

You can also use ContextSDK with a simple imperative syntax, if using blocks is undesireable or would make your code harder to write:

Context context = ContextSDKBinding.InstantContext("upsell");
if (context.shouldUpsell)
    // Show your upsell prompt here.
    context.Log(Outcome.Positive); // or Outcome.Negative
} else {
    // Don't do anything - it's a bad moment.
    // Make sure to still log a Skipped outcome so we get the full picture.

The main thing to note here is that you are fully responsible for making sure that the result of Context.shouldUpsell is handled, and to call context.Log(Outcome.Skipped); in the case where Context.shouldUpsell == false.

Also note that ContextSDKBinding.InstantContext will not return a full context object if called shortly after the app was opened. This is not an issue as long as the majority of calls to it happen after the apps has been running for a bit already.


Some games may not have an easy way to pass the context object from where you initially generate it, to where you know the outcome of the user interaction. In those cases, you can use the RecentContext method to get the most recent context object based on the unique flowName. RecentContext can be used with context objects created by the Optimize, and InstantContext methods.

Important: This approach requires you to create the context object first using either Calibrate, Optimize, or InstantContext. Only the most recent context for each flowName name will be stored, and older context objects will be discarded.

The context must already be created at the time the prompt is shown. RecentContext only allows you to log the outcome of the user interaction together with the context object from the moment right before the prompt was shown.

ContextSDKBinding.Optimize("upsell", delegate (Context context) {
    // [Prompt the user for an upgrade right after getting the context]
// Once the user either finished the purchase, or dismissed the upgrade:
Outcome outcome = Outcome.Positive; // or .negative

Context context = ContextSDKBinding.RecentContext("upsell");

if (context != null) {

Custom Signals

ContextSDK uses more than 170 signals based on various built-in sensors to make its predictions. However, you can improve its performance by providing additional data to the ContextSDK that's specific to your app. Some examples of what you could provide: In-game progress, number of friends/messages, number of entries in a list, etc.

If you have custom signals that are relevant for all of your flows, you can declare them globally, and they will be automatically added to every context object you fetch.

ContextSDKBinding.SetGlobalCustomSignal("number_of_levels_completed", 21);

You can easily override the global custom signals by providing the same id when calling the SetGlobalCustomSignal method again using a different value. To remove a global custom signal, simply call the SetGlobalCustomSignal method with a null value.

In general, we recommend using global signals. But if have custom signals that are specific to a certain flow, you can provide them as a parameter when getting your context object:

CustomSignals customSignals = new CustomSignals();
customSignals.AppendCustomSignal("percentage_onboarding_finished", 0.3f);
customSignals.AppendCustomSignal("upsell_copy_button_used", "Purchase Premium");
customSignals.AppendCustomSignal("user_sent_first_message", true);
customSignals.AppendCustomSignal("number_of_friends", 4);

ContextSDKBinding.Optimize("upsell", delegate (Context context)
    // [Prompt the user for an upgrade right after getting the context]
}, customSignals);

Please be sure to consider the user's privacy and don't include any sensitive data. You are responsible for ensuring that you have the necessary rights to provide the data to us. Please at no point include any PII (including but not limited to emails, user IDs, IP addresses, exact locations, etc.) in your custom signals.

Custom Model Rollout

Once you've shipped your app with ContextSDK to the App Store, and you've collected around 1,000 sales events, we can start training your custom machine learning model to optimize your app.

Our recommended approach is to distribute your machine learning models over-the-air directly to your app. This works instantly, uses minimal system resources in the background, and allows us to iterate faster and more efficiently to further improve your app's performance.

In the future, you'll be able to launch your first custom model on our Dashboard, but for the time being, we will reach out to you via email once your first model is ready.

To make decisions you need to either use the .Optimize method, or check the .shouldUpsell property to decide if you should show the prompt or not.

Our OTA rollouts are safe, reliable, and won't affect your app's performance. Our systems continuously monitor the rollout and the resulting conversion performance to ensure everything is working as expected.

If you prefer to disable Over-the-Air updates, we can provide you with a custom SDK binary that includes your custom model. Please drop us a short email at containing your installation method (CocoaPods, SPM, or manual), and we will get you started.

Done with the integration? Header over to the Release Section to go live with your app!