Configure Banner Ads in iOS
Learn how to integrate, configure, lay out, test, and manage adaptive banner ads in UIKit and SwiftUI iOS apps while handling privacy and failures.
What banner advertising does
A banner ad is a persistent display advertisement shown within part of an app screen. The advertising SDK sends an ad request to an ad service, receives an ad when inventory is available, and renders it inside a banner view.
Banner advertising can create revenue without requiring the user to leave the current screen. The trade-off is that the banner consumes screen space and can distract from controls or content. Treat the banner as part of the layout rather than placing it on top of the interface after the interface has already been designed.
- Revenue: money earned from advertising activity, usually measured using impressions, clicks, or other provider-specific events.
- Fill rate: the proportion of ad requests that receive an ad response.
- Impression: an advertisement display recorded under the provider's measurement rules.
- Click: a user interaction with the advertisement that may open an advertiser destination.
- Viewability: whether the ad was sufficiently visible and on screen for the provider to count it.
| Banner Type | Sizing Method | Typical Location | When to Use It |
|---|---|---|---|
| Fixed-size | Uses a predefined width and height | Reserved ad slot or legacy layout | When the provider and design require a known size |
| Adaptive | Chooses dimensions from the available width | Most modern screen-edge placements | When the interface must support different devices |
| Anchored adaptive | Adaptive size attached to the top or bottom edge | Below a navigation bar or above a tab bar | For persistent screen-level advertising |
| Inline | Uses a size suitable for a position in scrolling content | Between rows, cards, or paragraphs | When the ad should scroll with the content |
| Placement | Best Use Case | Layout Considerations | Potential UX Risks |
|---|---|---|---|
| Bottom anchored | Persistent content screens | Pin to the bottom safe area and reserve vertical space | Can cover tab bars, keyboard input, or home-indicator space |
| Top anchored | Screens without a prominent top toolbar | Account for the status area, navigation bar, and safe area | Can compete with titles and navigation controls |
| Inline | Long lists and feeds | Give the banner its own content item and loading space | Can interrupt reading or scrolling if inserted too often |
Prerequisites and project preparation
You should know basic Swift, Xcode project structure, UIKit view controllers or SwiftUI composition, Auto Layout and safe areas, the iOS app lifecycle, dependency management, and basic App Store privacy concepts. Review iOS access fundamentals if you need a refresher on iOS development concepts.
- Choose an ad network or mediation platform that supports iOS.
- Create an account and register the app. The platform normally supplies an App ID, which associates the SDK integration with the application.
- Create a banner placement. Its ad unit ID identifies the specific location where banner requests are made.
- Check the provider's supported iOS versions, Swift requirements, and SDK release notes.
- Choose a dependency method. Swift Package Manager is generally the simplest option for a new project; CocoaPods or another provider-supported method may also be available.
Add the SDK with Swift Package Manager
In Xcode, select File > Add Package Dependencies, enter the package repository address supplied by the chosen provider, select a compatible version rule, and add the provider's iOS product to the app target. Do not mix dependency methods for the same SDK unless the provider explicitly supports that arrangement.
Application configuration
Providers commonly require an application identifier in Info.plist. They may also require network configuration, mediation adapter entries, privacy manifest support, or provider-specific settings. Use the exact key and value format from the SDK documentation. A Google Mobile Ads-style configuration, for example, has this representative form:
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY</string>
<key>NSUserTrackingUsageDescription</key>
<string>This identifier helps us provide relevant advertising.</string>The tracking usage description is required before requesting App Tracking Transparency authorization. It must accurately explain the app's intended use. The ad SDK and any mediation adapters must also satisfy current privacy-manifest and App Store disclosure requirements.
Initialize the advertising SDK
Initialize the SDK once, early in the application lifecycle, and provide the application key if the provider requires one. The exact API differs by SDK. The following UIKit example uses a Google Mobile Ads-style API as a concrete pattern; replace names and identifiers when using another provider.
import GoogleMobileAds
@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
MobileAds.shared.start { status in
if let error = status.adapterStatusesByClassName.first(where: {
$0.value.state == .notReady
}) {
print("An ad adapter is not ready: \(error.key)")
}
}
return true
}
}Some SDKs complete initialization asynchronously and return an error or adapter status. Store that state if the app needs to decide whether a placement can load. Do not create repeated initialization calls from every view controller. If initialization fails, keep the main content usable, log a non-sensitive diagnostic, and follow the provider's retry guidance.
Create a bottom-anchored UIKit banner
A view controller should own the banner for the duration of the placement. Set its ad unit ID, root or presenting view controller when required, delegate or callback handler, and test-device settings. The test identifier below is a commonly supplied Google test banner ID; use the official test ID for your selected provider.
import UIKit
import GoogleMobileAds
final class ArticleViewController: UIViewController, BannerViewDelegate {
private let bannerView = BannerView(adSize: AdSizeBanner)
private var bannerBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
bannerView.translatesAutoresizingMaskIntoConstraints = false
bannerView.adUnitID = "ca-app-pub-3940256099942544/243528117011"
bannerView.rootViewController = self
bannerView.delegate = self
view.addSubview(bannerView)
bannerBottomConstraint = bannerView.bottomAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.bottomAnchor
)
NSLayoutConstraint.activate([
bannerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
bannerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
bannerBottomConstraint
])
let request = Request()
bannerView.load(request)
}
func bannerViewDidReceiveAd(_ bannerView: BannerView) {
print("Banner loaded")
// Update content constraints or insets here if the screen reserves space dynamically.
}
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
print("Banner failed: \(error.localizedDescription)")
// Keep the article usable; do not show an empty blocking container.
}
}For a production adaptive banner, calculate the provider's anchored adaptive size from the current safe-area width rather than using AdSizeBanner. The names vary by SDK, but the sequence is consistent: obtain available width, create an anchored adaptive size, assign it, then load the request.
Safe-area and content constraints
Pinning to view.safeAreaLayoutGuide.bottomAnchor avoids the home-indicator region. It does not automatically prevent overlap with a tab bar or custom toolbar. If a tab bar belongs to the same screen, place the banner above that control or incorporate the control's top anchor into the constraint plan.
// Example when the banner must sit above a custom bottom control:
NSLayoutConstraint.activate([
bannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
bannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
bannerView.bottomAnchor.constraint(equalTo: bottomToolbar.topAnchor)
])When the ad loads, either reserve the banner's height from the beginning or animate a height constraint from zero to the loaded height. When loading fails, collapse or hide the reserved area so the app does not show an unexplained blank strip.
Adaptive layout during rotation and resizing
Device rotation, iPad split view, multitasking, and trait changes can change the available width. Recalculate an adaptive banner size during a size transition instead of reusing a fixed portrait dimension.
override func viewWillTransition(
to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator
) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { _ in
let width = self.view.safeAreaLayoutGuide.layoutFrame.width
self.bannerView.adSize = currentAnchoredAdaptiveSize(for: width)
self.bannerView.load(Request())
self.view.layoutIfNeeded()
})
}currentAnchoredAdaptiveSize represents the selected provider's adaptive-size API; its name and return type are SDK-specific. Avoid reloading on every SwiftUI update or every insignificant layout pass. Reload only when the effective width changes and the provider's policy permits it.
Load requests safely
Create one request for the intended load operation and submit it after SDK initialization and the privacy state are ready.
let request = Request()
// Apply only provider-supported options after checking consent and app policy.
// Examples can include content rating, child-directed treatment,
// and other targeting controls.
bannerView.load(request)- Use the provider's test ad unit IDs during development.
- Register simulator or physical test devices through the SDK's approved test-device mechanism when required.
- Set content-rating and child-directed treatment options according to the app and audience; do not guess these values.
- Do not put personal data into request parameters unless the provider, consent state, and legal basis permit it.
- Do not request a new ad on every appearance callback, state update, or failed frame layout.
- Allow the provider's normal refresh behavior unless its policy explicitly documents a configurable refresh interval.
Ad lifecycle and event handling
| Event | Meaning | Recommended App Behavior |
|---|---|---|
| Initialization complete | The SDK and adapters report readiness | Permit requests, or record the failure and keep content available |
| Load success | A banner is available | Show it, update reserved space, and log non-sensitive diagnostics |
| Load failure | No banner was returned | Hide or collapse it and use controlled retry behavior |
| Impression | The provider counted a display | Allow provider measurement; send approved analytics only |
| Click or presentation | The user interacted and an ad destination may open | Do not interfere with the provider's transition |
| Return to app | The ad destination closed or backgrounded the app | Restore app state and avoid duplicate loads |
Delegates or callbacks may be called on a particular queue specified by the SDK. Update UIKit and SwiftUI state on the main thread when necessary. A load failure is normal: network access, inventory, configuration, or policy checks can prevent a response.
Failure handling and cleanup
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
let nsError = error as NSError
print("domain=\(nsError.domain), code=\(nsError.code)")
bannerView.isHidden = true
// Retry later with backoff only if the provider permits it.
}
deinit {
bannerView.delegate = nil
bannerView.rootViewController = nil
}When dismissing a screen, remove observers, clear delegates, and release banner instances that are not reused. If a banner is shared across screens, define one clear owner and do not attach it simultaneously to multiple view hierarchies.
Use a banner from SwiftUI
Many advertising SDKs expose UIKit views. Wrap the banner with UIViewRepresentable, and let the wrapper update only when the available width or relevant configuration changes.
import SwiftUI
import GoogleMobileAds
struct BannerContainer: UIViewRepresentable {
let adUnitID: String
let availableWidth: CGFloat
func makeUIView(context: Context) -> BannerView {
let banner = BannerView(
adSize: currentAnchoredAdaptiveSize(for: availableWidth)
)
banner.adUnitID = adUnitID
banner.rootViewController = topViewController()
banner.delegate = context.coordinator
banner.load(Request())
return banner
}
func updateUIView(_ banner: BannerView, context: Context) {
guard banner.adSize != currentAnchoredAdaptiveSize(for: availableWidth) else {
return
}
banner.adSize = currentAnchoredAdaptiveSize(for: availableWidth)
banner.load(Request())
}
func makeCoordinator() -> Coordinator { Coordinator() }
final class Coordinator: NSObject, BannerViewDelegate { }
}The helper functions in this example stand for your provider's adaptive-size and view-controller lookup APIs. In a real SwiftUI screen, measure the actual available width with a layout tool such as GeometryReader, apply a minimum valid width, and ensure the banner has an explicit vertical placement. Do not trigger a load merely because SwiftUI recomputed the body.
Privacy, consent, and compliance
App Tracking Transparency is Apple's permission framework for tracking users across apps and websites. If the app or an SDK performs tracking as defined by Apple's rules, add the required usage description and request authorization at an appropriate point in the user experience. A permission prompt must not be used as a substitute for a consent notice.
For applicable privacy regulations, show the required consent flow before enabling personalized advertising or transmitting data that requires consent. Determine the user's consent state first, configure the SDK with that state, and then request ads. If consent is denied or unavailable, use the provider's non-personalized or restricted mode where supported.
- Audit the advertising SDK and mediation adapters for privacy-manifest requirements.
- Keep App Store privacy disclosures consistent with actual SDK data collection and sharing.
- Apply age-appropriate ad settings and content ratings.
- Do not collect, log, or target with personal data before the required authorization or consent.
- Re-check consent when the user changes privacy choices.
Privacy-aware request flow
func prepareAdsThenLoad() {
consentManager.determineStatus { status in
trackingManager.requestAuthorizationIfAppropriate {
configureProvider(for: status)
DispatchQueue.main.async {
self.bannerView.load(Request())
}
}
}
}The consent manager and tracking manager above are application components, not universal SDK APIs. The important ordering is to determine applicable consent and authorization, configure the provider, then request the banner.
Testing and release validation
| Setting | Development | Production | Reason |
|---|---|---|---|
| Ad unit ID | Provider test ID | Registered production banner ID | Prevents invalid test traffic and accidental clicks |
| Test devices | Simulator and approved physical devices | Normal users; no test mode | Limits test behavior to development |
| Logging | Detailed SDK and layout diagnostics | Limited, privacy-safe diagnostics | Avoids exposing identifiers or user data |
| Consent data | Controlled test states | Real consent and privacy choices | Validates policy behavior |
| Retry behavior | Short, controlled test intervals | Provider-compliant backoff and refresh | Avoids excessive requests |
- Test on the simulator for layout, but also test on physical devices for network, permission, and SDK behavior.
- Check small and large iPhones, iPad widths, portrait and landscape orientations, safe-area insets, and split-screen resizing.
- Verify that content remains usable when the banner is hidden or fails to load.
- Disable network access and test timeouts, empty inventory, and return-to-app behavior.
- Use only test ads while developing. Never click production ads or generate artificial impressions.
- Before release, replace test IDs and test-device settings with production configuration, then verify the registered App ID, ad unit, consent behavior, and privacy disclosures.
Common integration failures
| Symptom | Likely Cause | How to Diagnose | Resolution |
|---|---|---|---|
| Banner does not appear | Invalid ID, uninitialized SDK, missing view, zero-size constraints, no inventory, or no network | Inspect callbacks, identifiers, initialization logs, view hierarchy, and constraints | Use test IDs, initialize once, add the view visibly, and fix size or network issues |
| Banner overlaps controls | Screen-edge constraint or no reserved content space | Inspect safe-area, tab-bar, toolbar, and keyboard geometry | Use safe-area or control-relative anchors and update content insets |
| Wrong size after rotation | Fixed dimensions or stale adaptive width | Log available width during size transitions | Recalculate size and reload only when the effective width changes |
| Works in development but not release | Test settings, incorrect production IDs, consent differences, or unpropagated registration | Compare release configuration and platform dashboard status | Correct production values and validate privacy and registration status |
| Privacy review is incomplete | Missing tracking description, consent, privacy manifest, or audience settings | Audit SDK documentation, manifests, disclosures, and runtime behavior | Complete the privacy flow and use age-appropriate settings |
| Repeated loads hurt performance | Loads from every update or immediate retry loops | Count banner instances and request calls | Use one owner, controlled retries, and provider-compliant refresh |
Exam-relevant checklist
- Know that an App ID identifies the application while an ad unit ID identifies a particular placement.
- Know that an adaptive banner uses the current available width; a fixed banner does not.
- Anchor banners to safe areas and reserve content space to prevent overlap.
- Initialize the SDK before submitting requests.
- Use test ads and approved test devices during development.
- Handle both success and failure callbacks without making the app depend on ad availability.
- Determine consent and tracking authorization before enabling behavior that requires them.
- Remove delegates and observers when a screen or banner is destroyed.