Media Placement
Media placements display in-content ads. The container can render several creative types, including video.
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
UIKit Implementation
- Swift
- Objective-C
import UIKit
import TeadsSDK
class ArticleViewController: UIViewController {
private var mediaPlacement: TeadsAdPlacementMedia?
private var adView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
setupMediaPlacement()
}
private func setupMediaPlacement() {
// Create configuration
let config = TeadsAdPlacementMediaConfig(
pid: 84242, // Your placement ID
articleUrl: URL(string: "https://example.com/article/123")
)
// Create placement with delegate
mediaPlacement = TeadsAdPlacementMedia(config, delegate: self)
// OR
mediaPlacement = Teads.createPlacement(
with: config,
delegate: self
)
// Load the ad
do {
adView = try mediaPlacement?.loadAd()
// Add to your view hierarchy
if let adView = adView {
insertAdViewInContent(adView)
}
} catch {
print("Failed to load ad: \(error)")
}
}
private func insertAdViewInContent(_ adView: UIView) {
// Add the ad view to your content
// For example, in a scroll view between paragraphs
contentStackView.insertArrangedSubview(adView, at: 2)
// The SDK handles sizing automatically
adView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
adView.leadingAnchor.constraint(equalTo: contentStackView.leadingAnchor),
adView.trailingAnchor.constraint(equalTo: contentStackView.trailingAnchor)
])
}
}
// MARK: - TeadsAdPlacementEventsDelegate
extension ArticleViewController: TeadsAdPlacementEventsDelegate {
func adPlacement(_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String : Any]?) {
switch event {
case .ready:
print("Ad is ready to be displayed")
case .rendered:
print("Ad has been rendered")
case .viewed:
print("Ad has met viewability criteria")
case .clicked:
print("User clicked on the ad")
// SDK handles URL opening automatically
case .failed:
if let error = data?["error"] as? String {
print("Ad failed to load: \(error)")
}
case .heightUpdated:
if let height = data?["height"] as? CGFloat {
print("Ad height updated to: \(height)")
// No need to do anything, the placement view will handle it's own size.
}
default:
break
}
}
}
#import <UIKit/UIKit.h>
#import <TeadsSDK/TeadsSDK-Swift.h>
@interface ArticleViewController : UIViewController <TeadsAdPlacementEventsDelegate>
@property (nonatomic, strong) TeadsAdPlacementMedia *mediaPlacement;
@property (nonatomic, strong) UIView *adView;
@end
@implementation ArticleViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupMediaPlacement];
}
- (void)setupMediaPlacement {
// Teads.createPlacement(with:delegate:) is a Swift-only generic — create the
// placement directly with its Objective-C-friendly convenience initializer
self.mediaPlacement = [[TeadsAdPlacementMedia alloc]
initWithPid:84242 // Your placement ID
articleUrl:[NSURL URLWithString:@"https://example.com/article/123"]
delegate:self];
// Load the ad
NSError *error = nil;
self.adView = [self.mediaPlacement loadAdAndReturnError:&error];
if (error) {
NSLog(@"Failed to load ad: %@", error);
return;
}
// Add to your view hierarchy
if (self.adView) {
[self insertAdViewInContent:self.adView];
}
}
- (void)insertAdViewInContent:(UIView *)adView {
// Add the ad view to your content
// For example, in a scroll view between paragraphs
[self.contentStackView insertArrangedSubview:adView atIndex:2];
// The SDK handles sizing automatically
adView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[adView.leadingAnchor constraintEqualToAnchor:self.contentStackView.leadingAnchor],
[adView.trailingAnchor constraintEqualToAnchor:self.contentStackView.trailingAnchor]
]];
}
#pragma mark - TeadsAdPlacementEventsDelegate
- (void)adPlacement:(id<TeadsAdPlacementIdentifiable>)placement
didEmitEvent:(TeadsAdPlacementEventName)event
data:(NSDictionary<NSString *, id> *)data {
switch (event) {
case TeadsAdPlacementEventNameReady:
NSLog(@"Ad is ready to be displayed");
break;
case TeadsAdPlacementEventNameRendered:
NSLog(@"Ad has been rendered");
break;
case TeadsAdPlacementEventNameViewed:
NSLog(@"Ad has met viewability criteria");
break;
case TeadsAdPlacementEventNameClicked:
NSLog(@"User clicked on the ad");
// SDK handles URL opening automatically
break;
case TeadsAdPlacementEventNameFailed: {
NSString *error = data[@"error"];
if (error) {
NSLog(@"Ad failed to load: %@", error);
}
break;
}
case TeadsAdPlacementEventNameHeightUpdated: {
NSNumber *height = data[@"height"];
if (height) {
NSLog(@"Ad height updated to: %@", height);
// No need to do anything, the placement view will handle its own size.
}
break;
}
default:
break;
}
}
@end
SwiftUI Media Implementation (Simplified Approach)
The SDK provides a native SwiftUI view for Media placements:
import SwiftUI
import TeadsSDK
struct ArticleView: View {
let mediaConfig = TeadsAdPlacementMediaConfig(
pid: 84242,
articleUrl: URL(string: "https://example.com/article/123")
)
var body: some View {
ScrollView {
VStack(spacing: 16) {
Text("Article Title")
.font(.largeTitle)
Text("First paragraph of content...")
// Media Ad Placement - Simple one-liner
TeadsAdPlacementSwiftUIView<TeadsAdPlacementMedia>(
config: mediaConfig,
delegate: nil
)
.frame(maxWidth: .infinity) // Important: Set width explicitly
Text("More article content...")
}
.padding()
}
}
}
Swift-only: TeadsAdPlacementSwiftUIView is a generic SwiftUI struct, and SwiftUI views are not bridgeable to Objective-C.
SwiftUI Media Implementation (With Event Handling)
If you need to handle events or track ad lifecycle:
import SwiftUI
import TeadsSDK
struct ArticleView: View {
@StateObject private var adManager = MediaAdManager()
var body: some View {
ScrollView {
VStack(spacing: 16) {
Text("Article Title")
.font(.largeTitle)
Text("First paragraph of content...")
// Media Ad Placement with event handling
TeadsAdPlacementSwiftUIView<TeadsAdPlacementMedia>(
config: adManager.mediaConfig,
delegate: adManager
)
.frame(maxWidth: .infinity) // Important: Set width explicitly
Text("More article content...")
}
.padding()
}
}
}
// Simple event handler
class MediaAdManager: NSObject, ObservableObject, TeadsAdPlacementEventsDelegate {
@Published var isLoaded = false
@Published var hasError = false
let mediaConfig = TeadsAdPlacementMediaConfig(
pid: 84242,
articleUrl: URL(string: "https://example.com/article/123")
)
func adPlacement(_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String : Any]?) {
DispatchQueue.main.async {
switch event {
case .ready, .rendered:
self.isLoaded = true
print("Ad loaded successfully")
case .failed:
self.hasError = true
if let error = data?["error"] as? String {
print("Ad failed: \(error)")
}
case .clicked:
print("Ad clicked")
default:
break
}
}
}
}
Swift-only: TeadsAdPlacementSwiftUIView is a generic SwiftUI struct, and SwiftUI views are not bridgeable to Objective-C.
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.
Media creatives change height after they load. Do not pin a fixed height. In SwiftUI, do not set .frame(height:).
In a stack or table, pin leading and trailing only. The placement view sizes itself.
In a collection view, cells keep a fixed size until you handle .heightUpdated: use its reported height to update and reload the affected cell.
Ad Lifecycle Listener
Implement TeadsAdPlacementEventsDelegate to observe playback, clicks, and viewability. 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
- ✅ Enable ad view resizing. Do not give the ad a fixed height.