Skip to main content

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

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
}
}
}

Loading Interstitials

Basic Loading

EMAManager.shared.loadInterstitialAd(zoneId: "YOUR_ZONE_ID", delegate: self)

Showing Interstitials

Check Readiness First

Always verify the ad is ready before showing:

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
}
}

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:

EMAManager.shared.showInterstitialAutomatic(zoneId: "YOUR_ZONE_ID")

Status Handling

Status Flow

loadInterstitialAd() → .initializing → .ready → showInterstitial(zoneId:from:) → .shown → .skipped

.failed (retry)

Status Callback

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
}
}
}

Status Values

Swift (AdStatus)Objective-C (EMAAdStatusType)Description
.initializingEMAAdStatusTypeInitializingAd is loading
.readyEMAAdStatusTypeReadyAd is ready to show
.shownEMAAdStatusTypeShownAd is currently displaying
.failed(Error?)EMAAdStatusTypeFailedAd failed to load
.skippedEMAAdStatusTypeSkippedAd was dismissed / closed
.willLeaveEMAAdStatusTypeWillLeaveUser 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

  1. Preload ahead of time — call loadInterstitialAd well 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.
  2. Always check readiness — show only when isInterstitialReady(zoneId:) is true, or use showInterstitialAutomatic(zoneId:), which queues the request and presents the ad as soon as it is ready.
  3. 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).
  4. Reload after dismissal, not while showing — the SDK ignores a loadInterstitialAd call made while an ad is on screen. Trigger the next load from the .skipped status. Interstitial auto-reload is off by default, so reload yourself unless the zone enables it server-side.
  5. Respect the user — don't show on every screen or interrupt critical flows such as checkout or onboarding.

Troubleshooting

Interstitial Not Showing

  1. Ensure you're passing a valid view controller (self must be a UIViewController).
  2. Check ads are not disabled.
  3. Enable debug logging.
EMAManager.shared.showInterstitial(zoneId: "YOUR_ZONE_ID", from: self)
print("Ads disabled: \(EMASettings.shared.isAdsDisabled)")
EMASettings.shared.logLevel = .all

API Reference

EMAManager.loadInterstitialAd

func loadInterstitialAd(
zoneId: String,
delegate: AdStatusDelegate? = nil
)
ParameterTypeDescription
zoneIdStringYour interstitial zone ID
delegateAdStatusDelegate?Callback delegate

EMAManager.showInterstitial

func showInterstitial(
zoneId: String,
from viewController: UIViewController
)
ParameterTypeDescription
zoneIdStringThe zone identifier for the interstitial to show
viewControllerUIViewControllerThe 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

SwiftObjective-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 EMAAdObserver and pass your object as the observer: argument (instead of delegate:). Status is delivered as EMAAdStatusType via interstitialStatusChanged:.