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.0")
]
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")
Outbran.fetchRecommendations(for: request) { response in
    for recommendation in response.recommendations {
        print("Title: \(recommendation.title)")
        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.title)")
        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.title)")
            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.