Drawlogue docs
v2.0.0
Live demoConsole demo Get help
● Monetise · AdMob, Unity Ads, ironSource LevelPlay

Ads.
Your ids, your networks, off by default.

The app can show banner, interstitial, native, app-open and rewarded ads from AdMob, Unity Ads or ironSource LevelPlay, from one network or a waterfall per format. Each network is your own publisher account. No ad id of the author ships: only Google's public AdMob test ids, which you replace.

Test ids onlytool/check_ad_ids.shGoogle consent form (UMP)AdMob SSV optionalUnity / LevelPlay rewards capped

01Your own ids are required

You must supply every monetisation id yourself. The item earns nothing and shows no ad until you do, and none of these values is in the download as a default or a fallback:

What you supplyWhere you get itWhere you put it
Your AdMob app id for Android and for iOSAdMob → Apps → App settingsAndroidManifest.xml and Info.plist (step 1); they replace Google's two published test app ids, the only AdMob values in the native files
Your AdMob ad unit ids (banner, interstitial, native, app-open, rewarded, per platform)AdMob → Apps → Ad unitsConsole → AdMob ids
Your Unity Ads game ids and placementsUnity Cloud → MonetizationConsole → Unity Ads ids
Your ironSource LevelPlay app keys and unitsLevelPlay dashboardConsole → ironSource LevelPlay ids
Your Google Play and App Store product ids for every plan period, credit pack and Remove adsPlay Console and App Store Connect, where you create the products and set the pricesConsole → Plans and Store & purchases (In-app purchases)

What the download contains instead: empty unit, game-id, app-key and credential fields in the app model, the backend defaults and the console (28 fields, each with a test that fails if it stops being empty); placeholder product names such as pro_monthly that belong to no store account; Google's two published test app ids in the native files, which the Google SDK needs to start and which you replace; and a Firebase placeholder (app/lib/firebase_options.dart with empty apiKey and appId and the emulator project id demo-drawlogue; no google-services.json or GoogleService-Info.plist is included). No ad unit id, not even a test unit, is compiled into the app: an empty field shows no ad in debug and release builds alike (how an id travels).

02What ships in the code

An ad id tells a network whose app is showing the ad and who gets paid. The source contains no real ad id, so you put in your own.

IdWhere it livesWhat ships
AdMob app id, Androidandroid/app/src/main/AndroidManifest.xml, com.google.android.gms.ads.APPLICATION_IDGoogle's test app id ca-app-pub-3940256099942544~3347511713
AdMob app id, iOSios/Runner/Info.plist, GADApplicationIdentifierGoogle's test app id ca-app-pub-3940256099942544~1458002511
AdMob ad unit idsConsole → AdMob idsEmpty. No fallback in any build: an empty unit shows no ad of that format. For development, paste Google's test units (links below) into the console.
Unity Ads game ids and unitsConsole → Unity Ads idsEmpty; no game id in the native files. The Unity SDK's test mode is on in debug builds only.
ironSource LevelPlay app keys and unitsConsole → ironSource LevelPlay idsEmpty

Google publishes test unit ids for development: Android test ads, iOS test ads. They are not in the code; paste them into the console while you develop and replace them with your own units before release. The web demo shows simulated, labelled "DEMO AD" placeholders and contacts no network.

03Where ad credentials are handled

No ad credential of the author is compiled into the app, the backend or the console, as a default or as a fallback. Every id you enter travels one way only:

  1. You enter itin the console (AdMob ids, Unity Ads ids, ironSource LevelPlay ids). The console stores it and writes it to the Firestore document config/public, field ads.admob, ads.unity or ads.ironsource (schema).
  2. The app reads itfrom GET /v1/config when it starts (app/lib/data/models/ads_config.dart) and hands it to the network SDK (app/lib/ads/native_adapters.dart).
  3. An empty fieldmeans no ad of that format, in debug and release builds alike. The app holds no fallback unit id, not even Google's test units; while you develop, paste Google's published test units into the console yourself and replace them before release. Unity Ads and LevelPlay are used only when their game id / app key and the rewarded unit are set.
CredentialDefault in the shipped code
AdMob app id (native files)Google's public test app id, ca-app-pub-3940256099942544~…, which earns nothing
AdMob unit ids (12 fields)Empty string
Unity Ads game ids and units (8 fields)Empty string; no Unity id in AndroidManifest.xml or Info.plist
ironSource LevelPlay app keys and units (8 fields)Empty string; no LevelPlay key in the native files
AdMob reporting credentialsEmpty; optional, stored encrypted in config/private

The 28 empty defaults are in three files, and each has a test that fails if one of them stops being an empty string:

Where the default livesWhat it isTest
admin/src/manifest.ts, networkSectionThe 28 console fields (default: "")admin/test/manifest.test.ts
firebase/functions/src/api/defaults.ts, DEFAULT_PUBLIC.adsWhat the backend answers before the console has saved anythingfirebase/functions/test/unit/defaults.test.ts
app/lib/data/models/ads_config.dart, AdUnitsWhat the app assumes when a field is missingapp/test/ad_defaults_test.dart

Check it yourself: tool/check_ad_ids.sh (below) searches the app for any AdMob id that is not Google's test id and for Unity or LevelPlay keys in the native configuration. A search of the whole download for ca-app-pub- finds only Google's test publisher 3940256099942544.

04Check that no foreign id ships

From app/:

tool/check_ad_ids.sh            # fails if any non-test ad id is hard-coded
tool/check_ad_ids.sh --release  # also fails while the AdMob app id is still Google's test id

Terminal: macOS or Linux as shown; on Windows use WSL or Git Bash (how).

On the shipped source the first command prints PASS no real ad ids are hard-coded with a note that the AdMob app id is Google's test id. Run the --release form before every store build: it must pass once you put your own app id in.

05The ad SDKs: whose terms apply, and what you do

In plain words: this item contains no ad network SDK. The source only names three plugins. When you build the app, your own computer downloads them, and the networks' SDKs, from their publishers. Each network then deals with you, not with the author: you open the account, you accept its terms, and it pays you.

NetworkPlugin named in app/pubspec.yamlLicence of the pluginThe network's own SDKTerms you accept with your own account
AdMobgoogle_mobile_ads 9.0.0, published by GoogleApache-2.0Google Mobile Ads SDK, downloaded by Gradle and CocoaPodsGoogle's terms and programme policies for AdMob publishers, shown when you create the AdMob account
Unity Adsunity_ads_plugin, a community plugin by Pavel Zaichyk, not published by UnityMITUnity Ads SDK (Maven com.unity3d.ads:unity-ads, pod UnityAds)Unity Terms of Service and the Unity Advertising Additional Terms
ironSource LevelPlayunity_levelplay_mediation 9.3.0, published by Unity TechnologiesProprietary, not open source: the LICENSE file of version 9.3.0 places it under the Unity Advertising Terms of Service as a "Service Asset" (current licence on pub.dev)LevelPlay SDK (Maven com.unity3d.ads-mediation:mediation-sdk, pod IronSourceSDK) and the adapters of the networks you mediateThe same Unity terms

Redistribution: why no SDK is in the download

We read Unity's pages linked above on 11 November 2026; they can change, so read the current text yourself. This is a summary to help you find the right pages, not legal advice.

  • The Unity Advertising Additional Terms (last updated 30 June 2026) cover the Unity Ad Network and the LevelPlay mediation platform. They give the account holder a limited, revocable, non-transferable and non-sublicensable licence to use Unity's SDKs (the "Service Assets") in the account holder's own applications. We found no clause that lets anyone pass the SDK on to others.
  • For that reason the item does not redistribute them. There is no SDK file, .aar, framework or pod in the download; the only .jar is the standard Gradle wrapper. The plugins and SDKs arrive from pub.dev, Maven and CocoaPods when you run flutter pub get and build.
  • The licence you buy on CodeCanyon covers the item's own code. It does not include, replace or extend an ad network's SDK licence or publisher agreement, and the author is not a party to your agreements with Google or Unity.

What you do, step by step

  1. Choose your networksAll three are optional and ads ship switched off. Use one, two, three or none.
  2. Open your own account with each network you useClick paths: AdMob, Unity Ads, LevelPlay.
  3. Read and accept that network's termsAccept them as the person or company that publishes the app in the stores. The network pays the account holder under those terms.
  4. Finish the network's own requirementsApp review or approval, payment and tax details, app-ads.txt where the network asks for it, and its privacy settings (Consent, Network approval).
  5. Enter your ids in the consoleStep 1 and Step 2 below. Until then every id is empty.
  6. Declare the SDKs in the storesGoogle Play's Data safety form and the App Store privacy details must list what the ad SDKs in your build collect. Each network documents this for its SDK.
  7. If someone else will operate the appFor example a client: they need their own network accounts and must accept the terms themselves. An ad account and its agreement cannot be handed over with the source code.

Leave a network's SDK out of your app

A network whose console fields are empty is never started, but its SDK is still built into the app. If you do not want to accept Unity's terms at all, remove both Unity plugins before you build. This needs a code editor; the app compiles and its tests pass without them.

  1. Remove the pluginsIn app/pubspec.yaml delete the lines unity_ads_plugin and unity_levelplay_mediation.
  2. Remove their codeIn app/lib/ads/native_adapters.dart delete the two import lines of these packages and everything from the comment line Unity Ads to the end of the file (the classes UnityAdapter, LevelPlayAdapter and the LevelPlay banner).
  3. Return no adapter for themIn the same file, in createNativeAdapter, change the two lines to AdNetwork.unity => null, and AdNetwork.ironsource => null,.
  4. iOSIn app/ios/Podfile the pre_install block for unity_levelplay_mediation no longer matches anything; you may delete it.
  5. RebuildRun flutter pub get, then flutter analyze; it must report no issues.
  6. ConsoleKeep the network AdMob and do not write unity or ironsource in a waterfall; such a line would simply find no ad.

06Step 1 · Put your AdMob app id in the app

  1. Get itAdMob → Apps → your app → App settings → App ID (ca-app-pub-…~…). One for Android, one for iOS (click path).
  2. AndroidReplace the value of com.google.android.gms.ads.APPLICATION_ID in AndroidManifest.xml.
  3. iOSReplace the string after GADApplicationIdentifier in Info.plist.
  4. Console tooEnter the same two app ids in Console → AdMob ids, so the Status check "Ad ids set for what is switched on" can confirm them.

The app id must be in the native files because Google's SDK reads it when the app starts, before any setting arrives. If you never show AdMob ads, you may keep the test id; --release then fails as a reminder.

07Step 2 · Enter the unit ids and choose the networks

  1. Ad unit idsConsole → the page of your network: banner, interstitial, rewarded, native and app-open units for Android and iOS (Unity Ads and LevelPlay have banner, interstitial and rewarded only). Where to find them: AdMob, Unity Ads, LevelPlay.
  2. Unity and LevelPlay need a rewarded unitThe app uses Unity Ads or LevelPlay only when the game id / app key and the rewarded unit are set for the platform.
  3. One network or a waterfallConsole → Ads → How ads are filled: "One network" uses the network you select for every format; "Waterfall per format" tries the listed networks in order (one per line, first tried first). Exact rules and an example: Waterfall.

The three id pages of the console. Every field starts empty; fill only the networks and formats you use.

Console page AdMob ids with empty fields for the Android and iOS app ids and the banner and interstitial units
Console → AdMob ids: Android and iOS app id, then banner, interstitial, rewarded, native and app-open units per platform
Console page Unity Ads ids with empty fields for the Android and iOS game ids and the banner and interstitial units
Console → Unity Ads ids: game id per platform, then banner, interstitial and rewarded units
Console page ironSource LevelPlay ids with empty fields for the Android and iOS app keys and the banner and interstitial units
Console → ironSource LevelPlay ids: app key per platform, then banner, interstitial and rewarded units

08Waterfall: the exact network names

You never edit Firestore by hand

A waterfall is set up entirely in the console. You type the lists on Console → Ads and click Save changes; the console writes them to Firestore for you. Nothing on this page asks you to open the Firebase console or to edit JSON. The JSON further down is shown only so that a developer can see what the console writes.

Set up a waterfall in the console

  1. Enter the ids firstFill the id pages of every network you want in the list (Step 2). A network without ids is passed over.
  2. Open the Ads pageConsole → Ads.
  3. Choose the modeHow ads are filled → Waterfall per format.
  4. Type the listsIn each field Waterfall: banner, interstitial, rewarded, native and app open, write one network name per line, the one to try first at the top. The accepted names are in the table below.
  5. SaveClick Save changes in the bar at the bottom.
  6. CheckConsole → Status → App config written to Firestore must be green. If a line was skipped, this check names it.
  7. Restart the appClose the app fully and open it again; it reads the new lists when it starts.

The accepted names

In waterfall mode each format has its own list on Console → Ads, one network per line, tried from the top. The console accepts exactly these names (upper or lower case):

WriteNetworkFormats it can serve in the app
admobGoogle AdMobbanner, interstitial, rewarded, native, appOpen
unityUnity Adsbanner, interstitial, rewarded
ironsourceironSource LevelPlaybanner, interstitial, rewarded

A valid setup that prefers AdMob and falls back to the other two:

Console fieldLines
Waterfall: banneradmob
unity
ironsource
Waterfall: interstitialadmob
ironsource
Waterfall: rewardedadmob
Waterfall: nativeadmob
Waterfall: app openadmob

What the console writes (for developers, read-only)

After you save, the console writes the lists to the Firestore document config/public as shown here. You do not type or edit this:

"ads": {
  "enabled": true,
  "mode": "waterfall",
  "network": "admob",
  "waterfall": {
    "banner": ["admob", "unity", "ironsource"],
    "interstitial": ["admob", "ironsource"],
    "rewarded": ["admob"],
    "native": ["admob"],
    "appOpen": ["admob"]
  }
}
Do not edit config/public in the Firebase console

The console is the only writer of this document. On every save, and every time the console starts, it replaces the whole document from its own stored settings (admin/src/sync.ts, syncConfig), so a value typed into Firestore by hand is lost at the next save and is never checked for typos. The app cannot write the document either: the Firestore rules deny it (firebase/firestore.rules). To change a waterfall, change it on Console → Ads.

What happens with a typo

Nothing fails silently and nothing throws. A line that is not valid is skipped, the rest of the list is kept, and Console → Status, check App config written to Firestore, turns red with the reason, for example:

LineStatus message
admobbWaterfall banner line 1 "admobb" skipped: unknown network (admob, unity, ironsource).
unity in the native listWaterfall native line 1 "unity" skipped: unity has no native format in the app.
admob twiceWaterfall banner line 2 "admob" skipped: listed twice.

If every line of a format is skipped, the app uses the network selected in Network (one-network mode) for that format. In the app a network that has no ad (no fill) or reports an error is passed over, and the next one in the list is tried; when none fills, nothing is shown.

Console Ads page with the Show ads master switch, How ads are filled, the one-network selection and the banner waterfall list with admob
Console → Ads: master switch Show ads, How ads are filled, the one-network choice and the waterfall lists (read-only demo console)

09Step 3 · Switch on placements

PlacementConsole fieldDefault
App-open adApp-open adoff
Banner on the home screenBanner on the home screenoff
Banner in the galleryBanner in the image galleryoff
Native ad in the assistant listNative ad after every n assistants0 = off
InterstitialInterstitial after every n messages; Seconds between two interstitials (minimum 30, default 120)0 = off; never shown while an answer streams
RewardedRewarded ad unlocks extra messages / Rewarded ad unlocks an imageoff

Then turn on the master switch Show ads and save. Users on a plan with "No ads" and Remove ads users never see ads.

11Rewarded ads and server-side verification

Do you need server-side verification? In plain words

Short answer: no, not to start. Rewarded ads work without it, it ships switched off, and most operators can leave it off.

A rewarded ad gives the user one extra message or one image after they watch it. Normally the app tells your backend "this user watched the ad", and the backend believes it. Server-side verification (SSV) adds a second opinion: the backend waits until AdMob itself confirms that the ad was watched. It protects against one thing only: a person who modifies the app to claim the reward without watching the ad.

Your situationDo you need SSV?What to do
You do not use rewarded ads (both rewarded placements are off, as shipped)NoNothing. Skip the rest of this section.
You use rewarded ads and keep the daily limit small (it ships as 3 per user per day)NoLeave SSV off. The daily limit already caps what a cheater can get.
Your rewarded ads come from Unity Ads or ironSource LevelPlayNot availableSSV in this app works with AdMob only. Keep the daily limit small.
You raise the daily limit a lot, or you suspect cheating (for example, your AdMob report shows far fewer rewarded ads than the rewarded unlocks you see under Console → Users → a user → today's usage)YesServe rewarded ads with AdMob only and switch SSV on (steps below).
  • What you risk without SSV: a cheater gets at most the daily rewarded limit (Console → Limits → Free: extra messages unlocked by a rewarded ad per day, shipped as 3) in extra messages or images per account per day, and you pay your AI provider for those requests. Nothing else is exposed, and the limit applies whether SSV is on or off.
  • What SSV asks of you: one setting on each rewarded ad unit in AdMob, one switch in the console, and a backend that AdMob can reach over HTTPS. After the ad the user waits a few seconds until AdMob's confirmation arrives. Rewarded ads from Unity Ads or LevelPlay stop unlocking anything while SSV is on.
  • You can decide later. The console switch can be turned on or off at any time and takes effect the next time the app starts; no app update is needed.

How a reward is confirmed (technical detail)

How the reward is confirmed depends on the network:

NetworkHow the reward is confirmed
AdMob, SSV off (default)The app reports the completed ad; the backend issues a single-use reward token (valid 10 minutes).
AdMob, SSV on (optional)The backend issues the token only after AdMob's signed callback for that ad has arrived.
Unity Ads, ironSource LevelPlayTrusted from the app. Drawlogue has no server-side verification for these networks; the app reports the completed ad and the backend issues the token.
Unverified rewards are capped

Every rewarded unlock, verified or not, counts against Free: extra messages unlocked by a rewarded ad per day (Console → Limits, default 3 per user). With Unity Ads or LevelPlay a modified app could claim rewards without watching ads, up to that daily cap. Keep the cap low, or serve rewarded ads with AdMob and switch SSV on.

Switch on AdMob SSV

  1. AdMobAdMob → your rewarded ad unit → Server-side verification → callback URL <API_BASE_URL>/v1/rewarded/ssv → Verify URL → Save (click path).
  2. ConsoleAds → Rewarded ads: server-side verification (AdMob SSV) on, Save.
  3. Only AdMob for rewardedWith SSV on, every rewarded unlock waits for AdMob's callback. Use it only when AdMob serves all rewarded ads (one network AdMob, or AdMob alone in the rewarded waterfall); a Unity or LevelPlay rewarded ad would then never be confirmed.
  4. How it worksThe app sets the ad's SSV user_id to the user's id and custom_data to a random nonce. The backend checks the callback's signature with Google's published keys. Until the callback has arrived, the app's request answers 404 not_found ("The reward is not confirmed yet. Try again in a few seconds.") and retries.

12Common ad problems

Ads do not show although the setup looks right

Go through these in order; the first one that fails is usually the cause.

  1. Status pageConsole → Status, check Ad ids set for what is switched on. It names every id a release build still needs, for example "Release builds show no ad without these ids — AdMob: androidBanner, iosBanner", and says "Ads are on but every placement is off" when no placement is switched on.
  2. Master switch and placementConsole → Ads: Show ads on, and the placement itself on (banner on home, interstitial every n messages, and so on). Save.
  3. The app has the new settingsThe app reads the configuration when it starts, and the API caches it for 60 seconds. Close the app fully and open it again.
  4. The user may see no adsUsers on a plan with "No ads" and users who bought Remove ads never see ads. Test with a free account.
  5. Interstitial timingAn interstitial needs the set number of messages and the minimum seconds since the last one (default 120), and never appears while an answer is streaming.
  6. Release build with an empty unitA release build has no test fallback: an empty unit id means no ad of that format.
  7. Unity Ads or LevelPlayThey are used only when the game id / app key and the rewarded unit are set for that platform.
  8. The network has no ad yetNew ad units and accounts often show no fill for hours, and AdMob serves limited ads until your app and account are reviewed and app-ads.txt is verified. Consent matters too: in the EEA and UK a user who has not answered the consent form gets no personalised ads.
  9. Device logRun the debug build with flutter run and read the device log (Android Studio Logcat or the Xcode console). The network SDKs print their own load errors there, for example AdMob's "Ad failed to load" with an error code (3 = no fill). An exception inside an adapter is logged under drawlogue as ad admob:, ad unity: or ad ironsource:.

Test ids shipped in a release build

  • AdMob app id: the native files ship Google's test app id. A store build with it shows no paid ads. Run tool/check_ad_ids.sh --release from app/ before every store build; it fails while the test app id is still there.
  • Unit ids: the app has no built-in unit id, so a build of any kind shows test ads only if someone typed a Google test unit into the console. Before release check the three id pages: no value may start with ca-app-pub-3940256099942544.
  • Unity Ads: test mode is on only in debug builds. Make sure test mode is not forced for your game id in the Unity dashboard's testing settings.
  • Never test with your own live ads in a release build; add your phone as a test device in each network instead.

SSV callbacks never arrive

With Rewarded ads: server-side verification on, the app shows the rewarded ad, then asks the backend for the reward up to 8 times, 2 seconds apart. If AdMob's callback has not arrived by then, the user gets no reward.

  1. Callback URLAdMob → the rewarded ad unit → Server-side verification: exactly <API_BASE_URL>/v1/rewarded/ssv, over HTTPS, reachable from the internet (not localhost, not an emulator). Press Verify URL: the backend answers 200 to AdMob's test.
  2. Console switchConsole → Ads → Rewarded ads: server-side verification (AdMob SSV) on and saved. Without it the callback answers 404 "Server-side verification is not enabled."
  3. Right ad unitThe SSV URL is set per ad unit. The unit in Console → AdMob ids → rewarded must be the one that has the callback.
  4. Only AdMobUnity Ads and LevelPlay never send AdMob callbacks. With SSV on, the rewarded waterfall must be admob only.
  5. LogsFirebase console → Functions → Logs for /v1/rewarded/ssv: no request at all = AdMob cannot reach the URL; 400 Invalid signature or AdMob SSV keys unavailable = the function cannot load Google's verifier keys (check outbound network).
  6. DelayAdMob usually calls within seconds, but it can be slower on new ad units. Test on a real device with a test device id, not in the web demo (SSV is off in demo mode).

More answers: Troubleshooting → rewarded ads.

13Ad revenue in the console

Ad revenue is "not measured" unless you connect AdMob reporting (Console → Ad revenue reporting: AdMob publisher id and AdMob API OAuth credentials) and pull finished days on the Revenue centre page, or record payouts by hand with a reference (the way to record Unity Ads and LevelPlay income). Nothing is estimated.

14Network approval

Each network reviews your app and account before serving real ads, and pays under its own terms and thresholds. While you wait, keep testing with test ads; never click your own live ads.