---
id: "ad-monetization/rewards"
title: "Granting Ad Rewards"
description: "Grant a reward to users when they complete an AdMob rewarded or rewarded interstitial ad. RevenueCat verifies each reward server-side using AdMob Server-Side Verification (SSV) before granting it, so rewards can't be spoofed by a tampered client. You configure what each ad unit grants in the RevenueCat dashboard — no backend of your own required."
permalink: "/docs/ad-monetization/rewards"
slug: "rewards"
version: "current"
original_source: "docs/ad-monetization/rewards.mdx"
---

> **AI agents:** This is the Markdown version of a RevenueCat documentation page. For the complete documentation index, see [llms.txt](https://www.revenuecat.com/docs/llms.txt).

Grant a reward to users when they complete an AdMob **rewarded** or **rewarded interstitial** ad. RevenueCat verifies each reward server-side using AdMob [Server-Side Verification (SSV)](https://support.google.com/admob/answer/9603226) before granting it, so rewards can't be spoofed by a tampered client. You configure what each ad unit grants in the RevenueCat dashboard — no backend of your own required.

Today, verified rewards grant [virtual currency](https://www.revenuecat.com/docs/offerings/virtual-currency). Support for additional reward types may be added in the future.

:::warning\[Beta Feature]
This feature is currently in beta.
:::

## How it works

1. A user completes a rewarded ad.
2. AdMob sends an SSV callback to RevenueCat, with the user attached by the SDK.
3. RevenueCat verifies the reward and grants a reward based on your configuration.
4. The SDK reports the verified result to your app.

## Prerequisites

- The [AdMob Adapter SDK](https://www.revenuecat.com/docs/getting-started/adapter-sdks/admob) is installed and the RevenueCat SDK is configured.
- SDK minimums: `purchases-ios` 5.0.0+ (iOS 15+) or `purchases-android` 8.0.0+. The reward verification APIs are experimental and require explicit opt-in.
- Your AdMob account is [connected to RevenueCat](https://www.revenuecat.com/docs/integrations/third-party-integrations/google-admob) so your rewarded ad units sync to the dashboard.

## Step 1: Configure ad units in AdMob

For each rewarded ad unit you want to grant a reward for, enable **Server-side verification** in the AdMob console and set the SSV callback URL to:

```
https://api.revenuecat.com/v1/incoming-webhooks/admob-ssv-rewarded
```

This is a single, shared endpoint — use the same URL for every ad unit. RevenueCat resolves the ad unit and the user from data the SDK attaches at show time. See Google's guide on [setting up SSV](https://support.google.com/admob/answer/9603226) for where to enter the URL.

![The Server-side verification field on an AdMob rewarded ad unit, set to the RevenueCat SSV callback URL](https://www.revenuecat.com/docs_images/ad-monetization/admob-ssv-callback-url.png)

## Step 2: Configure the reward in the RevenueCat dashboard

On the **Rewards** page (under **Ads**) in your RevenueCat dashboard, add a rule for each rewarded ad unit:

1. Select a synced rewarded ad unit.
2. Choose the virtual currency to grant.
3. Enter the amount (a positive whole number).

![The Add reward dialog in the RevenueCat dashboard, with fields for the ad unit, virtual currency, and amount](https://www.revenuecat.com/docs_images/ad-monetization/add-reward-dialog.png)

RevenueCat grants this amount every time a reward from that ad unit is verified.

## Step 3: Implement it in your app

Enable verification on each ad after it loads, then present it with the verification callbacks.

When verification succeeds with a virtual currency reward, the SDK automatically invalidates the local virtual currencies cache before delivering the result. Refetch balances only when your UI needs the updated total — see [reading balances](https://www.revenuecat.com/docs/offerings/virtual-currency#reading-balances).

### Rewarded ads

```swift
// Opt in to the experimental reward verification APIs.
@_spi(Experimental) import RevenueCatAdMob

RewardedAd.loadAndTrack(
    withAdUnitID: "AD_UNIT_ID",
    request: Request(),
    placement: "bonus_coins",
    fullScreenContentDelegate: self
) { ad, error in
    if error != nil { return }
    guard let ad else { return }

    // Enable RevenueCat reward verification before presenting the ad.
    ad.enableRewardVerification()
    self.rewardedAd = ad
}

// Later, present the ad with verification callbacks:
rewardedAd?.present(
    from: self,
    rewardVerificationStarted: {
        // RevenueCat is verifying the reward server-side.
        // Show a loading state here if you gate the reward on the result.
    },
    rewardVerificationCompleted: { result in
        if let virtualCurrency = result.verifiedReward?.virtualCurrency {
            // Verified. RevenueCat already granted the reward server-side; the amount
            // and currency come from the reward rule you configured in the dashboard.
            print("Granted \(virtualCurrency.amount) \(virtualCurrency.code)")

            // The SDK has already invalidated the cache. Refetch balances so your
            // UI reflects the new total.
            Purchases.shared.virtualCurrencies { _, _ in
                // Update your UI with the refreshed balances.
            }
        } else {
            // Verification did not succeed — for example AdMob rejected the reward,
            // the callback timed out, or a network error occurred. Do not grant the
            // reward client-side as a fallback; let the user retry with another ad.
        }
    }
)
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun loadRewardedAd(context: Context) {
    Purchases.sharedInstance.adTracker.loadAndTrackRewardedAd(
        context = context,
        adUnitId = "AD_UNIT_ID",
        adRequest = AdRequest.Builder().build(),
        placement = "bonus_coins",
        loadCallback = object : RewardedAdLoadCallback() {
            override fun onAdLoaded(ad: RewardedAd) {
                // Enable RevenueCat reward verification before presenting the ad.
                ad.enableRewardVerification()
                rewardedAd = ad
            }

            override fun onAdFailedToLoad(error: LoadAdError) {
                rewardedAd = null
            }
        },
    )
}

// Later, show the ad with verification callbacks:
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun showRewardedAd(activity: Activity) {
    rewardedAd?.show(
        activity = activity,
        rewardVerificationStarted = {
            // RevenueCat is verifying the reward server-side.
            // Show a loading state here if you gate the reward on the result.
        },
        rewardVerificationCompleted = { result ->
            rewardedAd = null

            val virtualCurrency = result.verifiedReward as? VerifiedReward.VirtualCurrency
            if (virtualCurrency != null) {
                // Verified. RevenueCat already granted the reward server-side; the amount
                // and currency come from the reward rule you configured in the dashboard.
                println("Granted ${virtualCurrency.amount} ${virtualCurrency.code}")

                // The SDK has already invalidated the cache. Refetch balances so your
                // UI reflects the new total.
                Purchases.sharedInstance.getVirtualCurrenciesWith(
                    onError = { /* Handle error */ },
                    onSuccess = { /* Update your UI with the refreshed balances */ },
                )
            } else {
                // Verification did not succeed — for example AdMob rejected the reward,
                // the callback timed out, or a network error occurred. Do not grant the
                // reward client-side as a fallback; let the user retry with another ad.
            }
        },
    )
}
```

### Rewarded interstitial ads

```swift
// Opt in to the experimental reward verification APIs.
@_spi(Experimental) import RevenueCatAdMob

RewardedInterstitialAd.loadAndTrack(
    withAdUnitID: "AD_UNIT_ID",
    request: Request(),
    placement: "between_levels",
    fullScreenContentDelegate: self
) { ad, error in
    if error != nil { return }
    guard let ad else { return }

    // Enable RevenueCat reward verification before presenting the ad.
    ad.enableRewardVerification()
    self.rewardedInterstitialAd = ad
}

// Later, present the ad with verification callbacks:
rewardedInterstitialAd?.present(
    from: self,
    rewardVerificationStarted: {
        // RevenueCat is verifying the reward server-side.
        // Show a loading state here if you gate the reward on the result.
    },
    rewardVerificationCompleted: { result in
        if let virtualCurrency = result.verifiedReward?.virtualCurrency {
            // Verified. RevenueCat already granted the reward server-side; the amount
            // and currency come from the reward rule you configured in the dashboard.
            print("Granted \(virtualCurrency.amount) \(virtualCurrency.code)")

            // The SDK has already invalidated the cache. Refetch balances so your
            // UI reflects the new total.
            Purchases.shared.virtualCurrencies { _, _ in
                // Update your UI with the refreshed balances.
            }
        } else {
            // Verification did not succeed — for example AdMob rejected the reward,
            // the callback timed out, or a network error occurred. Do not grant the
            // reward client-side as a fallback; let the user retry with another ad.
        }
    }
)
```

```kotlin
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun loadRewardedInterstitialAd(context: Context) {
    Purchases.sharedInstance.adTracker.loadAndTrackRewardedInterstitialAd(
        context = context,
        adUnitId = "AD_UNIT_ID",
        adRequest = AdRequest.Builder().build(),
        placement = "between_levels",
        loadCallback = object : RewardedInterstitialAdLoadCallback() {
            override fun onAdLoaded(ad: RewardedInterstitialAd) {
                // Enable RevenueCat reward verification before presenting the ad.
                ad.enableRewardVerification()
                rewardedInterstitialAd = ad
            }

            override fun onAdFailedToLoad(error: LoadAdError) {
                rewardedInterstitialAd = null
            }
        },
    )
}

// Later, show the ad with verification callbacks:
@OptIn(ExperimentalPreviewRevenueCatPurchasesAPI::class)
fun showRewardedInterstitialAd(activity: Activity) {
    rewardedInterstitialAd?.show(
        activity = activity,
        rewardVerificationStarted = {
            // RevenueCat is verifying the reward server-side.
            // Show a loading state here if you gate the reward on the result.
        },
        rewardVerificationCompleted = { result ->
            rewardedInterstitialAd = null

            val virtualCurrency = result.verifiedReward as? VerifiedReward.VirtualCurrency
            if (virtualCurrency != null) {
                // Verified. RevenueCat already granted the reward server-side; the amount
                // and currency come from the reward rule you configured in the dashboard.
                println("Granted ${virtualCurrency.amount} ${virtualCurrency.code}")

                // The SDK has already invalidated the cache. Refetch balances so your
                // UI reflects the new total.
                Purchases.sharedInstance.getVirtualCurrenciesWith(
                    onError = { /* Handle error */ },
                    onSuccess = { /* Update your UI with the refreshed balances */ },
                )
            } else {
                // Verification did not succeed — for example AdMob rejected the reward,
                // the callback timed out, or a network error occurred. Do not grant the
                // reward client-side as a fallback; let the user retry with another ad.
            }
        },
    )
}
```

## Granted reward events

Rewards earned in debug builds are treated as sandbox events. After a verified grant, confirm it in the [Customer History](https://www.revenuecat.com/docs/dashboard-and-metrics/customer-profile) timeline, where it appears as a virtual currency transaction:

![Customer History timeline showing a granted virtual currency from an ad reward](https://www.revenuecat.com/docs_images/ad-monetization/customer-history-ad-reward.png)

Opening the entry shows a `VIRTUAL_CURRENCY_TRANSACTION` event whose `"source"` is `"ad_reward"`, which distinguishes ad-reward grants from purchases and other sources. The event also includes an `ad_transaction_id` matching the reward verification.
