Ads
one build, four networks.
Choose AdMob, AppLovin MAX, Unity Ads or ironSource LevelPlay in the console, enter the ids, and point the network's reward callback to your Cloud Function. Points for a video are credited only by that callback.
01How a rewarded video is credited
- The app asks for a sessionIt calls
requestAdSession, which checks the daily cap and the cooldown and returns a one-timenonce. - The app shows the videoIt passes the user id and the nonce to the ad SDK (
app/lib/ads/native_adapters.dart). - The ad network calls your functionAfter the user watched, the network's server calls
ssvAdmob,ssvApplovin,ssvUnityorssvIronsource. - The function verifies and credits onceIt checks the network's signature (a bad signature gets 403), removes duplicates, matches the pending session of the same user and credits the points in one transaction. A mismatch opens a fraud flag that you review in the console.
The app never credits itself. If the callback URL is missing or wrong in the network's dashboard, users watch videos and receive nothing. Set up the callback before you release.
02Choose the network
In the console open Ads and pick the Ad network. The default is AdMob. The app reads the choice from config/public, so switching needs no new build. All four SDKs are inside every build.
| Setting (console → Ads) | Default | Meaning |
|---|---|---|
| Ad network | AdMob | The network for rewarded, interstitial and banner ads. |
| Interstitial every n-th screen change | 0 | 0 = no interstitials. |
| Seconds between interstitials (minimum) | 120 | Minimum gap between two interstitials (30 to 3600). |
| Banner on the home screen | off | Shows a banner on the home screen. |
Users who bought remove-ads, and users with an active VIP subscription, see no interstitials and no banners (showsAds in app/lib/data/models.dart). Rewarded videos stay available because the user chooses them.
03Ids and keys per network
Each network has its own section in the console (AdMob units, AppLovin MAX units, Unity Ads units, ironSource LevelPlay units). The Status page warns when the chosen network lacks its required ids or its verification secret.
| Network | Required ids | Also available | Verification secret |
|---|---|---|---|
| AdMob | Android rewarded unit, iOS rewarded unit | Interstitial and banner units per platform | None. Verified with Google's public keys. |
| AppLovin MAX | SDK key, Android and iOS rewarded units | Interstitial and banner units | AppLovin S2S event key: MAX dashboard → Account → General → Keys → Event Key |
| Unity Ads | Android and iOS game ids, Android and iOS rewarded units (placement ids) | Interstitial and banner units | Unity S2S secret: sent to you by Unity Ads support when you register the callback URL |
| ironSource LevelPlay | Android and iOS app keys, Android and iOS rewarded units | Interstitial and banner units | ironSource private key: LevelPlay → Settings → Server-to-server callback → Private Key (you choose it) |
Secrets are write-only in the console, only an owner can change them, and they are stored encrypted with ADMIN_SECRET_KEY. The console writes them to config/private, which only Cloud Functions can read.
04Server-to-server callback URLs
Replace REGION-PROJECT with your region and project id, for example us-central1-my-project. The exact URLs are printed by firebase deploy and shown in Firebase console → Functions. Set the console's Backend → Cloud Functions base URL to https://REGION-PROJECT.cloudfunctions.net as well.
AdMob
Where: AdMob → Apps → Ad units → your rewarded unit → Server-side verification.
https://REGION-PROJECT.cloudfunctions.net/ssvAdmob
AppLovin MAX
Where: MAX → Manage → Ad Units → your rewarded unit → S2S Rewarded Callback URL.
https://REGION-PROJECT.cloudfunctions.net/ssvApplovin?user_id={USER_ID}&custom_data={CUSTOM_DATA}&event_id={EVENT_ID}&event_token={EVENT_TOKEN}&amount={AMOUNT}¤cy={CURRENCY}&ad_unit={AD_UNIT_ID}&ts={TS}
Unity Ads
Where: e-mail Unity Ads support with your Game IDs and this URL. They reply with the secret; enter it as Unity S2S secret.
https://REGION-PROJECT.cloudfunctions.net/ssvUnity
ironSource LevelPlay
Where: LevelPlay → Settings → Server-to-server callback → Callback URL. Enable it for Rewarded, and set the Private Key you also enter in the console.
https://REGION-PROJECT.cloudfunctions.net/ssvIronsource
The app passes the nonce with setDynamicUserId. The parameter name dynamicUserId comes from the ironSource SDK guides; the function also accepts custom_nonce as a fallback. After setup, trigger one real callback from the LevelPlay dashboard and confirm the user receives points.
How each callback is checked
| Network | Check (firebase/functions/src/ssv/) |
|---|---|
| AdMob | ECDSA signature over the query string, Google's verifier keys (cached up to 6 hours). user_id = uid, custom_data = nonce. |
| AppLovin MAX | event_token must equal sha1(event_id + Event Key). |
| Unity Ads | hmac = HMAC-MD5(secret, other parameters sorted). sid = uid:nonce. Answers 1. |
| ironSource LevelPlay | signature = md5(timestamp + eventId + applicationUserId + rewards + private key). Answers <eventId>:OK. |
05Test ids ship by default
The package contains only Google's public AdMob test ids; a test enforces it. With AdMob selected and no unit ids entered, the app falls back to Google's test units (app/lib/ads/ad_adapter.dart), so you see test ads during development. They never earn anything. The other three networks show nothing until their ids are entered.
06Replace the AdMob test app ids
Required before releaseThe Google Mobile Ads plugin needs an AdMob app id inside the app itself. The package ships Google's test app ids:
| File | Key | Shipped test value |
|---|---|---|
app/android/app/src/main/AndroidManifest.xml | com.google.android.gms.ads.APPLICATION_ID | ca-app-pub-3940256099942544~3347511713 |
app/ios/Runner/Info.plist | GADApplicationIdentifier | ca-app-pub-3940256099942544~1458002511 |
Replace both with your own app ids from AdMob → Apps → App settings (one Android app, one iOS app).
app/test/no_cash_out_test.dart checks only the Dart code for AdMob ids, so putting your own app id in AndroidManifest.xml and Info.plist does not break flutter test. Enter your unit ids in the operator console, not in the code.
The Google plugin is in every build and also provides the consent form below, so keep a valid AdMob app id even if you serve ads from another network.
If you use another network on iOS, also add that network's SKAdNetworkItems entries to Info.plist as its integration guide describes. The package lists Google's entry only.
07Consent (UMP)
Before any ad request the app runs Google's User Messaging Platform (gatherConsent() in app/lib/ads/native_adapters.dart): it shows the consent form when required (GDPR, US states) and passes the result to whichever network is active. Users can reopen it in Settings → Ad privacy when their region requires it.
- Create the messagesAdMob → Privacy & messaging. Create the GDPR message (and the US state regulations message if you serve the US) for your apps.
- Add your ad partnersIf you use AppLovin, Unity or ironSource, add them to the ad partners list of the GDPR message.
- iOS tracking text
Info.plistcontainsNSUserTrackingUsageDescription. Adjust the text to your app.
08Check it worked
- Console → Status shows no warning for "Ad unit ids set for the chosen network" and "Rewarded-ad verification secret set"
- Watch one video on a real device: the balance goes up within seconds and the console Ledger shows an
adrow - No new rows in Fraud flags for your own test views