Skip to content

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

Add the following to your Podfile:

ruby
platform :ios, '13.0'

target 'YourApp' do
  use_frameworks!

  # Opera Ads SDK
  pod 'OpAdxSdk', '~> 2.9.0'
end

Then run:

bash
pod install

Method 2: Manual Integration

  1. Download the latest OpAdxSdk.xcframework from the releases page
  2. Drag the framework into your Xcode project
  3. In General > Frameworks, Libraries, and Embedded Content, select Embed & Sign
  4. 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;
}

@end

Initialization Parameters

ParameterTypeRequiredDescription
applicationIdStringYesYour application ID (format: pub{}/ep{}/app{})
iOSAppIdStringYesiTunes App ID (numeric string)
publisherNameStringNoPublisher name for reporting
useTestAdBooleanNoEnable test ads (default: false)
coppaBooleanNoCOPPA compliance flag
usPrivacyStringNoCCPA/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");
}

@end

Native Ad Components

The SDK provides access to the following native ad assets:

AssetTypeDescription
title()StringAd headline (required)
body()StringAd description text
callToAction()StringCTA button text (e.g., "Install")
iconUrl()StringSquare icon image URL
mainImageUrl()StringMain creative image URL
rating()DoubleApp rating (0-5)
advertiser()StringAdvertiser name
mediaViewUIViewVideo/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 ConstantDimensionsDescription
BANNER320x50Standard banner
BANNER_LARGE320x100Large banner
BANNER_MREC300x250Medium rectangle
BANNER_LEADERBOARD728x90Leaderboard (iPad)
BANNER_SMARTScreen width x autoSmart 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 reward

SSV Callback Parameters:

  • user_id: User identifier you provided
  • custom_data: Custom data you provided
  • reward_type: Reward type (e.g., "coins")
  • reward_amount: Reward amount (e.g., 100)
  • transaction_id: Unique transaction ID
  • signature: 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 COPPA
  • nil (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 CMP

TCF Keys Checked:

  • IABTCF_TCString: TCF consent string
  • IABTCF_gdprApplies: Whether GDPR applies
  • IABTCF_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 details

Complete 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: s14170965187264

Log Tag System

The SDK uses structured log tags to organize logs by component:

Log TagDescriptionWhen It Appears
OpAdx-InitSDK initializationDuring SDK startup
OpAdx-AdLoadAd loading core flowWhen loading any ad format
OpAdx-NetworkNetwork request detailsDuring ad requests and responses
OpAdx-BannerBanner adsBanner lifecycle events
OpAdx-InterstitialInterstitial adsInterstitial lifecycle events
OpAdx-RewardedRewarded adsRewarded ad lifecycle events
OpAdx-NativeNative adsNative ad lifecycle events
OpAdx-AppOpenApp open adsApp open ad lifecycle events
OpAdx-SKAdNetworkSKAdNetworkApp 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_FILL

Custom 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 .info or .error level in production
  • Set log level to .none or .error before releasing
swift
#if DEBUG
    OpAdxLogger.logLevel = .debug  // Development
#else
    OpAdxLogger.logLevel = .error  // Production
#endif

Log 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 or ERROR
  • 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 = true

Test Placement IDs

Ad FormatPlacement IDVideo Support
Natives14198263063424No
Banners14170965187264No
Banner (Video)s14198605602880Yes
Interstitials14198264979520No
Interstitial (Video)s14198603681728Yes
Rewarded Videos14198592226752Yes
Rewarded Interstitials14496445187904Yes
App Opens14496438551808No

Important Notes:

  • Test ads will show "This is a test ad" watermark
  • Set useTestAd = false before 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

CodeNameDescriptionResolution
1SDK_NOT_INITIALIZEDSDK not initialized before ad loadCall OpAdxSDK.initialize() first
2INVALID_PLACEMENT_IDInvalid or empty placement IDCheck placement ID format
3NETWORK_ERRORNetwork connection failedCheck internet connectivity
4TIMEOUTAd request timed outRetry after delay
5NO_FILLNo ad available to showNormal occurrence, try again later
6AD_ALREADY_LOADEDAd is already loadedDon't call load() multiple times
7AD_EXPIREDCached ad has expiredLoad a fresh ad
8INTERNAL_ERRORInternal SDK errorContact support with logs
9INVALID_AD_RESPONSEMalformed ad responseContact support
10AD_RENDERING_ERRORFailed to render ad creativeCheck 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

  1. Preload Ads: Load interstitial and rewarded ads in advance
  2. Check Validity: Always check isAdInvalidated() before showing
  3. Handle No Fill: Implement retry logic with exponential backoff
  4. 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

  1. Destroy Ads: Always call destroy() when done with an ad
  2. Weak References: Use [weak self] in closures to avoid retain cycles
  3. 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

  1. Natural Breaks: Show interstitials at natural transition points
  2. Clear Rewards: Clearly communicate rewards before showing rewarded ads
  3. Loading States: Show loading indicators while ads load
  4. 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

  1. Main Thread: All SDK APIs must be called on the main thread
  2. Background Loading: SDK handles network calls asynchronously
  3. 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:

  1. Check internet connectivity
  2. Verify placement ID is correct
  3. Ensure useTestAd = true during development
  4. Check if ad inventory is available for your region
  5. Review error logs for specific error codes

Issue: SDK Initialization Failed

Symptoms: SDK initialization callback returns error

Solutions:

  1. Verify Application ID format: pub{}/ep{}/app{}
  2. Check iOS App ID is a valid numeric string
  3. Ensure SDK is initialized before loading ads
  4. Check debug logs for specific error message

Issue: Ads Not Showing

Symptoms: Ad loads successfully but doesn't display

Solutions:

  1. Check if ad has expired: isAdInvalidated()
  2. Ensure view controller is presented (not nil)
  3. Verify ad view is added to view hierarchy
  4. Check Auto Layout constraints
  5. Ensure main thread is used for UI operations

Issue: Crash on Ad Load

Solutions:

  1. Ensure SDK is initialized before loading ads
  2. Check all APIs are called on main thread
  3. Verify placement ID format
  4. Update to latest SDK version
  5. Enable debug logging and check crash logs

Issue: Rewarded Ads Not Granting Rewards

Solutions:

  1. Check onUserRewarded callback is implemented
  2. Verify SSV configuration (if using server-side verification)
  3. Ensure user watches ad completely
  4. Check reward logic implementation
  5. 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:

  1. Update pod version to ~> 2.9.0
  2. Enable new logging system during development
  3. 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


Appendix

Minimum SDK Requirements

ComponentMinimum Version
iOS13.0
Xcode14.0
Swift5.0
CocoaPods1.10.0

Third-Party Dependencies

LibraryVersionPurpose
Alamofire~> 5.6HTTP networking
GoogleUserMessagingPlatform~> 2.0GDPR consent
OMSDK_Opera~> 1.4Open 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 SKAdNetworkItems array.

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