Migration Guide from Outbrain SDK to Teads Unified SDK
This guide helps developers currently using the Outbrain SDK transition to the new Teads Unified SDK. Following the merger of Teads and Outbrain, we've created a unified SDK that maintains all current Teads SDK functionality while adding powerful new capabilities.
Important Notice
⚠️ The standalone Outbrain SDK is being deprecated
✅ All Outbrain features are preserved in the Teads Unified SDK
New features and improvements are available
Migration is required but straightforward
Overview of Changes
What's Changing
| Aspect | Outbrain SDK | Teads Unified SDK |
|---|---|---|
| SDK Name | OutbrainSDK | TeadsSDK |
| Import Statement | import OutbrainSDK | import TeadsSDK |
| Initialization | Outbrain.initializeOutbrain() | Teads.configure() |
| Widget Class | SFWidget | TeadsAdPlacementFeed |
| Recommendations | OBRequest | TeadsAdPlacementRecommendations |
What's Preserved
✅ All widget functionality
✅ Content recommendation algorithms
✅ Viewability tracking
✅ User personalization
✅ Dark mode support
✅ Event tracking
What's New
🎁 Access to Teads video ad formats
🎁 Unified event system
🎁 Improved performance
🎁 Enhanced privacy controls
Step-by-Step Migration
Step 1: Update Dependencies
Remove Outbrain SDK
CocoaPods:
# Remove from Podfile
# pod 'OutbrainSDK'
# Add Teads SDK
pod 'TeadsSDK', '~> 6.0'
Swift Package Manager:
// Remove Outbrain package
// Add Teads package
dependencies: [
.package(url: "https://github.com/teads/TeadsSDK-iOS.git", upToNextMajor: "6.0.1")
]
Run pod install or update your SPM dependencies.
Step 2: Update Imports
Replace all Outbrain imports with Teads:
// Before
import OutbrainSDK
// After
import TeadsSDK
Step 3: Update SDK Initialization
Before (Outbrain SDK)
// AppDelegate or App initialization
Outbrain.initializeOutbrain(withPartnerKey: "YOUR_PARTNER_KEY")
After (Teads Unified SDK)
// AppDelegate or App initialization
Teads.configure(with: "YOUR_PARTNER_KEY")
Step 4: Migrate Widget Implementation
The widget functionality is now provided through TeadsAdPlacementFeed.
Before (Outbrain SDK) - UIKit
class WidgetViewController: UIViewController {
var widget: SFWidget?
override func viewDidLoad() {
super.viewDidLoad()
// Create widget
widget = SFWidget()
widget?.delegate = self
// Configure widget
widget?.configure(
with: self,
url: "https://mobile-demo.outbrain.com",
widgetId: "MB_1",
widgetIndex: 0,
installationKey: "NANOWDGT01",
userId: "user123",
darkMode: false
)
// Add to view
view.addSubview(widget!)
// Setup constraints
widget?.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
widget!.leadingAnchor.constraint(equalTo: view.leadingAnchor),
widget!.trailingAnchor.constraint(equalTo: view.trailingAnchor),
widget!.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
}
// Delegate
extension WidgetViewController: SFWidgetDelegate {
func didChangeHeight(_ newHeight: CGFloat) {
// Update height
}
func onRecClick(_ url: URL) {
// Handle click
}
func onOrganicRecClick(_ url: URL) {
// Handle organic click
}
}
After (Teads Unified SDK) - UIKit
class WidgetViewController: UIViewController {
var feedPlacement: TeadsAdPlacementFeed?
var feedView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Create configuration
let config = TeadsAdPlacementFeedConfig(
articleUrl: URL(string: "https://mobile-demo.outbrain.com")!,
widgetId: "MB_1",
installationKey: "NANOWDGT01",
widgetIndex: 0,
userId: "user123",
darkMode: false
)
// Create placement
feedPlacement = Teads.createPlacement(with: config, delegate: self)
// Load feed
do {
feedView = try feedPlacement?.loadAd()
// Add to view
if let feedView = feedView {
view.addSubview(feedView)
// Setup constraints...
}
} catch {
print("Failed to load feed: \(error)")
}
}
}
// Delegate
extension WidgetViewController: TeadsAdPlacementEventsDelegate {
func adPlacement(_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String : Any]?) {
switch event {
case .heightUpdated:
if let height = data?["height"] as? CGFloat {
// No need to update height, the placement handles it's own height automatically
}
case .clickedOrganic:
if let url = data?["url"] as? String {
// Handle organice click
}
case .ready:
print("Feed loaded successfully")
default:
break
}
}
}
Step 5: Migrate SwiftUI Implementation
Before (Outbrain SDK) - SwiftUI
import SwiftUI
import OutbrainSDK
struct ContentView: View {
var body: some View {
VStack {
// Your content
// Outbrain widget
OutbrainWidgetView(
url: "https://mobile-demo.outbrain.com",
widgetId: "MB_1",
widgetIndex: 0,
installationKey: "NANOWDGT01",
userId: "user123",
darkMode: false,
onOrganicRecClick: { url in
// Handle click
}
)
.frame(height: 400)
}
}
}
After (Teads Unified SDK) - SwiftUI
import SwiftUI
import TeadsSDK
struct ContentView: View {
@StateObject private var feedManager = FeedManager()
var body: some View {
VStack {
// Your content
// Teads Feed placement
if let feedView = feedManager.feedView {
FeedContainer(feedView: feedView)
.frame(height: feedManager.feedHeight)
}
}
.onAppear {
feedManager.loadFeed()
}
}
}
// UIViewRepresentable wrapper
struct FeedContainer: UIViewRepresentable {
let feedView: UIView
func makeUIView(context: Context) -> UIView {
return feedView
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
// Feed Manager
class FeedManager: NSObject, ObservableObject {
@Published var feedView: UIView?
@Published var feedHeight: CGFloat = 400
private var feedPlacement: TeadsAdPlacementFeed?
func loadFeed() {
let config = TeadsAdPlacementFeedConfig(
articleUrl: URL(string: "https://mobile-demo.outbrain.com")!,
widgetId: "MB_1",
installationKey: "NANOWDGT01",
widgetIndex: 0,
userId: "user123",
darkMode: false
)
feedPlacement = Teads.createPlacement(with: config, delegate: self)
do {
feedView = try feedPlacement?.loadAd()
} catch {
print("Failed to load feed: \(error)")
}
}
}
extension FeedManager: TeadsAdPlacementEventsDelegate {
func adPlacement(_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String : Any]?) {
if event == .heightUpdated, let height = data?["height"] as? CGFloat {
DispatchQueue.main.async {
self.feedHeight = height
}
}
}
}
Step 6: Migrate Recommendations API
Before (Outbrain SDK)
// Fetch recommendations programmatically
let request = OBRequest(url: "https://mobile-demo.outbrain.com",
widgetID: "SDK_1")
Outbrain.fetchRecommendations(for: request) { response in
for recommendation in response.recommendations {
print("Title: \(recommendation.content)")
print("URL: \(recommendation.url)")
}
}
After (Teads Unified SDK)
// Fetch recommendations programmatically
let config = TeadsAdPlacementRecommendationsConfig(
articleUrl: URL(string: "https://mobile-demo.outbrain.com")!,
widgetId: "SDK_1",
widgetIndex: 0
)
let placement = TeadsAdPlacementRecommendations(config, delegate: self)
// Callback approach
placement.loadAd { response in
for recommendation in response.recommendations {
print("Title: \(recommendation.content)")
print("URL: \(recommendation.url)")
}
}
// Or async/await approach
Task {
do {
let loader = try placement.loadAd()
let recommendations = try await loader()
for recommendation in recommendations {
print("Title: \(recommendation.content)")
print("URL: \(recommendation.url)")
}
} catch {
print("Error: \(error)")
}
}
Step 7: Update Dark Mode Handling
Before (Outbrain SDK)
// Toggle dark mode
widget?.toggleDarkMode(isDarkMode)
After (Teads Unified SDK)
// For Feed placement
feedPlacement?.toggleDarkMode(isDarkMode)
// Or configure at creation
let config = TeadsAdPlacementFeedConfig(
// ... other parameters
darkMode: true
)
Step 8: Update Viewability Tracking (Regular SDK / TeadsAdPlacementRecommendations)
Before (Outbrain SDK)
// Configure viewability per listing
Outbrain.configureViewabilityPerListing(for: view, withRec: recommendation)
After (Teads Unified SDK)
// Configure viewability per listing
TeadsAdPlacementRecommendations.configureViewabilityPerListing(for: view, withRec: recommendation)
New Opportunities with Teads SDK
Add Video Ads to Your App
Now you can monetize with premium video ads alongside your content recommendations:
class EnhancedContentViewController: UIViewController {
// Existing feed placement
var feedPlacement: TeadsAdPlacementFeed?
// NEW: Add video ads
var videoPlacement: TeadsAdPlacementMedia?
func setupPlacements() {
// Your existing feed
setupFeed()
// NEW: Add video ad
let videoConfig = TeadsAdPlacementMediaConfig(
pid: 84242, // Get PID from Teads
articleUrl: URL(string: "https://example.com/article/123")
)
videoPlacement = TeadsAdPlacementMedia(videoConfig, delegate: self)
if let videoView = try? videoPlacement?.loadAd() {
// Insert video ad in your content
contentStackView.insertArrangedSubview(videoView, at: 2)
}
}
}
Enhanced Event Tracking
The unified event system provides more detailed insights:
extension YourViewController: TeadsAdPlacementEventsDelegate {
func adPlacement(_ placement: TeadsAdPlacementIdentifiable?,
didEmitEvent event: TeadsAdPlacementEventName,
data: [String : Any]?) {
// Handle specific events
switch event {
case .viewed:
// Track viewability
case .clicked:
// Track engagement
case .failed:
// Handle errors
// ... Handle other events if needed
default:
break
}
}
}
API Mapping Reference
| Outbrain SDK | Teads Unified SDK |
|---|---|
SFWidget | TeadsAdPlacementFeed |
OBRequest | TeadsAdPlacementRecommendationsConfig |
OBRecommendation | OBRecommendation (unchanged) |
OBError | Standard Swift Error |
SFWidgetDelegate | TeadsAdPlacementEventsDelegate |
OBResponseDelegate | Closure/async callbacks |
Outbrain.initializeOutbrain() | Teads.configure() |
Outbrain.fetchRecommendations() | TeadsAdPlacementRecommendations.loadAd() |
Support and Resources
Migration Support
- Integration Guide
- Support: Support
Next Steps
- Review the Integration Guide for detailed implementation
- Explore new Video Ad opportunities
- Learn about Privacy Compliance
We're here to help make your migration smooth and successful. See our support page in case you have any questions.