Interstitial Placement
Interstitial placements display a fullscreen ad that the user can dismiss. Unlike other placement types, an interstitial is loaded in the background and shown at a natural transition point in your app.
The official Teads SDK sample application includes working examples of this format. Use it for implementation examples and as a reference while you set up this placement.
Example
Configuration
- Swift
- Objective-C
import TeadsSDK
let config = TeadsAdPlacementInterstitialConfig(
articleUrl: URL(string: "https://example.com/article")!,
widgetId: "INT_APP_1", // Your widget ID
installationKey: "NANOWDGT01", // Your installation key
floorPrice: 2 // Optional: minimum bid price in US dollars
)
#import <TeadsSDK/TeadsSDK-Swift.h>
// Objective-C has no separate Config type — pass parameters (including the
// optional floorPrice) directly to the placement's convenience initializer.
TeadsAdPlacementInterstitial *placement = [[TeadsAdPlacementInterstitial alloc]
initWithArticleUrl:[NSURL URLWithString:@"https://example.com/article"]
widgetId:@"INT_APP_1" // Your widget ID
installationKey:@"NANOWDGT01" // Your installation key
floorPrice:2 // Optional: minimum bid price in US dollars
delegate:nil];
Loading an Interstitial
Create the placement and load it ahead of the moment you want to show it:
- Swift
- Objective-C
import TeadsSDK
class InterstitialManager: NSObject {
private var placement: TeadsAdPlacementInterstitial?
func load() {
let config = TeadsAdPlacementInterstitialConfig(
articleUrl: URL(string: "https://example.com/article")!,
widgetId: "INT_APP_1",
installationKey: "NANOWDGT01"
)
placement = Teads.createPlacement(with: config, delegate: self)
placement?.loadAd()
}
}
#import <TeadsSDK/TeadsSDK-Swift.h>
@interface InterstitialManager : NSObject
@property (nonatomic, strong) TeadsAdPlacementInterstitial *placement;
@end
@implementation InterstitialManager
- (void)load {
// Teads.createPlacement(with:delegate:) is a Swift-only generic — create the
// placement directly with its Objective-C-friendly convenience initializer
self.placement = [[TeadsAdPlacementInterstitial alloc]
initWithArticleUrl:[NSURL URLWithString:@"https://example.com/article"]
widgetId:@"INT_APP_1"
installationKey:@"NANOWDGT01"
delegate:self];
[self.placement loadAd];
}
@end
The delegate must conform to TeadsFullScreenEventsDelegate (which extends TeadsAdPlacementEventsDelegate) to receive both ad and fullscreen lifecycle events. Passing a delegate that does not conform to TeadsFullScreenEventsDelegate will result in a warning and no events being delivered.
Presenting the Ad
Check isReady before calling show(from:):
- Swift
- Objective-C
func showAd(from viewController: UIViewController) {
guard let placement, placement.isReady else {
print("Ad not ready")
return
}
placement.show(from: viewController)
}
- (void)showAdFrom:(UIViewController *)viewController {
if (!self.placement || !self.placement.isReady) {
NSLog(@"Ad not ready");
return;
}
[self.placement showFrom:viewController];
}
show(from:) accepts an optional UIViewController. If nil is passed, the SDK falls back to the application's top view controller automatically.
Handling Events
Implement TeadsFullScreenEventsDelegate to respond to ad and lifecycle events:
- Swift
- Objective-C
extension InterstitialManager: TeadsFullScreenEventsDelegate {
// Ad events (load result, viewability, clicks)
func adPlacement(
_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String: Any]?
) {
switch event {
case .ready:
print("Ad loaded — ready to show")
case .failed:
let reason = data?["reason"] as? String ?? "Unknown"
print("Ad failed: \(reason)")
// reason is "Ad expired" when the cache TTL elapses before show()
case .rendered:
print("Ad appeared on screen")
case .viewed:
print("Viewability threshold reached")
case .clicked:
print("Ad clicked")
// The SDK opens the URL automatically — do not navigate manually
default:
break
}
}
// Fullscreen lifecycle events
func fullScreenPlacement(
_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsFullScreenEventName,
data: [String: Any]?
) {
switch event {
case .willPresent:
print("Ad about to present — pause audio, suspend timers")
case .presented:
print("Ad is now fullscreen")
case .willDismiss:
print("Ad about to dismiss")
case .dismissed:
print("Ad dismissed — resume app state")
placement?.invalidate()
@unknown default:
break
}
}
}
@interface InterstitialManager () <TeadsFullScreenEventsDelegate>
@end
@implementation InterstitialManager (TeadsFullScreenEventsDelegate)
// Ad events (load result, viewability, clicks)
- (void)adPlacement:(id<TeadsAdPlacementIdentifiable>)placement
didEmitEvent:(TeadsAdPlacementEventName)event
data:(NSDictionary<NSString *, id> *)data {
switch (event) {
case TeadsAdPlacementEventNameReady:
NSLog(@"Ad loaded — ready to show");
break;
case TeadsAdPlacementEventNameFailed: {
NSString *reason = data[@"reason"] ?: @"Unknown";
NSLog(@"Ad failed: %@", reason);
// reason is "Ad expired" when the cache TTL elapses before show()
break;
}
case TeadsAdPlacementEventNameRendered:
NSLog(@"Ad appeared on screen");
break;
case TeadsAdPlacementEventNameViewed:
NSLog(@"Viewability threshold reached");
break;
case TeadsAdPlacementEventNameClicked:
NSLog(@"Ad clicked");
// The SDK opens the URL automatically — do not navigate manually
break;
default:
break;
}
}
// Fullscreen lifecycle events
- (void)fullScreenPlacement:(id<TeadsAdPlacementIdentifiable>)placement
didEmitEvent:(TeadsFullScreenEventName)event
data:(NSDictionary<NSString *, id> *)data {
switch (event) {
case TeadsFullScreenEventNameWillPresent:
NSLog(@"Ad about to present — pause audio, suspend timers");
break;
case TeadsFullScreenEventNamePresented:
NSLog(@"Ad is now fullscreen");
break;
case TeadsFullScreenEventNameWillDismiss:
NSLog(@"Ad about to dismiss");
break;
case TeadsFullScreenEventNameDismissed:
NSLog(@"Ad dismissed — resume app state");
[self.placement invalidate];
break;
default:
break;
}
}
@end
Ad Cache TTL
Once loaded, the ad must be shown within its cache TTL or it expires. The default TTL is 3600 seconds (1 hour), configurable server-side per widget. When the ad expires, .failed is emitted with reason: "Ad expired" and the placement is automatically cleaned up. Call loadAd() again to fetch a fresh ad.
Cleanup
Call invalidate() when you are done with a placement or want to discard a loaded ad before showing it:
- Swift
- Objective-C
// Discard without showing
placement?.invalidate()
// Or set to nil to let ARC clean up
placement = nil
// Discard without showing
[self.placement invalidate];
// Or set to nil to let ARC clean up
self.placement = nil;
invalidate() is safe to call multiple times. After invalidation the same placement instance can be reloaded via loadAd().
Best Practices
The SDK opens the click URL. Do not navigate in this handler or the browser will open twice. Use the event for tracking only.
Ad Lifecycle Listener
Implement TeadsFullScreenEventsDelegate (which extends TeadsAdPlacementEventsDelegate) to observe playback, clicks, viewability, and fullscreen presentation events. See Placement Events Listener for the full event reference and error handling guide.
Checklist
- ✅ Ensure Brand Safety is enabled
- ✅ Ensure you comply with privacy legal requirements (GDPR/CCPA/GPP)
- ✅ Comply with app-ads.txt
- ✅ Implement proper error handling
- ✅ Test with the PIDs in Test PIDs and Configurations