I have several questions that I'm confused with:
Who is best responsible for ad refreshing? After I load the request bannerView.load(GADRequest())
is it best practice to let the developer or Google monitor it?
Should the refresh times be as little as 30 seconds or a minimum of 60 seconds? It seems odd that they recommend 60 seconds but give you the option to choose 30 seconds. I've read on different threads that you can get penalized for all sorts of things and your AdMob account will get closed no questions asked. If that's the case if you pick 30 seconds inside the console and they recommend 60, if they feel anything is "funny" they can terminate your account based on that alone. It's a very oblique process.
It says If your app is automatically refreshing ads, make sure ad requests are not made when the screen is off. If the answer to my first question is to let Google monitor/automatically refresh (without using my code below) how would Google know whether the screen is off or not? For example, the ad is shown in viewControllerA
but the user presses a button and viewControllerB
is pushed on. Since viewControllerA
is still on the stack the ad will constantly get refreshed, I don't see how Google would know the screen is off until viewControllerA
is deallocated. Also, if the user went to the background how would Google know? I'm assuming off means the user can no longer see the screen which means they can't see the ad so there's no need to refresh because they either switched tabs, pushed on another VC, or went to the background (all cases handled in the below code)
Where is the link to the refresh console page? Before you could go to https://apps.admob.com > Monetize and you would end up on the page with the refresh options. When I log in I no longer see a Monetize option but get a sidebar with a bunch of icons. None of the icons bring me to the refresh page. FYI I just started using AdMob yesterday and I only saw the refresh page in videos and online tutorials so I never used it before.
It says here (emphasis mine):
Refreshing ads
We recommend that you have ads persist for 60 seconds or longer, depending on the functionality of your app. Our internal tests have shown that this ensures users have enough time to engage with ads, providing the best performance for both advertisers and publishers. Furthermore, these tests have shown that refreshing ads more often can hurt fill rate for our publishers.
If your app is automatically refreshing ads, make sure ad requests are not made when the screen is off. Also, if users navigate to and from pages with ads in an app over a short period of time, a new ad request should not be made sooner than the recommended 60 second rate.
But it also says here:
Banner ads
We recommend using the Google-optimized automatic refresh rate. The optimized rate is calculated using AdMob historical data to ensure the ads shown in your ad units are being refreshed at the best rate for banner ads.
You may also set a custom refresh rate of 30-120 seconds or disable refresh rate completely.
Here's how I would manage the requests myself every 30 secs taking into account when the user goes to the background, switches tabs, or pushes on another VC. If I don't do all of this and left it up to them ("We recommend using the Google-optimized automatic refresh rate"), how would Google know the screen is off or not?
var timer: Timer?
override viewDidLoad() {
super.viewDidLoad()
// instantiate bannerView ...
NotificationCenter.default.addObserver(self, selector: #selector(startAdRefreshTimer), name: UIApplication.willEnterForegroundNotification, object: nil)
// *** the screen is OFF
NotificationCenter.default.addObserver(self, selector: #selector(stopAdRefreshTimer), name: UIApplication.willResignActiveNotification, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startAdRefreshTimer()
}
// *** the screen is OFF
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopAdRefreshTimer()
}
@objc func startAdRefreshTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 30,
repeats: true,
block: { [weak self](timer) in
self?.refreshAd()
})
}
func refreshAd() {
bannerView.load(GADRequest())
}
@objc func stopAdRefreshTimer() {
if timer != nil {
timer?.invalidate()
timer = nil
}
}
// this really isn't necessary because of what's in viewWillDisappear but I added it anyway
@objc func buttonToPushNextVCTapped() {
let nextVC = NextVC()
navigationController?.pushViewController(viewController: nextVC, animated: true, completion: { [weak self] in
// *** the screen is OFF
self?.stopAdRefreshTimer()
})
}
This isn't the perfect solution because if the user switched tabs back and forth quickly and repeatedly the requests would happen much sooner then 30 seconds which would probably get your account banned. This is just for example purposes.
The refresh rate is the number of seconds until the next ad unit is displayed. The industry average for banner ads is around 30s. Some publishers play around a lot with refresh rates to find the one with the highest conversion rate for their app.
Ad serving When apps are newly registered with AdMob, it typically takes up to an hour and a few ad requests to allow inventory to build. Because of this, you may not see live impressions immediately. Note: In some cases, it may take longer than an hour. Please wait 24 hours before seeking additional help.
When your app requests ads to be displayed. An ad request is counted each time a request is sent, even if no ads are returned and/or when house ads are shown.
Answer to my 1st, 2nd, and 3rd question:
1st this is my setup, I have the bannerView inside a headerView which seems to be totally fine. I'm also using a TabBarController
. Btw the vc the collectionView is in handles the bannerView
and load(GADRequest())
. The headerView only displays the ad so I don't have to worry about it constantly getting called as the user scrolls and the headerView is recycled. You can read the link in my set up for more details.
2nd AdMob's BannerView has a delegate method that gets called when a new ad is received:
MyController: GADBannerViewDelegate {
/// Tells the delegate an ad request loaded an ad.
func adViewDidReceiveAd(_ bannerView: GADBannerView) {
print("adViewDidReceiveAd")
}
}
3rd. I placed a break point on that print statement to see what happens and here are the results.
When I left the headerView visible (didn't scroll it off of the scene) the delegate method fired every 60 secs. I could be off by a few seconds because I looked at the time on my computer and didn't use a timer. Anyway pretty much every 60 secs the break point was hit and the test ad was changed.
As soon as I scrolled the headerView off of the scene and waited the breakpoint never got hit which means that the delegate method was never called. I waited 10 minutes and nothing happened -no ads were served.
As soon as I scrolled the headerView back on scene, I waited a several seconds and the breakpoint was eventually hit which means the delegate was called. Like in the first scenario it got hit every 60 seconds after that.
I switched to a different tab, left for a few minutes and the same exact thing in #2 happened, break point wasn't hit because the delegate wasn't called.
As soon as I came back to the tab with the headerView, the same thing in #3 happened, breakpoint was hit every 60secs because the delegate was called.
I went to the background and like #2 again the break point wasn't hit because the delegate wasn't called.
As soon as I came back from the background like #3 the breakpoint was hit every 60secs because the delegate was called.
My conclusion is that the bannerView DEFINITELY knows when it's not present on the scene. Wether a tab is changed, the app goes to the background (probably uses a notification), and most mysteriously it even knows when it's a subView of another view and that view is scrolled on/off the scene.
I'm in the Bronx, NY, it's 8am (I started testing around 7am) and the ad changed basically every 60 seconds. Maybe in other parts of the world, different times of the day, or different times of the year the duration might be longer or shorter?
Knowing what I know now I think that it's best that I let Google monitor the load(GADRequest())
and change the ads when it's ready. An ad changing every 60s is fine by me. If the scene can hold the user's attention for longer than a minute that's 2 ads served. It's more beneficial because I can spend more time trying to keep their attention than focus on serving them an ad.
As far as the code from my question to handle all the off cases it seems the bannerView is capable of handling all of that on it's own. It's less code for me to maintain and deal with and more importantly it's 1 less reason to worry about getting banned for handling something improperly.
In summary (this works best for me)
let Google handle/monitor the bannerView.load(GADRequest())
to serve news ads
don't customize the refresh, it seems to change every 60 secs on it's own
when using a bannerView (and possibly letting Google monitor the load(GADRequest()))
ads aren't requested when the screen is off so no need to waste time worrying about it
Answer to my 4th question:
The Monetization page to open App Refresh doesn't seem to exist anymore. After you login into AdMob follow these 5 steps (a new screen will appear for steps 3, 4, and 5 after your click your blue ad unit name in step 2).
I think you will find many confusing things in AdMob banners. To determine what was going on with network calls for ads, I had to use Charles proxy to monitor the network stream. I could not find any evidence that the banner, on any view that wasn't on the top of the stack, was continuing to request ads. But, I didn't dig into the framework to find out how/why because I was trying to solve another issue. I would recommend just allowing Admob to serve the ads with their timing using their stock code stubs:
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
I also added some debug code to the delegate function adViewDidReceiveAd(_ bannerView: GADBannerView)
to make sure my app was not serving ads when the view was not on top of the stack. Couldn't find any evidence.
Last, would highly recommend never testing with production ads and to follow their best practices relentlessly on ad placement in your VCs as to not touch or otherwise be directly adjacent to other actionable objects. Very possible you could be put in AdMob jail and not know it for weeks or longer (only that ads will stop serving and you will get the dreaded code 1 "No Ad to Show" debug message).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With