Interstitial Ads
Interstitial ads are full-screen ads that cover the interface. Display them at natural pause points in your app, such as between game levels or after completing a task.
Each ad format uses a Zone ID to identify the ad placement. Zone IDs are configured in the Empower dashboard.
Note: All ad status listeners are optional. The SDK handles ad loading and display automatically. Use listeners only if you need to track ad states for analytics, UI updates, or custom logic.
Quick Start
- Swift
- Objective-C
import EmpowerMobileAds
class HomeViewController: UIViewController, AdStatusDelegate {
private let interstitialZoneId = "YOUR_INTERSTITIAL_ZONE_ID"
override func viewDidLoad() {
super.viewDidLoad()
loadInterstitial()
}
func loadInterstitial() {
EMAManager.shared.loadInterstitialAd(zoneId: interstitialZoneId, delegate: self)
}
func showInterstitialIfReady() {
if EMAManager.shared.isInterstitialReady(zoneId: interstitialZoneId) {
EMAManager.shared.showInterstitial(zoneId: interstitialZoneId, from: self)
} else {
print("Interstitial not ready")
}
}
func empowerInterstitialStatusChanged(adStatus: AdStatus) {
switch adStatus {
case .ready:
print("Interstitial ready to show")
case .failed(let error):
print("Interstitial failed to load: \(error?.localizedDescription ?? "unknown")")
case .skipped:
loadInterstitial() // Preload next
default:
break
}
}
}
@import EmpowerMobileAds;
@interface HomeViewController () <EMAAdObserver>
@end
@implementation HomeViewController
static NSString *const interstitialZoneId = @"YOUR_INTERSTITIAL_ZONE_ID";
- (void)viewDidLoad {
[super viewDidLoad];
[self loadInterstitial];
}
- (void)loadInterstitial {
[[EMAManager shared] loadInterstitialAdWithZoneId:interstitialZoneId observer:self];
}
- (void)showInterstitialIfReady {
if ([[EMAManager shared] isInterstitialReadyForZoneId:interstitialZoneId]) {
[[EMAManager shared] showInterstitialWithZoneId:interstitialZoneId fromViewController:self];
} else {
NSLog(@"Interstitial not ready");
}
}
- (void)interstitialStatusChanged:(EMAAdStatusType)status {
switch (status) {
case EMAAdStatusTypeReady:
NSLog(@"Interstitial ready to show");
break;
case EMAAdStatusTypeFailed:
NSLog(@"Interstitial failed to load");
break;
case EMAAdStatusTypeSkipped:
[self loadInterstitial]; // Preload next
break;
default:
break;
}
}
@end
Loading Interstitials
Basic Loading
- Swift
- Objective-C
EMAManager.shared.loadInterstitialAd(zoneId: "YOUR_ZONE_ID", delegate: self)
[[EMAManager shared] loadInterstitialAdWithZoneId:@"YOUR_ZONE_ID" observer:self];
Showing Interstitials
Check Readiness First
Always verify the ad is ready before showing:
- Swift
- Objective-C
func showInterstitial() {
let zoneId = "YOUR_ZONE_ID"
if EMAManager.shared.isInterstitialReady(zoneId: zoneId) {
EMAManager.shared.showInterstitial(zoneId: zoneId, from: self)
} else {
print("Interstitial not ready yet")
// Optionally show without ad or wait
}
}
- (void)showInterstitial {
NSString *zoneId = @"YOUR_ZONE_ID";
if ([[EMAManager shared] isInterstitialReadyForZoneId:zoneId]) {
[[EMAManager shared] showInterstitialWithZoneId:zoneId fromViewController:self];
} else {
NSLog(@"Interstitial not ready yet");
// Optionally show without ad or wait
}
}
Automatic Presentation
You can use showInterstitialAutomatic to automatically present from the topmost view controller. If the ad isn't ready yet, the request is queued and the ad will be shown when it becomes available:
- Swift
- Objective-C
EMAManager.shared.showInterstitialAutomatic(zoneId: "YOUR_ZONE_ID")
[[EMAManager shared] showInterstitialAutomaticForZoneId:@"YOUR_ZONE_ID"];
Status Handling
Status Flow
loadInterstitialAd() → .initializing → .ready → showInterstitial(zoneId:from:) → .shown → .skipped
↓
.failed (retry)
Status Callback
- Swift
- Objective-C
Adopt AdStatusDelegate and implement empowerInterstitialStatusChanged(adStatus:):
extension HomeViewController: AdStatusDelegate {
func empowerInterstitialStatusChanged(adStatus: AdStatus) {
switch adStatus {
case .initializing:
print("Interstitial is loading...")
case .ready:
print("Interstitial ready to show")
case .shown:
print("Interstitial is currently displaying")
case .skipped:
print("Interstitial was dismissed")
loadInterstitial() // Preload next
case .failed(let error):
print("Interstitial failed: \(error?.localizedDescription ?? "unknown")")
case .willLeave:
print("User tapped the ad (leaving the app)")
default:
break
}
}
}
Adopt EMAAdObserver and implement interstitialStatusChanged::
// MyViewController.m — conform to <EMAAdObserver>
- (void)interstitialStatusChanged:(EMAAdStatusType)status {
switch (status) {
case EMAAdStatusTypeInitializing:
NSLog(@"Interstitial is loading...");
break;
case EMAAdStatusTypeReady:
NSLog(@"Interstitial ready to show");
break;
case EMAAdStatusTypeShown:
NSLog(@"Interstitial is currently displaying");
break;
case EMAAdStatusTypeSkipped:
NSLog(@"Interstitial was dismissed");
[self loadInterstitial]; // Preload next
break;
case EMAAdStatusTypeFailed:
NSLog(@"Interstitial failed");
break;
case EMAAdStatusTypeWillLeave:
NSLog(@"User tapped the ad (leaving the app)");
break;
default:
break;
}
}
Status Values
Swift (AdStatus) | Objective-C (EMAAdStatusType) | Description |
|---|---|---|
.initializing | EMAAdStatusTypeInitializing | Ad is loading |
.ready | EMAAdStatusTypeReady | Ad is ready to show |
.shown | EMAAdStatusTypeShown | Ad is currently displaying |
.failed(Error?) | EMAAdStatusTypeFailed | Ad failed to load |
.skipped | EMAAdStatusTypeSkipped | Ad was dismissed / closed |
.willLeave | EMAAdStatusTypeWillLeave | User tapped the ad (leaving app) |
SwiftUI Integration
import SwiftUI
import EmpowerMobileAds
// MARK: - Interstitial Coordinator
class InterstitialCoordinator: NSObject, ObservableObject, AdStatusDelegate {
@Published var isReady = false
@Published var isShowing = false
private let zoneId: String
init(zoneId: String) {
self.zoneId = zoneId
super.init()
load()
}
func load() {
EMAManager.shared.loadInterstitialAd(zoneId: zoneId, delegate: self)
}
func show() {
guard isReady else { return }
// Get root view controller for SwiftUI
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootVC = windowScene.windows.first?.rootViewController else { return }
EMAManager.shared.showInterstitial(zoneId: zoneId, from: rootVC)
}
func empowerInterstitialStatusChanged(adStatus: AdStatus) {
DispatchQueue.main.async {
switch adStatus {
case .ready:
self.isReady = true
self.isShowing = false
case .shown:
self.isShowing = true
case .skipped:
self.isReady = false
self.isShowing = false
self.load() // Reload
case .failed:
self.isReady = false
self.isShowing = false
self.load() // Retry
default:
break
}
}
}
}
// MARK: - Usage in SwiftUI View
struct HomeView: View {
@StateObject private var interstitial = InterstitialCoordinator(zoneId: "YOUR_ZONE_ID")
@State private var level = 1
var body: some View {
VStack {
Text("Level \(level)")
.font(.largeTitle)
Button("Complete Level") {
completeLevel()
}
.buttonStyle(.borderedProminent)
}
}
private func completeLevel() {
level += 1
// Show interstitial every 3 levels
if level % 3 == 0 && interstitial.isReady {
interstitial.show()
}
}
}
Best Practices
- Preload ahead of time — call
loadInterstitialAdwell before the moment you want to show (app start, level start) so a ready ad is waiting. Interstitials belong at natural breaks, not mid-task. - Always check readiness — show only when
isInterstitialReady(zoneId:)istrue, or useshowInterstitialAutomatic(zoneId:), which queues the request and presents the ad as soon as it is ready. - Don't stack full-screen ads — before showing, make sure another full-screen ad isn't already
up: guard with
isAnyFullScreenAdShowing()(e.g. don't show an interstitial while an app-open or rewarded ad is on screen). - Reload after dismissal, not while showing — the SDK ignores a
loadInterstitialAdcall made while an ad is on screen. Trigger the next load from the.skippedstatus. Interstitial auto-reload is off by default, so reload yourself unless the zone enables it server-side. - Respect the user — don't show on every screen or interrupt critical flows such as checkout or onboarding.
Troubleshooting
Interstitial Not Showing
- Ensure you're passing a valid view controller (
selfmust be aUIViewController). - Check ads are not disabled.
- Enable debug logging.
- Swift
- Objective-C
EMAManager.shared.showInterstitial(zoneId: "YOUR_ZONE_ID", from: self)
print("Ads disabled: \(EMASettings.shared.isAdsDisabled)")
EMASettings.shared.logLevel = .all
[[EMAManager shared] showInterstitialWithZoneId:@"YOUR_ZONE_ID" fromViewController:self];
NSLog(@"Ads disabled: %d", EMASettings.shared.isAdsDisabled);
EMASettings.shared.logLevel = LogLevelAll;
API Reference
EMAManager.loadInterstitialAd
func loadInterstitialAd(
zoneId: String,
delegate: AdStatusDelegate? = nil
)
| Parameter | Type | Description |
|---|---|---|
zoneId | String | Your interstitial zone ID |
delegate | AdStatusDelegate? | Callback delegate |
EMAManager.showInterstitial
func showInterstitial(
zoneId: String,
from viewController: UIViewController
)
| Parameter | Type | Description |
|---|---|---|
zoneId | String | The zone identifier for the interstitial to show |
viewController | UIViewController | The view controller to present from |
EMAManager.showInterstitialAutomatic
@discardableResult
func showInterstitialAutomatic(zoneId: String) -> Bool
Shows the interstitial from the topmost view controller automatically. If the ad is not ready yet, the request is queued and executed when the ad becomes available. Returns true if the ad was shown immediately, false otherwise.
EMAManager.isInterstitialReady
func isInterstitialReady(zoneId: String) -> Bool
Returns true if the interstitial ad for the specified zone is ready to show.
EMAManager.isInterstitialShowing
func isInterstitialShowing(zoneId: String) -> Bool
Returns true while the interstitial is on screen (between show and dismiss). Use it to avoid
stacking another full-screen ad over it.
Objective-C selectors
| Swift | Objective-C selector |
|---|---|
loadInterstitialAd(zoneId:delegate:) | loadInterstitialAdWithZoneId:observer: |
showInterstitial(zoneId:from:) | showInterstitialWithZoneId:fromViewController: |
showInterstitialAutomatic(zoneId:) | showInterstitialAutomaticForZoneId: |
isInterstitialReady(zoneId:) | isInterstitialReadyForZoneId: |
isInterstitialShowing(zoneId:) | isInterstitialShowingForZoneId: |
In Objective-C, adopt
EMAAdObserverand pass your object as theobserver:argument (instead ofdelegate:). Status is delivered asEMAAdStatusTypeviainterstitialStatusChanged:.