⚠️ My AdMob Experience: Ban + Ad Plugin Tests

Hi everyone,
I’d like to share my experience after launching Ball Sort Challenge, made with Solar2D.

obs: Any advice on which ad network to use? is also welcome!

After 2 months of development, I published the game on the Play Store. In the first week, AdMob limited ad serving, claiming invalid traffic and self-clicks on my ads.

I investigated and saw 7,000 requests from India in the AdMob reports — but my game didn’t even have that many downloads. Then I remembered an app called 12 Testers Community, developed by someone from India. I’m not blaming the app, but I deleted my game from its list just in case.

To prevent issues, I decided never to install my own game on my device again. When I need to test it, I use testMode = true and AdMob’s test ad IDs.

After 15 days, the ad limit was removed.
I no longer installed the game on my smartphone, I made updates that with the emulator I was already sure would work, so I built a new version and uploaded it, even without having the game installed on the device for more than a week. But a week and a few days later, my account was fully suspended, again with the same reason: invalid traffic and self-clicks.

:arrows_counterclockwise: Testing Alternative Ad Networks
I tried several plugins. Only AdMob and Appodeal worked properly.

Appodeal worked, but significantly increased the app size. Also, it only generates real revenue with high ad volume.

With AdMob, even with low traffic, I got an eCPM of $1.70, which isn’t bad.

Other plugins like StartApp and AppLovin Max had 0% fill rate, even after disabling test mode. StartApp worked in test mode but failed in production. AppLovin didn’t show ads at all, even in test mode.

I haven’t tested Facebook Audience Network — if anyone uses it, please confirm if it still works and is worth using (it hasn’t been updated in Solar2D for 8 years).

:mag: Technical Review of My AdMob Code
I fully reviewed my code to check for anything suspicious. Here are the key points:

Banner Ads

if admob.isLoaded("banner") then
    admob.show("banner", { y = "bottom" })

→ Only shown if loaded. No forced interaction or automation.

Interstitial Ads

if admob.isLoaded("interstitial") then
    admob.show("interstitial")

→ Shown after completing levels. Normal behavior.

Rewarded Videos

if admob.isLoaded("rewardedVideo") then
    rewardHint = "reward_video"
    admob.show("rewardedVideo")

→ User chooses to watch. Rewards are only granted if the video is completed (event.phase == “reward”).

User Consent

system.setPreferences(“app”, {
userConsent = booConsent
})
→ Stores the user’s ad consent choice. GDPR-compliant behavior.

In short: there’s no automation or fraud in the code. Still, my account got banned.
If anyone went through something similar or has any tips, I’d really appreciate hearing from you.
Thanks and good luck to all devs out there!

Hello,
did you share with someone else your admob id needs for the admob init function? (ca-app-pub-78 etc…)

Sincerely.
Have a good day.
Yvan.

1 Like

No! I didn’t share

Not sure if it’s related, but this has been a requirement by AdMob since last year.

1 Like

To prevent excessive ad requests, I reviewed my code and implemented a simple solution to ensure each ad type is loaded only when necessary.
:white_check_mark: 1. Used a flag to control loading requests
I created a table called adRequested to track whether a loading attempt has already been made:
– Loading control

local adRequested = {
    banner = false,
    interstitial = false,
    rewardedVideo = false
}

:white_check_mark: 2. Set the flag to true when requesting a load
During initialization:

if event.phase == "init" then
    appodeal.load("banner")
    appodeal.load("interstitial")
    appodeal.load("rewardedVideo")

    adRequested.banner = true
    adRequested.interstitial = true
    adRequested.rewardedVideo = true
end

:white_check_mark: 3. Cleared the flag when loading completes or fails

elseif event.phase == "loaded" or
       event.phase == "failed" or
       event.phase == "closed" then
    adRequested[event.type] = false
end

:white_check_mark: 4. Reloaded the ad only if it’s neither loaded nor in the process of loading

local function tryLoadRewarded()
    if not appodeal.isLoaded("rewardedVideo") and not adRequested.rewardedVideo then
        adRequested.rewardedVideo = true
        appodeal.load("rewardedVideo")
    end
end

:pushpin: Result
:white_check_mark: Prevents multiple calls for the same ad type.
:white_check_mark: Improves control over request frequency.

This logic can be easily adapted for banners, interstitials, and other ad formats.
I hope this helps other developers!
If there’s any error in the logic, please point it out so I can fix it.
obs: As you can see I am using appodeal now - but the problem occurred with admob.

1 Like

But after all, did it solve the problem?