Rewarded Ads Implementation in Mobile Application
Rewarded is only ad format users watch voluntarily. Conversion to view where organically embedded in mechanics (extra life, bonus currency, level unlock) reaches 40–70% of button shows. No wonder eCPM for rewarded is 3–10 times higher than interstitial.
But format has specifics: fixing reward moment. If implemented incorrectly, users get rewards without watching — or don't get after honest viewing. Both destroy trust.
Where Reward Logic Breaks Exactly
Error #1: Award in onAdDismissed.
// WRONG
rewardedAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdDismissedFullScreenContent() {
giveReward() // user could have closed on 3rd second
}
}
onAdDismissedFullScreenContent fires on any close — both after full watch and button tap at start. Award needed only in onUserEarnedReward:
rewardedAd?.show(activity) { rewardItem ->
// This callback = user watched to end
val rewardAmount = rewardItem.amount
val rewardType = rewardItem.type
giveReward(rewardType, rewardAmount)
}
Error #2: Client-side verification.
Awarding right in onUserEarnedReward is normal for simple cases (add life in memory). But if reward affects server state (virtual currency, premium content) — need server verification via SSV (Server-Side Verification).
SSV flow:
- App requests rewarded with
customData— string with userId and nonce - After watch ad network (AdMob/IronSource) makes GET-request to verification endpoint
- Request parameters signed with ECDSA-key of network (public key obtainable from
https://www.gstatic.com/admob/reward/verifier-keys.json) - Your server verifies signature, awards
- Client gets confirmation via WebSocket or polling
// Pass userId in customData on load
val serverSideVerificationOptions = ServerSideVerificationOptions.Builder()
.setCustomData("userId:${currentUser.id};nonce:${UUID.randomUUID()}")
.build()
val adRequest = AdRequest.Builder().build()
RewardedAd.load(context, AD_UNIT_ID, adRequest, object : RewardedAdLoadCallback() {
override fun onAdLoaded(ad: RewardedAd) {
ad.setServerSideVerificationOptions(serverSideVerificationOptions)
rewardedAd = ad
}
})
SSV critical for any app where currency converts to real values or affects PvP balance.
UX-Managed Display
Button "Watch Ad" show only when ad loaded — when rewardedAd != null. Gray inactive button worse than hidden. Load in advance: right after previous show or when opening screen where button can appear.
If load fails — hide button, don't show error to user. Retry with exponential backoff (1 → 2 → 4 → 8 sec) implement silently in background.
Rewarded Interstitial
Less known but useful format — RewardedInterstitialAd. Unlike rewarded, doesn't require explicit user consent before show (no opt-in dialog), but still gives reward for watch. Works well at natural pause points: level start, loading screen. eCPM lower than rewarded, but higher than interstitial.
Timelines
Basic rewarded without SSV — 1–2 days. With server verification and integration to game economy — 2–3 days. Cost based on project analysis and verification requirements.







