> For the complete documentation index, see [llms.txt](https://docs.contextsdk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.contextsdk.com/context-decision/revenue-outcomes.md).

# Revenue Outcomes

Learn when and how to log revenue outcomes in ContextSDK to optimize monetization and improve model accuracy.

{% hint style="info" %}
On Android, log revenue with a `RevenueEvent`, as shown below. Logging a purchase straight from the store's product objects, as `logRevenueOutcome(from: product)` does with StoreKit on iOS, is iOS only: there is no Google Play Billing equivalent.
{% endhint %}

## What is a revenue outcome?

A revenue outcome represents the result of a monetization event in your app, such as an in-app purchase or an ad impression.

## Why is it important?

Understanding how and when users contribute to revenue allows ContextSDK to make informed predictions about the best moments to display monetization opportunities. Logging revenue outcomes helps ContextSDK optimize your ML models, ensuring that monetization decisions align with real-world user behavior, so we can optimize your app for revenue generation.

## When should I log revenue outcomes?

Log a revenue outcome whenever the user generates revenue. This includes in-app purchases, ad clicks, ad impressions, tips, or other sources of revenue.

Use revenue outcomes only for events that directly lead to revenue. For non-revenue actions that are positive, like permission prompts or rating requests, use standalone positive outcomes instead of revenue outcomes.

**When NOT to log revenue outcomes:**

* If the user dismisses the offer or doesn't convert, log a standalone negative outcome, not a revenue outcome
* If a purchase transaction fails due to technical issues (network problems, payment method issues, etc.), don't log anything - these failures don't reflect user intent or context quality

## How to log revenue outcomes

Here's a few examples of how to log revenue outcomes for different scenarios.

### In-app purchases

#### StoreKit 2 (iOS 15+)

If you're using **StoreKit 2**, log a purchase like this:

```swift
// `product` is the StoreKit 2 product that was purchased.
context.logRevenueOutcome(from: product)
```

#### StoreKit 1 (iOS 8+)

If your app uses **StoreKit 1** or needs to support iOS 14 and earlier, see [StoreKit1 Docs](/context-decision/revenue-outcomes/logging-revenue-with-storekit-1.md).

#### Third-party frameworks

If you're using **Superwall**, see [Using ContextSDK with Superwall](/context-decision/revenue-outcomes/superwall.md)

If you're using **Purchasely**, see [Using ContextSDK with Purchasely](/context-decision/revenue-outcomes/purchasely.md)

If you're using **RevenueCat**, see [Logging Revenue with RevenueCat](/context-decision/revenue-outcomes/revenuecat.md)

If you're using a different in-app purchase framework, retrieve the equivalent StoreKit product object and pass it to `logRevenueOutcome(from:)` for StoreKit 2 or `logStoreKit1RevenueOutcome(from:)` for StoreKit 1.

#### Android

On Android, log a purchase made through Google Play as a `RevenueEvent` with the `PURCHASE_APP_STORE` source, or `SUBSCRIPTION_APP_STORE` for a subscription, passing the price your billing library reports:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
// `priceAmountMicros` and `priceCurrencyCode` come from the purchased product's offer details.
val revenue = BigDecimal.valueOf(priceAmountMicros, 6)
context.logRevenueOutcome(
    RevenueEvent(RevenueSource.PURCHASE_APP_STORE, revenue, Currency.valueOf(priceCurrencyCode))
)
```

{% endtab %}

{% tab title="Java" %}

```java
// `priceAmountMicros` and `priceCurrencyCode` come from the purchased product's offer details.
BigDecimal revenue = BigDecimal.valueOf(priceAmountMicros, 6);
context.logRevenueOutcome(
    new RevenueEvent(RevenueSource.PURCHASE_APP_STORE, revenue, Currency.valueOf(priceCurrencyCode))
);
```

{% endtab %}
{% endtabs %}

`Currency.valueOf` throws for a code that isn't one of the `Currency` cases, so catch `IllegalArgumentException` if your store can report other currencies.

{% hint style="success" %}
There's no need to call `context.log(.positive)` after logging a revenue outcome from a `Product`, as the positive outcome is already logged internally. Alternatively, you can customize the outcome to be logged directly, via `logRevenueOutcome(from:outcome:)`.

For a list of all available outcomes see [Alternative Outcomes](/context-decision/advanced/alternative-outcomes.md).
{% endhint %}

### Ad clicks and impressions

For an **ad click**, log the revenue outcome as follows:

{% tabs %}
{% tab title="iOS" %}

```swift
let event = RevenueEvent(source: .adClick, revenue: 0.09, currency: .usd)
context.logRevenueOutcome(from: event, outcome: .positiveAdTapped)
```

{% endtab %}

{% tab title="Android" %}
{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val event = RevenueEvent(RevenueSource.AD_CLICK, BigDecimal("0.09"), Currency.USD)
context.logRevenueOutcome(event, EventOutcome.POSITIVE_AD_TAPPED)
```

{% endtab %}

{% tab title="Java" %}

```java
RevenueEvent event = new RevenueEvent(RevenueSource.AD_CLICK, new BigDecimal("0.09"), Currency.USD);
context.logRevenueOutcome(event, EventOutcome.POSITIVE_AD_TAPPED);
```

{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

Or for an **ad impression**:

{% tabs %}
{% tab title="iOS" %}

```swift
let event = RevenueEvent(source: .adImpression, revenue: 0.00175, currency: .usd)
context.logRevenueOutcome(from: event, outcome: .negativeNotInteracted)
```

{% endtab %}

{% tab title="Android" %}
{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val event = RevenueEvent(RevenueSource.AD_IMPRESSION, BigDecimal("0.00175"), Currency.USD)
context.logRevenueOutcome(event, EventOutcome.NEGATIVE_NOT_INTERACTED)
```

{% endtab %}

{% tab title="Java" %}

```java
RevenueEvent event = new RevenueEvent(RevenueSource.AD_IMPRESSION, new BigDecimal("0.00175"), Currency.USD);
context.logRevenueOutcome(event, EventOutcome.NEGATIVE_NOT_INTERACTED);
```

{% endtab %}
{% endtabs %}
{% endtab %}
{% endtabs %}

On Android, the outcome defaults to `EventOutcome.POSITIVE` when you leave it out: `context.logRevenueOutcome(event)`. Build the amount from a string, such as `BigDecimal("0.09")`, or from your ad network's value with `BigDecimal.valueOf(revenue)`: `BigDecimal(0.09)` holds the binary approximation of the `Double` instead.

Logging a revenue event attaches the amount, currency and source to the context's outcome, replacing any revenue already set on that context, and then logs the outcome. A later outcome logged on the same context carries them too.

The revenue values in these examples are placeholders. Use the actual revenue values from your ad network's SDK, preferring the most precise values available. If exact values aren't provided, an estimate is acceptable, however, greater precision improves accuracy.

Some ad networks may provide callbacks that contain live revenue data. Use this data to log revenue outcomes in real-time, ensuring that the revenue data is as accurate as possible.

## Best practices

* **Avoid duplicate logging:** Use `logRevenueOutcomeIfNotLoggedYet(from:)` (iOS) or `logRevenueOutcomeIfNotLoggedYet(event)` (Android) for events where duplicate logging may occur. If the context already logged an outcome, it does nothing.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.contextsdk.com/context-decision/revenue-outcomes.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
