Appearance
Opera Ads iOS SDK - Integration Guide
Overview
The Opera Ads iOS SDK enables developers to monetize their iOS applications with high-quality ads. The SDK supports multiple ad formats including Native, Banner (MRAID), Interstitial, Rewarded Video, Rewarded Interstitial, and App Open ads, with minimal setup and robust event callbacks.
Key Features
- Multiple Ad Formats: Native, Banner, Interstitial, Rewarded Video, Rewarded Interstitial, and App Open
- Bidding Support: Waterfall, Client-to-Server (C2S) Bidding, and Server-to-Server (S2S) Bidding
- Dual Language API: Full Swift and Objective-C support
- Mediation Ready: Adapters for AdMob, AppLovin MAX, and TopOn
- Privacy Compliant: GDPR, CCPA, and COPPA support
- Rich Media: MRAID 2.0 support for interactive ads
- Debug Logging: Comprehensive logging system for development
Prerequisites
Before integrating the Opera Ads SDK, ensure you meet the following requirements:
Development Environment
- Xcode: 14.0 or higher
- iOS Deployment Target: iOS 13.0 or higher
- Language: Swift 5.0+ or Objective-C
- CocoaPods: 1.10.0 or higher (if using CocoaPods)
Account Setup
- Active Opera Ads publisher account
- Application ID (format:
pub{}/ep{}/app{}) - iOS App ID (iTunes App ID)
- Placement IDs for each ad unit
Required Permissions
Add the following to your Info.plist:
xml
<!-- Required for ad serving -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<!-- Optional: For location-based targeting -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is used to provide more relevant ads</string>Installation & Setup
Method 1: CocoaPods (Recommended)
Add the following to your Podfile:
ruby
platform :ios, '13.0'
target 'YourApp' do
use_frameworks!
# Opera Ads SDK
pod 'OpAdxSdk', '~> 2.9.0'
endThen run:
bash
pod installMethod 2: Manual Integration
- Download the latest
OpAdxSdk.xcframeworkfrom the releases page - Drag the framework into your Xcode project
- In General > Frameworks, Libraries, and Embedded Content, select Embed & Sign
- Add required dependencies manually (if not using CocoaPods)
Dependency Configuration
The SDK requires the following dependencies (automatically included with CocoaPods):
ruby
# Core dependencies
pod 'Alamofire', '~> 5.6'
pod 'GoogleUserMessagingPlatform', '~> 2.0'
# Optional: For Open Measurement support
pod 'OMSDK_Opera', '~> 1.4'Initialization
Initialize the SDK in your AppDelegate before loading any ads. The SDK supports both synchronous and asynchronous initialization.
Swift Example
swift
import UIKit
import OpAdxSdk
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Enable debug logging (development only)
OpAdxLogger.logLevel = .debug
// Create SDK configuration
let config = OpAdxSdkInitConfig.create(
applicationId: "pub13423013211200/ep13423013211584/app14170937163904",
iOSAppId: "1444253128"
)
config.useTestAd = true // Use test ads during development
// Initialize SDK with callbacks
OpAdxSDK.initialize(
withConfig: config,
onSuccess: {
print("✅ Opera Ads SDK initialized successfully")
print("SDK Version: \(OpAdxSdkCore.getVersion()).\(OpAdxSdkCore.getBuildNum())")
},
onError: { error in
print("❌ SDK initialization failed: \(error.localizedDescription)")
}
)
return true
}
}Objective-C Example
objective-c
#import "AppDelegate.h"
#import <OpAdxSdk/OpAdxSdk.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Enable debug logging (development only)
OpAdxLogger.logLevel = OpAdxLogLevelDebug;
// Create SDK configuration
OpAdxSdkInitConfig *config = [OpAdxSdkInitConfig
createWithApplicationId:@"pub13423013211200/ep13423013211584/app14170937163904"
iOSAppId:@"1444253128"
publisherName:nil];
config.useTestAd = YES; // Use test ads during development
// Initialize SDK with callbacks
[OpAdxSDK initializeWithConfig:config
onSuccess:^{
NSLog(@"✅ Opera Ads SDK initialized successfully");
}
onError:^(NSError *error) {
NSLog(@"❌ SDK initialization failed: %@", error.localizedDescription);
}];
return YES;
}
@endInitialization Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
applicationId | String | Yes | Your application ID (format: pub{}/ep{}/app{}) |
iOSAppId | String | Yes | iTunes App ID (numeric string) |
publisherName | String | No | Publisher name for reporting |
useTestAd | Boolean | No | Enable test ads (default: false) |
coppa | Boolean | No | COPPA compliance flag |
usPrivacy | String | No | CCPA/US Privacy string (e.g., "1YNN") |
Ad Formats
1. Native Ads
Native ads provide customizable ad content that matches your app's look and feel.
Swift Implementation
swift
import OpAdxSdk
class NativeAdViewController: UIViewController {
private var nativeAd: OpAdxNativeAd?
func loadNativeAd() {
// Create native ad instance
nativeAd = OpAdxNativeAd(
placementId: "s14198263063424",
auctionType: .regular
)
// Create listener
let listener = OpAdxNativeAdListenerImp(
onAdLoaded: { [weak self] ad in
guard let self = self, let nativeAd = ad as? OpAdxNativeAd else { return }
print("Native ad loaded: \(nativeAd.title() ?? "")")
self.renderNativeAd(nativeAd)
},
onAdFailedToLoad: { error in
print("Native ad failed to load: \(error.message)")
},
onAdImpression: {
print("Native ad impression recorded")
},
onAdClicked: {
print("Native ad clicked")
}
)
// Load ad
nativeAd?.loadAd(listener: listener)
}
func renderNativeAd(_ nativeAd: OpAdxNativeAd) {
// Create native ad view
let nativeAdView = OpAdxNativeAdView(frame: CGRect(x: 0, y: 0, width: 300, height: 400))
nativeAdView.configure(with: nativeAd)
// Add to container
adContainer.addSubview(nativeAdView)
// Register for interaction tracking
let rootView = OpAdxNativeAdRootView(root: nativeAdView)
nativeAd.registerInteractionViews(
container: rootView,
interactionViews: nativeAdView.interactionViews,
adChoicePosition: .topRight
)
}
func destroyNativeAd() {
nativeAd?.destroy()
nativeAd = nil
}
}Objective-C Implementation
objective-c
#import <OpAdxSdk/OpAdxSdk.h>
@interface NativeAdViewController ()
@property (nonatomic, strong) OpAdxNativeAdBridge *nativeAd;
@end
@implementation NativeAdViewController
- (void)loadNativeAd {
// Create native ad instance
self.nativeAd = [[OpAdxNativeAdBridge alloc]
initWithPlacementId:@"s14198263063424"
auctionType:AdAuctionTypeRegular];
self.nativeAd.delegate = self;
[self.nativeAd loadAd];
}
#pragma mark - OpAdxNativeAdDelegate
- (void)nativeAdDidLoad:(OpAdxNativeAdBridge *)nativeAd {
NSLog(@"Native ad loaded: %@", nativeAd.title);
[self renderNativeAd:nativeAd];
}
- (void)nativeAd:(OpAdxNativeAdBridge *)nativeAd didFailWithError:(OpAdxAdError *)error {
NSLog(@"Native ad failed: %@", error.message);
}
- (void)nativeAdWillLogImpression:(OpAdxNativeAdBridge *)nativeAd {
NSLog(@"Native ad impression");
}
- (void)nativeAdDidClick:(OpAdxNativeAdBridge *)nativeAd {
NSLog(@"Native ad clicked");
}
@endNative Ad Components
The SDK provides access to the following native ad assets:
| Asset | Type | Description |
|---|---|---|
title() | String | Ad headline (required) |
body() | String | Ad description text |
callToAction() | String | CTA button text (e.g., "Install") |
iconUrl() | String | Square icon image URL |
mainImageUrl() | String | Main creative image URL |
rating() | Double | App rating (0-5) |
advertiser() | String | Advertiser name |
mediaView | UIView | Video/image media view |
2. Banner Ads
Banner ads are rectangular ads that appear at the top or bottom of your app's interface.
Supported Sizes
| Size Constant | Dimensions | Description |
|---|---|---|
BANNER | 320x50 | Standard banner |
BANNER_LARGE | 320x100 | Large banner |
BANNER_MREC | 300x250 | Medium rectangle |
BANNER_LEADERBOARD | 728x90 | Leaderboard (iPad) |
BANNER_SMART | Screen width x auto | Smart banner (adapts to device) |
Swift Implementation
swift
import OpAdxSdk
class BannerViewController: UIViewController {
private var bannerAdView: OpAdxBannerAdView?
func loadBannerAd() {
// Create banner ad view
bannerAdView = OpAdxBannerAdView()
bannerAdView?.setPlacementId("s14170965187264")
bannerAdView?.setAdSize(.BANNER_MREC)
// Create listener
let listener = OpAdxBannerAdListenerImp(
onAdLoaded: { [weak self] bannerAdInfo in
guard let self = self, let info = bannerAdInfo as? OpAdxBannerAdInfo else { return }
print("Banner loaded: \(info.adSize)")
self.showBanner()
},
onAdFailedToLoad: { error in
print("Banner failed to load: \(error.message)")
},
onAdImpression: {
print("Banner impression")
},
onAdClicked: {
print("Banner clicked")
}
)
// Load ad
bannerAdView?.loadAd(listener: listener)
}
func showBanner() {
guard let bannerAdView = bannerAdView else { return }
// Add to view hierarchy
view.addSubview(bannerAdView)
bannerAdView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
bannerAdView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
bannerAdView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
bannerAdView.widthAnchor.constraint(equalToConstant: 300),
bannerAdView.heightAnchor.constraint(equalToConstant: 250)
])
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
bannerAdView?.pause()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
bannerAdView?.resume()
}
func destroyBanner() {
bannerAdView?.destroy()
bannerAdView = nil
}
}Auto-Refresh Configuration
swift
// Set auto-refresh interval (30-120 seconds)
bannerAdView?.setAutoRefreshInterval(60)
// Or disable auto-refresh
bannerAdView?.setAutoRefreshInterval(0)3. Interstitial Ads
Interstitial ads are full-screen ads that cover the interface of their host app.
Swift Implementation
swift
import OpAdxSdk
class InterstitialViewController: UIViewController {
private var interstitialAd: OpAdxInterstitialAd?
func loadInterstitialAd() {
// Create interstitial ad
interstitialAd = OpAdxInterstitialAd(
placementId: "s14198264979520",
auctionType: .regular
)
// Create load listener
let loadListener = OpAdxInterstitialAdLoadListenerImp(
onAdLoaded: { [weak self] ad in
print("Interstitial loaded")
self?.showButton.isEnabled = true
},
onAdFailedToLoad: { error in
print("Interstitial failed to load: \(error.message)")
}
)
// Load ad
interstitialAd?.load(placementId: "s14198264979520", listener: loadListener)
}
func showInterstitialAd() {
guard let interstitialAd = interstitialAd else { return }
// Check if ad is still valid
if interstitialAd.isAdInvalidated() {
print("Ad has expired")
loadInterstitialAd() // Reload
return
}
// Create interaction listener
let interactionListener = OpAdxInterstitialAdInteractionListenerImp(
onAdClicked: {
print("Interstitial clicked")
},
onAdDisplayed: {
print("Interstitial displayed")
},
onAdDismissed: { [weak self] in
print("Interstitial dismissed")
self?.interstitialAd = nil
self?.loadInterstitialAd() // Preload next ad
},
onAdFailedToShow: { error in
print("Interstitial failed to show: \(error.message)")
}
)
// Show ad
interstitialAd.show(on: self, listener: interactionListener)
}
}4. Rewarded Video Ads
Rewarded video ads reward users for watching short videos.
Swift Implementation
swift
import OpAdxSdk
class RewardedViewController: UIViewController {
private var rewardedAd: OpAdxRewardedAd?
func loadRewardedAd() {
// Create rewarded ad
rewardedAd = OpAdxRewardedAd(
placementId: "s14198592226752",
auctionType: .regular
)
// Create load listener
let loadListener = OpAdxRewardedAdLoadListenerImp(
onAdLoaded: { [weak self] ad in
print("Rewarded ad loaded")
self?.showButton.isEnabled = true
},
onAdFailedToLoad: { error in
print("Rewarded ad failed to load: \(error.message)")
}
)
// Load ad
rewardedAd?.load(placementId: "s14198592226752", listener: loadListener)
}
func showRewardedAd() {
guard let rewardedAd = rewardedAd else { return }
// Set scene ID (optional, for analytics)
rewardedAd.setSceneId("level_complete")
// Set SSV options (optional, for server-side verification)
let ssvOptions = RewardSsvOptions.Builder()
.userId("user_12345")
.customData("level=5&score=1000")
.build()
rewardedAd.setRewardSsvOptions(ssvOptions)
// Create interaction listener
let interactionListener = OpAdxRewardedAdInteractionListenerImp(
onAdClicked: {
print("Rewarded ad clicked")
},
onAdDisplayed: {
print("Rewarded ad displayed")
},
onAdDismissed: { [weak self] in
print("Rewarded ad dismissed")
self?.rewardedAd = nil
self?.loadRewardedAd() // Preload next ad
},
onAdFailedToShow: { error in
print("Rewarded ad failed to show: \(error.message)")
},
onUserRewarded: { [weak self] reward in
print("User rewarded: \(reward.type) x \(reward.amount)")
self?.grantReward(reward)
}
)
// Show ad
rewardedAd.show(on: self, listener: interactionListener)
}
func grantReward(_ reward: OpAdxRewardItem) {
// Grant reward to user
let rewardType = reward.type // e.g., "coins"
let rewardAmount = reward.amount // e.g., 100
// Update user balance
UserDefaults.standard.set(
UserDefaults.standard.integer(forKey: "coins") + Int(rewardAmount),
forKey: "coins"
)
}
}5. App Open Ads
App Open ads are shown when users open or switch back to your app.
Swift Implementation
swift
import OpAdxSdk
class AppOpenAdManager: NSObject {
private var appOpenAd: OpAdxAppOpenAd?
private var isShowingAd = false
func loadAppOpenAd() {
appOpenAd = OpAdxAppOpenAd(
placementId: "s14496438551808",
auctionType: .regular
)
let loadListener = OpAdxAppOpenAdLoadListenerImp(
onAdLoaded: { [weak self] ad in
print("App open ad loaded")
self?.tryToShowAppOpenAd()
},
onAdFailedToLoad: { error in
print("App open ad failed to load: \(error.message)")
}
)
appOpenAd?.load(placementId: "s14496438551808", listener: loadListener)
}
func tryToShowAppOpenAd() {
guard let appOpenAd = appOpenAd,
!isShowingAd,
!appOpenAd.isAdInvalidated() else {
loadAppOpenAd() // Reload if needed
return
}
let interactionListener = OpAdxAppOpenAdInteractionListenerImp(
onAdClicked: { [weak self] in
print("App open ad clicked")
},
onAdDisplayed: { [weak self] in
self?.isShowingAd = true
print("App open ad displayed")
},
onAdDismissed: { [weak self] in
self?.isShowingAd = false
print("App open ad dismissed")
self?.appOpenAd = nil
self?.loadAppOpenAd() // Preload next ad
},
onAdFailedToShow: { error in
print("App open ad failed to show: \(error.message)")
}
)
if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
appOpenAd.show(on: rootVC, listener: interactionListener)
}
}
}
// Usage in AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var appOpenAdManager: AppOpenAdManager?
func applicationDidBecomeActive(_ application: UIApplication) {
appOpenAdManager?.tryToShowAppOpenAd()
}
}Advanced Features
Bidding Support
The Opera Ads SDK supports three bidding modes:
1. Waterfall (Regular)
Standard mediation waterfall based on CPM priorities.
swift
let ad = OpAdxInterstitialAd(placementId: "YOUR_PLACEMENT_ID", auctionType: .regular)2. Client-to-Server (C2S) Bidding
Also known as "In-App Bidding" or "Header Bidding".
swift
// Step 1: Get bid token
let request = BidTokenRequest.Builder(adMediation: .admob)
.placementId("YOUR_PLACEMENT_ID")
.adFormat(.interstitial)
.build()
OpAdxSDK.getBidToken(request) { callback in
callback.onSuccess(bidToken: { token in
print("Bid token: \(token)")
// Send token to your mediation platform
})
callback.onError(error: { error in
print("Failed to get bid token: \(error)")
})
}
// Step 2: Load ad with client bidding
let ad = OpAdxInterstitialAd(placementId: "YOUR_PLACEMENT_ID", auctionType: .clientBidding)3. Server-to-Server (S2S) Bidding
Bidding handled entirely on the server side.
swift
// Step 1: Get bid token (same as C2S)
// Step 2: Your server participates in the auction
// Step 3: Load ad with bid response
let ad = OpAdxInterstitialAd(placementId: "YOUR_PLACEMENT_ID", auctionType: .serverBidding)
ad.load(bidResponse: "BID_RESPONSE_FROM_SERVER", listener: listener)Audio Control
Control audio output for video ads:
swift
// Mute all video ads
OpAdxSDK.setMuted(true)
// Unmute all video ads
OpAdxSDK.setMuted(false)Important: Call setMuted() before loading ads. It affects all video ad formats.
Server-Side Verification (SSV)
For rewarded ads, configure SSV to prevent reward fraud:
swift
// Configure in your app
let ssvOptions = RewardSsvOptions.Builder()
.userId("user_12345") // Max 100 bytes after URL encoding
.customData("level=5&score=1000") // Max 1KB after URL encoding
.build()
rewardedAd.setRewardSsvOptions(ssvOptions)
// Configure callback URL in Opera Publisher Portal
// Your server will receive a callback when the user earns a rewardSSV Callback Parameters:
user_id: User identifier you providedcustom_data: Custom data you providedreward_type: Reward type (e.g., "coins")reward_amount: Reward amount (e.g., 100)transaction_id: Unique transaction IDsignature: HMAC-SHA256 signature for verification
Privacy & Compliance
COPPA Compliance
If your app is directed at children under 13 (or subject to COPPA):
swift
let config = OpAdxSdkInitConfig.Builder(applicationId: "YOUR_APP_ID")
.coppa(true) // Enable COPPA compliance
.build()COPPA Values:
true: Subject to COPPA (children under 13)false: Not subject to COPPAnil(default): Unspecified
CCPA / US Privacy
For California Consumer Privacy Act compliance:
swift
// Set US Privacy string (IAB USPrivacy format)
let config = OpAdxSdkInitConfig.Builder(applicationId: "YOUR_APP_ID")
.usPrivacy("1YNN") // Version 1, Notice given, Opt-out not given, LSPA not applicable
.build()US Privacy String Format (1YNN):
- Position 1: Version (always "1")
- Position 2: Notice given (Y/N/-)
- Position 3: Opt-out signal (Y/N/-)
- Position 4: LSPA covered (Y/N/-)
GDPR Compliance
The Opera Ads SDK (Vendor ID: 1135) is listed in the IAB Europe Transparency & Consent Framework (TCF) Global Vendor List.
The SDK automatically reads consent from the system preferences. No additional configuration is required if you're using a TCF-compliant consent management platform (CMP).
swift
// The SDK automatically checks for TCF consent strings
// stored in UserDefaults by your CMPTCF Keys Checked:
IABTCF_TCString: TCF consent stringIABTCF_gdprApplies: Whether GDPR appliesIABTCF_PurposeConsents: Purpose consents
Debug Logging
The Opera Ads SDK includes a comprehensive logging system for development and debugging, helping developers quickly identify and resolve integration issues.
Enable Debug Logs
Swift
swift
// Set log level (do this before SDK initialization)
OpAdxLogger.logLevel = .debug
// Available log levels:
// .none - No logs (recommended for production)
// .error - Errors only
// .warning - Warnings and errors
// .info - Info, warnings, and errors (default)
// .debug - Debug, info, warnings, and errors (recommended for development)
// .verbose - All logs including network request details (for detailed debugging)Objective-C
objective-c
// Set log level (do this before SDK initialization)
OpAdxLogger.logLevel = OpAdxLogLevelDebug;
// Available log levels:
// OpAdxLogLevelNone - No logs
// OpAdxLogLevelError - Errors only
// OpAdxLogLevelWarning - Warnings and errors
// OpAdxLogLevelInfo - Info, warnings, and errors
// OpAdxLogLevelDebug - Debug, info, warnings, and errors
// OpAdxLogLevelVerbose - All logs including network request detailsComplete Log Output Example
With .debug level enabled, you'll see logs throughout the ad lifecycle:
[11:23:45.123] ℹ️ [OpAdx-Init] 📱 Initializing Opera Ads SDK...
[11:23:45.124] ℹ️ [OpAdx-Init] Application ID: pub13423013211200/ep13423013211584/app14170937163904
[11:23:45.125] ℹ️ [OpAdx-Init] iOS App ID: 1444253128
[11:23:45.126] ℹ️ [OpAdx-Init] Use Test Ad: true
[11:23:45.200] ℹ️ [OpAdx-Init] ✅ SDK initialized successfully
[11:23:45.201] ℹ️ [OpAdx-Init] SDK Version: 2.9.0.20260325
[11:23:50.100] ℹ️ [OpAdx-Banner] 🎯 [Banner] Loading ad - Placement: s14170965187264, Size: 300x250
[11:23:50.101] ℹ️ [OpAdx-AdLoad] 🔄 Loading ad - Placement: s14170965187264, Auction: regular
[11:23:50.102] 🐛 [OpAdx-Network] Request ID: req_1234567890
[11:23:50.103] 🐛 [OpAdx-Network] Format: banner
[11:23:50.104] 🐛 [OpAdx-Network] Auction Type: regular
[11:23:51.200] 🐛 [OpAdx-Network] ✅ Network request succeeded - HTTP 200, Ads: 1
[11:23:51.201] ℹ️ [OpAdx-AdLoad] ✅ Ad loaded successfully - Placement: s14170965187264
[11:23:51.202] 🐛 [OpAdx-AdLoad] Ad Type: banner
[11:23:51.203] 🐛 [OpAdx-AdLoad] Creative ID: cr_9876543210
[11:23:51.204] 🐛 [OpAdx-AdLoad] eCPM: $0.0150
[11:23:51.205] ℹ️ [OpAdx-Banner] ✅ [Banner] Ad loaded successfully
[11:23:55.100] 🐛 [OpAdx-Banner] [Banner] renderAd: Render current banner ad
[11:23:55.500] ℹ️ [OpAdx-Banner] 👁️ Ad impression - Placement: s14170965187264
[11:24:00.100] ℹ️ [OpAdx-Banner] 👆 Ad clicked - Placement: s14170965187264Log Tag System
The SDK uses structured log tags to organize logs by component:
| Log Tag | Description | When It Appears |
|---|---|---|
OpAdx-Init | SDK initialization | During SDK startup |
OpAdx-AdLoad | Ad loading core flow | When loading any ad format |
OpAdx-Network | Network request details | During ad requests and responses |
OpAdx-Banner | Banner ads | Banner lifecycle events |
OpAdx-Interstitial | Interstitial ads | Interstitial lifecycle events |
OpAdx-Rewarded | Rewarded ads | Rewarded ad lifecycle events |
OpAdx-Native | Native ads | Native ad lifecycle events |
OpAdx-AppOpen | App open ads | App open ad lifecycle events |
OpAdx-SKAdNetwork | SKAdNetwork | App Store attribution events |
Error Log Example
When ad loading fails, you'll see detailed error information:
[11:25:00.100] ℹ️ [OpAdx-Banner] 🎯 [Banner] Loading ad - Placement: s14170965187264
[11:25:01.200] ❌ [OpAdx-AdLoad] Ad request failed - Code: 5, Message: NO_FILL
[11:25:01.201] 🐛 [OpAdx-AdLoad] HTTP Status Code: 204
[11:25:01.202] ❌ [OpAdx-Banner] Ad failed to load - Code: 5, Message: NO_FILLCustom Logging
You can also use OpAdxLogger for your own application logs:
swift
// Log custom messages
OpAdxLogger.info("User logged in successfully", tag: "MyApp")
OpAdxLogger.debug("Cache size: 25MB", tag: "MyApp")
OpAdxLogger.warning("Approaching storage limit", tag: "MyApp")
OpAdxLogger.logError("Failed to save file", tag: "MyApp")Production Environment Best Practices
Important Notes:
- ⚠️ Enable DEBUG or VERBOSE logs only in development and testing
- ✅ Use
.infoor.errorlevel in production - ✅ Set log level to
.noneor.errorbefore releasing
swift
#if DEBUG
OpAdxLogger.logLevel = .debug // Development
#else
OpAdxLogger.logLevel = .error // Production
#endifLog Filtering
In Xcode Console, use filtering to quickly locate issues:
- Filter SDK initialization: Search
OpAdx-Init - Filter ad loading: Search
OpAdx-AdLoad - Filter Banner ads: Search
OpAdx-Banner - Filter errors: Search
❌orERROR - Filter success events: Search
✅
Demo Configuration
Use the following test credentials during development:
Application Configuration
swift
let config = OpAdxSdkInitConfig.create(
applicationId: "pub13423013211200/ep13423013211584/app14170937163904",
iOSAppId: "1444253128"
)
config.useTestAd = trueTest Placement IDs
| Ad Format | Placement ID | Video Support |
|---|---|---|
| Native | s14198263063424 | No |
| Banner | s14170965187264 | No |
| Banner (Video) | s14198605602880 | Yes |
| Interstitial | s14198264979520 | No |
| Interstitial (Video) | s14198603681728 | Yes |
| Rewarded Video | s14198592226752 | Yes |
| Rewarded Interstitial | s14496445187904 | Yes |
| App Open | s14496438551808 | No |
Important Notes:
- Test ads will show "This is a test ad" watermark
- Set
useTestAd = falsebefore releasing to production - Replace placement IDs with your production IDs
- Never use test credentials in production builds
Error Codes
The SDK returns errors through the OpAdxAdError class.
Common Error Codes
| Code | Name | Description | Resolution |
|---|---|---|---|
| 1 | SDK_NOT_INITIALIZED | SDK not initialized before ad load | Call OpAdxSDK.initialize() first |
| 2 | INVALID_PLACEMENT_ID | Invalid or empty placement ID | Check placement ID format |
| 3 | NETWORK_ERROR | Network connection failed | Check internet connectivity |
| 4 | TIMEOUT | Ad request timed out | Retry after delay |
| 5 | NO_FILL | No ad available to show | Normal occurrence, try again later |
| 6 | AD_ALREADY_LOADED | Ad is already loaded | Don't call load() multiple times |
| 7 | AD_EXPIRED | Cached ad has expired | Load a fresh ad |
| 8 | INTERNAL_ERROR | Internal SDK error | Contact support with logs |
| 9 | INVALID_AD_RESPONSE | Malformed ad response | Contact support |
| 10 | AD_RENDERING_ERROR | Failed to render ad creative | Check device compatibility |
Error Handling Example
swift
let listener = OpAdxBannerAdListenerImp(
onAdLoaded: { bannerAdInfo in
print("Ad loaded successfully")
},
onAdFailedToLoad: { error in
print("Error Code: \(error.code)")
print("Error Message: \(error.message)")
switch error.code {
case 1:
// SDK not initialized
print("Please initialize SDK before loading ads")
case 5:
// No fill - normal occurrence
print("No ad available, will try again later")
case 3, 4:
// Network/timeout issues
print("Network issue, retrying in 30 seconds...")
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
self.loadBannerAd()
}
default:
print("Unexpected error occurred")
}
}
)Best Practices
Ad Loading
- Preload Ads: Load interstitial and rewarded ads in advance
- Check Validity: Always check
isAdInvalidated()before showing - Handle No Fill: Implement retry logic with exponential backoff
- Limit Frequency: Don't load ads too frequently (respect rate limits)
swift
func loadAdWithRetry(attempt: Int = 0) {
guard attempt < 3 else {
print("Max retry attempts reached")
return
}
// Exponential backoff: 1s, 2s, 4s
let delay = pow(2.0, Double(attempt))
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
self.loadAd()
}
}Memory Management
- Destroy Ads: Always call
destroy()when done with an ad - Weak References: Use
[weak self]in closures to avoid retain cycles - Lifecycle Management: Pause/resume banner ads in
viewWillDisappear/viewWillAppear
swift
// Destroy banner when view controller is deallocated
deinit {
bannerAdView?.destroy()
bannerAdView = nil
}
// Pause/resume banner ads
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
bannerAdView?.pause()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
bannerAdView?.resume()
}User Experience
- Natural Breaks: Show interstitials at natural transition points
- Clear Rewards: Clearly communicate rewards before showing rewarded ads
- Loading States: Show loading indicators while ads load
- Fallback Content: Have alternative content if no ad is available
swift
func showInterstitialAtNaturalBreak() {
// Good: After level completion
// Good: After user action (e.g., closing settings)
// Bad: Mid-gameplay
// Bad: During active user interaction
if interstitialAd != nil && !interstitialAd!.isAdInvalidated() {
showInterstitialAd()
} else {
// Fallback: Continue without ad
proceedToNextScreen()
}
}Performance
- Main Thread: All SDK APIs must be called on the main thread
- Background Loading: SDK handles network calls asynchronously
- Resource Cleanup: Remove ads from view hierarchy when destroyed
swift
// ✅ Correct: Call on main thread
DispatchQueue.main.async {
self.loadBannerAd()
}
// ❌ Wrong: Don't call on background thread
DispatchQueue.global().async {
self.loadBannerAd() // May cause crashes
}Troubleshooting
Issue: Ads Not Loading
Symptoms: onAdFailedToload called with NO_FILL error
Solutions:
- Check internet connectivity
- Verify placement ID is correct
- Ensure
useTestAd = trueduring development - Check if ad inventory is available for your region
- Review error logs for specific error codes
Issue: SDK Initialization Failed
Symptoms: SDK initialization callback returns error
Solutions:
- Verify Application ID format:
pub{}/ep{}/app{} - Check iOS App ID is a valid numeric string
- Ensure SDK is initialized before loading ads
- Check debug logs for specific error message
Issue: Ads Not Showing
Symptoms: Ad loads successfully but doesn't display
Solutions:
- Check if ad has expired:
isAdInvalidated() - Ensure view controller is presented (not nil)
- Verify ad view is added to view hierarchy
- Check Auto Layout constraints
- Ensure main thread is used for UI operations
Issue: Crash on Ad Load
Solutions:
- Ensure SDK is initialized before loading ads
- Check all APIs are called on main thread
- Verify placement ID format
- Update to latest SDK version
- Enable debug logging and check crash logs
Issue: Rewarded Ads Not Granting Rewards
Solutions:
- Check
onUserRewardedcallback is implemented - Verify SSV configuration (if using server-side verification)
- Ensure user watches ad completely
- Check reward logic implementation
- Review SSV callback logs on your server
Migration Guide
From v2.7.x to v2.8.x
Breaking Changes:
- None
New Features:
- Enhanced debug logging system
- Improved bidding support
- SKAdNetwork 4.0 support
Recommended Actions:
- Update pod version to
~> 2.9.0 - Enable new logging system during development
- Test all ad formats thoroughly
From v2.6.x to v2.7.x
Breaking Changes:
- Initialization callback signatures changed
Migration Steps:
swift
// Old (v2.6.x)
OpAdxSdkCore.shared.initialize(initConfig: config)
// New (v2.7.x+)
OpAdxSDK.initialize(
withConfig: config,
onSuccess: {
print("SDK initialized")
},
onError: { error in
print("Init failed: \(error)")
}
)Support & Resources
Documentation
- Integration Guide: [This Document]
- API Reference:
/docs/api-reference/ - Release Notes:
/docs/release-notes/
Sample Apps
- Swift Demo:
/OpAdxSdkDemo_Swift/ - Objective-C Demo:
/OpAdxSdkDemo_OC/
Mediation Adapters
- AdMob Adapter:
/Adapter/OpAdxAdapterAdmob/ - AppLovin Adapter:
/Adapter/OpAdxAdapterAppLovin/ - TopOn Adapter:
/Adapter/OpAdxAdapterTopon/
Contact
- Technical Support: [Contact Opera Ads Support]
- Publisher Portal: https://publisher.opera.com
- Bug Reports: [GitHub Issues]
Appendix
Minimum SDK Requirements
| Component | Minimum Version |
|---|---|
| iOS | 13.0 |
| Xcode | 14.0 |
| Swift | 5.0 |
| CocoaPods | 1.10.0 |
Third-Party Dependencies
| Library | Version | Purpose |
|---|---|---|
| Alamofire | ~> 5.6 | HTTP networking |
| GoogleUserMessagingPlatform | ~> 2.0 | GDPR consent |
| OMSDK_Opera | ~> 1.4 | Open Measurement |
SKAdNetwork Support
The SDK supports SKAdNetwork for ad attribution as a Source App. When ads are displayed, the SDK automatically handles startImpression / endImpression calls for attribution tracking.
1. Add SKAdNetwork ID to Info.plist (Required)
You must add Opera's SKAdNetworkIdentifier to your app's Info.plist. Without this, the system will silently ignore all attribution for Opera's ad network.
xml
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>a2p9lx4jpn.skadnetwork</string>
</dict>
</array>Note: If you are already using other ad networks, simply add Opera's identifier to your existing
SKAdNetworkItemsarray.
2. Enable SKAdNetwork in Code (Optional)
SKAdNetwork is enabled by default. You can configure it during initialization:
swift
// SKAdNetwork is enabled by default, disable if needed
OpAdxSDK.setSKAdNetworkEnabled(true)
// Enable debug logging for development
OpAdxSDK.setSKAdNetworkDebugLogEnabled(true)
// Register app for attribution (call once at app launch)
OpAdxSKAdNetworkManager.shared.registerApp()3. SKOverlay Configuration (Optional)
The SDK can display SKOverlay (in-app App Store overlay) for supported ads:
swift
// Enable/disable SKOverlay (default: true)
OpAdxSKAdNetworkManager.shared.useSKOverlay = true
// Display strategy: .auto (default), .onImpression, .onClick
OpAdxSKAdNetworkManager.shared.overlayDisplayStrategy = .auto- auto: Fullscreen ads (interstitial, rewarded, app open) show overlay on impression; non-fullscreen ads (banner, native) show on click
- onImpression: Always show overlay when ad is displayed
- onClick: Only show overlay when user clicks the ad
ProGuard / R8 Configuration
If using code obfuscation, add these rules:
-keep class com.opera.ads.** { *; }
-keep interface com.opera.ads.** { *; }
-keepattributes *Annotation*Document Version: 2.9.0 Last Updated: 2026-03-24 SDK Version: 2.9.0.20260324
