# Banner Ad

To receive Banner Ads, you need to conform to the `MediationAdDelegate` protocol. This protocol will notify you when the ad is successfully loaded or failed to load.

**Implementation:**

```swift
extension BannerAdManager: MediationAdDelegate {
    func onBannerAdLoaded(bannerAd: AdsFramework.MediationBannerAd) {
        guard let bannerview = bannerAd.view else {
            print("Banner Ad request failed with reason banner ad null")
            return
        }
        addBannerViewToView(bannerview)
        bannerAd.eventDelegate = self
    }
    
    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Banner Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Tracking Events:**

To track click and impression events for Banner Ads, conform to `MediationBannerAdEventDelegate`:

```swift
extension BannerAdManager: MediationBannerAdEventDelegate {
    func recordBannerClick() {
        print("Banner clicked")
    }
    
    func recordBannerImpression() {
        print("Banner impression recorded")
    }
}
```


# Interstitial Ad

To receive Interstitial Ads, you need to conform to the `MediationAdDelegate` protocol. Once the ad is loaded, it can be presented by calling `presentInterstitial(from:)`.

**Implementation:**

```swift
extension InterstitialAdManager: MediationAdDelegate {
    func onInterstitialAdLoaded(interstitialAd: AdsFramework.MediationInterstitialAd) {
        interstitialAd.presentInterstitial(from: self)
        interstitialAd.eventDelegate = self
    }
    
    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Interstitial Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Tracking Events:**

To track click, impression, and fullscreen events, conform to `MediationInterstitialAdEventDelegate`:

```swift
extension InterstitialAdManager: MediationInterstitialAdEventDelegate {
    func recordInterstitialClick() {
        print("Interstitial clicked")
    }
    
    func recordInterstitialImpression() {
        print("Interstitial impression recorded")
    }
    
    func ad(didFailToPresentFullScreenContentWithError error: AdsFramework.AdError) {
        print("Interstitial failed to present: \(error.description)")
    }
    
    func adWillPresentFullScreenContent() {
        print("Interstitial will present full screen content")
    }
    
    func adDidDismissFullScreenContent() {
        print("Interstitial dismissed full screen content")
    }
}
```


# Rewarded Ad

To receive Rewarded Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, it can be presented by calling `presentRewarded(from:)`.

**Implementation:**

```swift
extension RewardedAdManager: MediationAdDelegate {
    func onRewardedAdLoaded(rewardedAd: AdsFramework.MediationRewardedAd) {
        rewardedAd.presentRewarded(from: self)
        rewardedAd.eventDelegate = self
    }
    
    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Rewarded Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Tracking Events:**

To track rewarded video events, conform to `MediationRewardedAdEventDelegate`:

```swift
extension RewardedAdManager: MediationRewardedAdEventDelegate {
    func recordRewardedClick() {
        print("Rewarded ad clicked")
    }
    
    func recordRewardedImpression() {
        print("Rewarded ad impression recorded")
    }
    
    func didRewardUser(reward: AdsFramework.AdReward) {
        print("User rewarded: \(reward.amount) \(reward.type)")
    }
    
    func didStartVideo() {
        print("Rewarded video started")
    }
    
    func didEndVideo() {
        print("Rewarded video ended")
    }
}
```


# Rewarded-Interstitial Ad

To receive Rewarded Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, it can be presented by calling `presentRewardedInterstitial(from:)`.

**Implementation:**

```swift
extension RewardedInterstitialAdManager: MediationAdDelegate {
    func onRewardedInterstitialAdLoaded(rewardedInterstitialAd: any MediationRewardedInterstitialAd) {
        rewardedInterstitialAd.presentRewardedInterstitial(from: self)
        rewardedInterstitialAd.eventDelegate = self
    }

    func onAdFailedToLoad(error: AdError) {
        print("RewardedInterstitialAd Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Tracking Events:**

To track rewarded-interstitial video events, conform to `MediationRewardedInterstititalAdEventDelegate`:

```swift
extension RewardedInterstitialAdManager: MediationRewardedInterstitialAdEventDelegate {
    func recordRewardedInterstitialClick() {
        print("Rewarded interstitial clicked")
    }
    
    func recordRewardedInterstitialImpression() {
        print("Rewarded interstitial impression recorded")
    }
    
    func didRewardUser(reward: AdsFramework.AdReward) {
        print("User rewarded: \(reward.amount) \(reward.type)")
    }
}
```


# Native Ad

To receive Native Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, you can populate your custom native ad view with the ad's data.

**Implementation:**

```swift
extension NativeAdManager: MediationAdDelegate {
    func onNativeAdLoaded(nativeAd: AdsFramework.MediationNativeAd) {
        nativeAd.eventDelegate = self
        guard let nibObjects = Bundle.main.loadNibNamed("NativeView", owner: nil, options: nil),
              let adView = nibObjects.first as? MediationNativeAdView else {
            printLog("Could not load nib file for adView")
            return
        }
        (adView.bodyView as? UILabel)?.text = nativeAd.body
        (adView.headlineView as? UILabel)?.text = nativeAd.headline
        (adView.ctaView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
        (adView.ctaView as? UIButton)?.isUserInteractionEnabled = false
        if let mediaView = nativeAd.mediaView {
            addMediaViewToParentView(childView: mediaView, parentView: adView.mediaView)
        }
        
        adView.setNativeAd(nativeAd: nativeAd)
        viewBanner.addSubview(adView)
    }

    func onAdFailedToLoad(error: AdError) {
        print("Native Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Tracking Events:**

To track impression and click events for Native Ads, conform to `MediationNativeAdEventDelegate`:

```swift
extension NativeAdManager: MediationNativeAdEventDelegate {
    func recordNativeClick() {
        print("Native ad clicked")
    }
    
    func recordNativeImpression() {
        print("Native ad impression recorded")
    }
}
```


# Native Reward Ad

To receive Native Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, you can populate your custom native ad view with the ad's data.

**Implementation:**

```swift
extension NativeRewardAdManager: MediationAdDelegate {
    func onNativeRewardAdLoaded(nativeRewardAd: AdsFramework.MediationNativeRewardAd) {
        nativeRewardAd.eventDelegate = self

        guard let nibObjects = Bundle.main.loadNibNamed("NativeRewardView", owner: nil, options: nil),
              let adView = nibObjects.first as? MediationNativeRewardAdView else {
            printLog("Could not load nib file for adView")
            return
        }

        (adView.headlineView as? UILabel)?.text = nativeRewardAd.headline
        (adView.bodyView as? UILabel)?.text = nativeRewardAd.body
        (adView.ctaView as? UIButton)?.setTitle(nativeRewardAd.callToAction, for: .normal)
        (adView.ctaView as? UIButton)?.isUserInteractionEnabled = false

        if let mediaView = nativeRewardAd.mediaView {
            addMediaViewToParentView(childView: mediaView, parentView: adView.mediaView)
        }

        adView.setNativeRewardAd(nativeRewardAd: nativeRewardAd)
        viewBanner.addSubview(adView)
    }

    func onAdFailedToLoad(error: AdError) {
        print("Native Reward Ad request failed with reason \(error.description)")
    }
}
```

**Reward Metadata:**

Native Reward Ads expose reward metadata through `nativeRewardAd.reward`

Example:

```swift
if let reward = nativeRewardAd.reward {
    let couponCode = reward.coupon?.code
    let redemptionUrl = reward.coupon?.redemptionUrl
    let expiresAt = reward.coupon?.expiresAt
    let brandName = reward.brand?.displayName
    let brandLogo = reward.brand?.logoUrl
    let description = reward.description
    let terms = reward.tnc
    let instructions = reward.redemptionInstructions

    print("Coupon code: \(couponCode ?? "")")
}
```

**Tracking Events:**

To track impression and click events for Native Reward Ads, conform to `MediationNativeRewardAdEventDelegate`:

```swift
extension NativeRewardAdManager: MediationNativeRewardAdEventDelegate {
    func recordNativeRewardClick() {
        print("Native reward ad clicked")
    }

    func recordNativeRewardImpression() {
        print("Native reward ad impression recorded")
    }
}
```

**Manual Click and Impression Tracking:**

If you are not using `MediationNativeRewardAdView`, or if you set custom click/impression handling, call these methods manually:

```swift
nativeRewardAd.recordNativeRewardImpression()
nativeRewardAd.recordNativeRewardClick()
```

**Cleanup:**

Destroy the ad when it is no longer needed:

```swift
nativeRewardAd.destroy()
```


# Custom Native Ad

To receive Custom Native Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, you can populate your custom native ad view with the ad's data.

**Implementation:**

```swift
extension CustomNativeAdManager: MediationAdDelegate {
    func onCustomNativeAdLoaded(customNativeAd: AdsFramework.MediationNativeCustomFormatAd) {
        customNativeAd.eventDelegate = self
        if customNativeAd.getCustomFormatId() == "123456" {
            // Show native custom format for template ID 123456
            displayNativeCustomFormatAd(customNativeAd)
        } else if customNativeAd.getCustomFormatId() == "654321" {
            // Show native custom format for template ID 654321
            displayNativeCustomFormatAd(customNativeAd)
        } else {
            // Fallback for unknown custom native formats
            displayNativeCustomFormatAd(customNativeAd)
        }
    }

    func onAdFailedToLoad(error: AdError) {
        print("Custom Native Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Define your custom native ad layout:**

The below layout is an example UIKit view. You can create the same UI in a XIB, storyboard, or in code.

```swift
final class CustomNativeAdView: UIView {
    let mainImageView = UIImageView()
    let mediaContainerView = UIView()
    let titleLabel = UILabel()
    let bodyLabel = UILabel()
    let advertiserLabel = UILabel()
    
    let ctaButton = UIButton(type: .system)
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        mainImageView.contentMode = .scaleAspectFill
        mainImageView.clipsToBounds = true
        mainImageView.translatesAutoresizingMaskIntoConstraints = false

        mediaContainerView.translatesAutoresizingMaskIntoConstraints = false

        let textStack = UIStackView(arrangedSubviews: [
            titleLabel,
            bodyLabel,
            advertiserLabel,
            ctaButton
        ])
        textStack.axis = .vertical
        textStack.spacing = 8
        textStack.translatesAutoresizingMaskIntoConstraints = false

        let rootStack = UIStackView(arrangedSubviews: [
            mainImageView,
            mediaContainerView,
            textStack
        ])
        rootStack.axis = .vertical
        rootStack.spacing = 12
        rootStack.translatesAutoresizingMaskIntoConstraints = false

        addSubview(rootStack)

        NSLayoutConstraint.activate([
            rootStack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            rootStack.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            rootStack.topAnchor.constraint(equalTo: topAnchor, constant: 16),
            rootStack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),

            mainImageView.heightAnchor.constraint(equalToConstant: 180),
            mediaContainerView.heightAnchor.constraint(equalToConstant: 190)
        ])

        titleLabel.font = .boldSystemFont(ofSize: 18)
        bodyLabel.font = .systemFont(ofSize: 14)
        advertiserLabel.font = .systemFont(ofSize: 13)
        advertiserLabel.textColor = .secondaryLabel
    }
}
```

**Use the `MediationNativeCustomFormatAd` object to populate your custom native layout.:**

The asset names depend on your GAM custom native format. The example below uses common asset names such as `Headline`, `Body`, `Calltoaction`, and `Attribution`.

```swift
private func displayNativeCustomFormatAd(_ ad: AdsFramework.MediationNativeCustomFormatAd) {
    let adView = CustomNativeAdView()

    adView.titleLabel.text = ad.getText(for: "Headline")
    adView.bodyLabel.text = ad.getText(for: "Body")
    adView.advertiserLabel.text = ad.getText(for: "Attribution")
    adView.ctaButton.setTitle(ad.getText(for: "Calltoaction"), for: .normal)

    adView.ctaButton.addAction(UIAction { [weak ad] _ in
        ad?.performClick(on: "Calltoaction")
    }, for: .touchUpInside)

    // Add the custom native view to your container.
    // `adContainerView` is a UIView you have added to your view controller.
    adContainerView.addSubview(adView)
    adView.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activate([
        adView.leadingAnchor.constraint(equalTo: adContainerView.leadingAnchor),
        adView.trailingAnchor.constraint(equalTo: adContainerView.trailingAnchor),
        adView.topAnchor.constraint(equalTo: adContainerView.topAnchor),
        adView.bottomAnchor.constraint(equalTo: adContainerView.bottomAnchor)
    ])

    // Render image and media assets (GAM only)
    renderImageAndMediaAssets(for: ad, into: adView)

    // Record an impression when your custom native ad view is visible.
    ad.recordNativeImpression()
}
```

**Render image and media assets (GAM only):**

Image and `MediaContent` assets are exposed through the `MediationNativeCustomFormatAdGAM` protocol. To access them, import `GoogleMobileAds` and conditionally cast the loaded ad.

```swift
private func renderImageAndMediaAssets(
    for ad: AdsFramework.MediationNativeCustomFormatAd,
    into adView: CustomNativeAdView
) {
    guard let gamAd = ad as? any MediationNativeCustomFormatAdGAM else { return }

    // Image asset (asset names depend on your GAM custom native format,
    // e.g. "Image", "MainImage", "Icon", "Logo")
    if let nativeImage = gamAd.getImage(for: "MainImage") {
        if let uiImage = nativeImage.image {
            adView.mainImageView.image = uiImage
        } else if let url = nativeImage.imageURL {
            // Load remotely using your image loader, e.g. URLSession.
            URLSession.shared.dataTask(with: url) { data, _, _ in
                guard let data, let uiImage = UIImage(data: data) else { return }
                DispatchQueue.main.async {
                    adView.mainImageView.image = uiImage
                }
            }.resume()
        }
    }

    // Video / media content for GAM custom native videos.
    if let mediaContent = gamAd.getMediaContent(),
       mediaContent.hasVideoContent || mediaContent.mainImage != nil {
        let mediaView = MediaView()
        mediaView.contentMode = .scaleAspectFill
        mediaView.clipsToBounds = true
        mediaView.mediaContent = mediaContent
        mediaView.translatesAutoresizingMaskIntoConstraints = false

        adView.mediaContainerView.addSubview(mediaView)
        NSLayoutConstraint.activate([
            mediaView.leadingAnchor.constraint(equalTo: adView.mediaContainerView.leadingAnchor),
            mediaView.trailingAnchor.constraint(equalTo: adView.mediaContainerView.trailingAnchor),
            mediaView.topAnchor.constraint(equalTo: adView.mediaContainerView.topAnchor),
            mediaView.bottomAnchor.constraint(equalTo: adView.mediaContainerView.bottomAnchor)
        ])
    }
}
```

**Tracking Events:**

To track impression and click events for Native Ads, conform to `MediationNativeCustomAdEventDelegate`:

```swift
extension CustomNativeAdManager: MediationNativeCustomAdEventDelegate {
    func recordNativeCustomClick() {
        print("Custom Native ad clicked")
    }
    
    func recordNativeCustomImpression() {
        print("Custom Native ad impression recorded")
    }
    
    func recordNativeCustomClick(ad: AdsFramework.MediationNativeCustomFormatAd, assetName: String) {
        print("Custom native click on asset: \(assetName)")
    }
}
```

**Call `destroy()` when the view controller is deallocated or when the custom native ad is no longer needed.**

```swift
deinit {
    customNativeAd?.destroy()
}
```

{% hint style="info" %}
**If your custom native format can return different asset names, you can inspect the available assets dynamically:**

```swift
let assetNames = customNativeAd.getAvailableAssetNames() ?? []

for assetName in assetNames {
    if let text = customNativeAd.getText(for: assetName), !text.isEmpty {
        print("Text asset: \(assetName) = \(text)")
    }

    if let gamAd = customNativeAd as? any MediationNativeCustomFormatAdGAM,
       let image = gamAd.getImage(for: assetName) {
        print("Image asset: \(assetName), uiImage=\(String(describing: image.image)), url=\(String(describing: image.imageURL))")
    }
}
```

{% endhint %}


# Carousel Banner Ad

To receive multiple Banner Ads, you need to conform to the `MediationAdDelegate` protocol. This protocol will notify you when the ad is successfully loaded or failed to load.

**Implementation:**

```swift
extension BannerAdManager: MediationAdDelegate {
    func onCarouselBannerAdLoaded(carouselBannerAd: AdsFramework.MediationCarouselBannerAd) {
        guard !carouselBannerAd.ads.isEmpty else {
            print("Carousel Banner Ad request failed with reason no banner ads")
            return
        }

        addCarouselBannerToView(carouselBannerAd.ads)
    }
    
    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Banner Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Example carousel rendering:**

```swift
private func addCarouselBannerToView(_ bannerAds: [AdsFramework.MediationBannerAd]) {
    carouselStackView.arrangedSubviews.forEach { view in
        carouselStackView.removeArrangedSubview(view)
        view.removeFromSuperview()
    }

    for bannerAd in bannerAds {
        guard let bannerView = bannerAd.view else {
            continue
        }

        bannerAd.eventDelegate = self

        let slideView = UIView()
        slideView.translatesAutoresizingMaskIntoConstraints = false

        bannerView.translatesAutoresizingMaskIntoConstraints = false
        slideView.addSubview(bannerView)

        NSLayoutConstraint.activate([
            bannerView.centerXAnchor.constraint(equalTo: slideView.centerXAnchor),
            bannerView.centerYAnchor.constraint(equalTo: slideView.centerYAnchor),

            slideView.widthAnchor.constraint(equalTo: carouselScrollView.frameLayoutGuide.widthAnchor),
            slideView.heightAnchor.constraint(equalTo: carouselScrollView.frameLayoutGuide.heightAnchor)
        ])

        carouselStackView.addArrangedSubview(slideView)
    }

    pageControl.numberOfPages = bannerAds.count
    pageControl.currentPage = 0
}
```

**Tracking Events:**

To track click and impression events for Banner Ads, conform to `MediationBannerAdEventDelegate`:

```swift
extension BannerAdManager: MediationBannerAdEventDelegate {
    func recordBannerClick() {
        print("Banner clicked")
    }
    
    func recordBannerImpression() {
        print("Banner impression recorded")
    }
}
```

{% hint style="info" %}
Carousel Banner Ads return multiple banner ads in `carouselBannerAd.ads`. \
Each item is a `MediationBannerAd`, so add every banner ad's `view` to your carousel UI and assign `eventDelegate` for click and impression tracking.
{% endhint %}


# Carousel Native Ad

To receive multiple Native Ads, conform to the `MediationAdDelegate` protocol. Once the ad is loaded, you can populate your native ad view with the ad's data.

**Implementation:**

```swift
extension NativeAdManager: MediationAdDelegate {
    func onCarouselNativeAdLoaded(carouselNativeAd: AdsFramework.MediationCarouselNativeAd) {
        guard !carouselNativeAd.ads.isEmpty else {
            print("Carousel Native Ad request failed with reason no native ads")
            return
        }

        addCarouselNativeAdsToView(carouselNativeAd.ads)
    }

    func onAdFailedToLoad(error: AdError) {
        print("Native Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

**Example carousel rendering:**

```swift
private func addCarouselNativeAdsToView(_ nativeAds: [AdsFramework.MediationNativeAd]) {
    carouselStackView.arrangedSubviews.forEach { view in
        carouselStackView.removeArrangedSubview(view)
        view.removeFromSuperview()
    }

    for nativeAd in nativeAds {
        nativeAd.eventDelegate = self

        guard let nibObjects = Bundle.main.loadNibNamed("NativeView", owner: nil, options: nil),
              let adView = nibObjects.first as? MediationNativeAdView else {
            print("Could not load nib file for adView")
            continue
        }

        populateNativeAdView(adView, with: nativeAd)

        let slideView = UIView()
        slideView.translatesAutoresizingMaskIntoConstraints = false

        adView.translatesAutoresizingMaskIntoConstraints = false
        slideView.addSubview(adView)

        NSLayoutConstraint.activate([
            adView.leadingAnchor.constraint(equalTo: slideView.leadingAnchor),
            adView.trailingAnchor.constraint(equalTo: slideView.trailingAnchor),
            adView.topAnchor.constraint(equalTo: slideView.topAnchor),
            adView.bottomAnchor.constraint(equalTo: slideView.bottomAnchor),

            slideView.widthAnchor.constraint(equalTo: carouselScrollView.frameLayoutGuide.widthAnchor),
            slideView.heightAnchor.constraint(equalTo: carouselScrollView.frameLayoutGuide.heightAnchor)
        ])

        carouselStackView.addArrangedSubview(slideView)
    }

    pageControl.numberOfPages = nativeAds.count
    pageControl.currentPage = 0
}
```

**Helper method:**

```swift
private func populateNativeAdView(
    _ adView: MediationNativeAdView,
    with nativeAd: AdsFramework.MediationNativeAd
) {
    (adView.bodyView as? UILabel)?.text = nativeAd.body
    (adView.headlineView as? UILabel)?.text = nativeAd.headline
    (adView.ctaView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
    (adView.ctaView as? UIButton)?.isUserInteractionEnabled = false

    if let mediaView = nativeAd.mediaView {
        addMediaViewToParentView(childView: mediaView, parentView: adView.mediaView)
    }

    adView.setNativeAd(nativeAd: nativeAd)
}
```

**Tracking Events:**

To track impression and click events for Native Ads, conform to `MediationNativeAdEventDelegate`:

```swift
extension NativeAdManager: MediationNativeAdEventDelegate {
    func recordNativeClick() {
        print("Native ad clicked")
    }
    
    func recordNativeImpression() {
        print("Native ad impression recorded")
    }
}
```

{% hint style="info" %}
Carousel Native Ads return multiple native ads in `carouselNativeAd.ads`. \
Each item is a `MediationNativeAd`, so create one `MediationNativeAdView` for each ad, populate it with the ad data, call `setNativeAd(nativeAd:)`, and assign `eventDelegate` for click and impression tracking.
{% endhint %}


# Adaptive Banner Ad (Only for GAM)

Adaptive banners use the available width to request an optimally-sized banner for the device.

#### Ad Request : <a href="#a-d-request" id="a-d-request"></a>

Create your `AdSterAdLoader` and pass the adaptive parameters on the `AdRequestConfiguration` as shown below.

<details>

<summary>Anchored adaptive banner</summary>

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    adaptiveAdWidth: Int(UIScreen.main.bounds.width),
    adaptiveType: "Anchored"
))
```

</details>

<details>

<summary>Current orientation inline adaptive banner</summary>

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    adaptiveAdWidth: Int(UIScreen.main.bounds.width),
    adaptiveType: "CurrentOrientationInline"
))
```

</details>

<details>

<summary>Inline adaptive banner</summary>

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    adaptiveAdWidth: Int(UIScreen.main.bounds.width),
    adaptiveAdHeight: 300,
    adaptiveType: "Inline"
))
```

</details>

{% hint style="info" %}
`adaptiveType` accepts `"Anchored"`, `"Inline"`, and `"CurrentOrientationInline"` (case-insensitive). Any other value falls back to the placement's configured/fixed size.\
`adaptiveAdHeight` is only used by the `"Inline"` type and is ignored otherwise. \
Width is expressed in points — using the safe-area / screen width is recommended.
{% endhint %}

#### Receiving the ad :

Conform to the `MediationAdDelegate` protocol to be notified when the ad loads, then add the returned view to your layout.

```swift
extension BannerAdManager: MediationAdDelegate {
    func onBannerAdLoaded(bannerAd: AdsFramework.MediationBannerAd) {
        guard let bannerview = bannerAd.view else {
            print("Banner Ad request failed with reason banner ad null")
            return
        }
        addBannerViewToView(bannerview)
        bannerAd.eventDelegate = self
    }

    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Banner Ad request failed with reason \(error.description)")
    }

    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
    }
```


# Collapsible Anchored Adaptive Banner Ad (Only for GAM)

A collapsible banner initially renders at a larger size and can be collapsed to a smaller anchored banner (or vice-versa), giving a larger first impression without permanently occupying screen space.

#### Ad Request <a href="#a-d-request" id="a-d-request"></a>

Pass `collapsiblePlacement` on your `AdRequestConfiguration` alongside the adaptive parameters. Use `CollapsiblePlacement.top` or `CollapsiblePlacement.bottom` to indicate where the expanded banner should anchor.

#### Collapsible banner anchored to the bottom

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    adaptiveAdWidth: Int(UIScreen.main.bounds.width),
    adaptiveType: "Anchored",
    collapsiblePlacement: CollapsiblePlacement.bottom
))
```

#### Collapsible banner anchored to the top

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    adaptiveAdWidth: Int(UIScreen.main.bounds.width),
    adaptiveType: "Anchored",
    collapsiblePlacement: CollapsiblePlacement.top
))
```

{% hint style="info" %}
`collapsiblePlacement` accepts `CollapsiblePlacement.top` and `CollapsiblePlacement.bottom` (case-insensitive `"top"` / `"bottom"` strings are also accepted). Any other value is ignored and a standard banner is requested. Whether a collapsible creative is served is ultimately controlled by the ad network fill.
{% endhint %}

#### Receiving the ad

Handle the loaded ad through the `MediationAdDelegate` protocol exactly as with a standard banner ad — see [Banner Ad](https://ios-docs.adster.tech/ad-types/banner-ad).


# Render Unified Ad (Only for GAM)

Below are the steps to load and render a unified ad on your app

**Implementation:**

```swift
extension BannerAdManager: MediationAdDelegate {
    func onBannerAdLoaded(bannerAd: AdsFramework.MediationBannerAd) {
        //Show banner ad here
    }
    
    func onNativeAdLoaded(nativeAd: AdsFramework.MediationNativeAd) {
        //Show native ad here
    }
    
    func onCustomNativeAdLoaded(customNativeAd: AdsFramework.MediationNativeCustomFormatAd) {
        //show custom native ad here
    }
    
    func onAdFailedToLoad(error: AdsFramework.AdError) {
        print("Banner Ad request failed with reason \(error.description)")
    }
    
    func onAdRevenuePaid(revenue: Double, adUnitId: String, network: String, currency: String, precisionType: AdsFramework.PrecisionType) {
        print("Revenue: \(revenue) \(currency), adUnitId: \(adUnitId), network: \(network), precision: \(precisionType)")
        
    }
}
```

{% hint style="info" %}
`onNativeAdLoaded()` - [Click here](https://docs.adster.tech/how-to-render-an-ad/native-ad#kotlin) for Rendering implementation \
`onBannerAdLoaded()` - [Click here](https://docs.adster.tech/how-to-render-an-ad/banner-ad) for Rendering implementation\
`onCustomNativeAdLoaded()` - [Click here](https://docs.adster.tech/how-to-render-an-ad/native-ad-2) for Rendering implementation
{% endhint %}


# How to pass predefined custom targeting values in ad request

Below are the steps to pass predefined custom targeting value in ad request (Supported by all ad formats)

Create your `AdSterAdLoader` as per the below format

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    customTargetingValues: ["test": "123"]
))
```

<details>

<summary>Single key with single value</summary>

```swift
customTargetingValues: ["test": "123"]
```

</details>

<details>

<summary>Single key with multiple values</summary>

```swift
customTargetingValues: [
    "city": ["BANGALORE", "PUNE", "MUMBAI"]
]
```

</details>

<details>

<summary>Multiple keys with single value</summary>

```swift
customTargetingValues: [
    "test1": "123",
    "test2": "324"
]
```

</details>

<details>

<summary>Multiple keys with multiple values</summary>

```swift
customTargetingValues: [
    "city": ["BANGALORE", "PUNE", "MUMBAI"],
    "country": ["INDIA", "BHUTAN"]
]
```

</details>


# How to pass publisher provided identifiers in ad request (PPID)

Below are the steps to pass PPID in ad loader (Supported by all ad formats)

Create your `AdSterAdLoader` as per the below format

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "placement_name",
    viewController: self,
    publisherProvidedId: "Test",
))
```


# Troubleshooting

Here are some common issues and their solutions:

| Issue                    | Solution                                                                                   |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| SDK initialization fails | Check your internet connection and ensure you have the correct API keys                    |
| Ads not loading          | Verify that your placement IDs are correct and that your app has the necessary permissions |
| Poor ad fill rate        | Consider adjusting your targeting parameters or try different ad formats                   |

### Best Practices

* Initialize the SDK as early as possible in your app's lifecycle
* Cache ads in advance for a smoother user experience
* Implement multiple ad formats to maximize revenue
* Test ads in development mode before releasing your app
* Monitor ad performance regularly and make adjustments as needed


# Test Placements

Sample test ad units by Adster to ensure Ads are coming and is displayed in app by the developers.

Banner (320x50) - <mark style="color:$success;">**`banner_320x50`**</mark>

Banner (300x250) - <mark style="color:$success;">**`banner_300x250`**</mark>&#x20;

Adaptive Banner - <mark style="color:$success;">**`banner_adaptive`**</mark>

Native - <mark style="color:$success;">**`native`**</mark>

Interstitial - <mark style="color:$success;">**`interstitial`**</mark>&#x20;

Appopen - <mark style="color:$success;">**`appopen`**</mark>

Rewarded - <mark style="color:$success;">**`rewarded`**</mark>

Rewarded - <mark style="color:$success;">**`rewarded_interstitial`**</mark>&#x20;

Unified - <mark style="color:$success;">**`unified`**</mark>

Placement code snippet 👇

```swift
let loader = AdSterAdLoader()
loader.delegate = self
loader.loadAd(adRequestConfiguration: AdRequestConfiguration(
    placement: "banner_300x250",
    viewController: self,
    publisherProvidedId: "Test",
    customTargetingValues: ["test": "123"]
))
```


# Integrate Ads & APP Ads For Easy Management

We have built a easy to use UI for adding / updating ads.txt from UI for product & Adops teams. Its a one time integration where domain/ads.txt and domain/app-ads.txt needs to be linked to our URL. Everytime when a new entry is added we publish the same in our URL and hence website needs to pick from this published url of adster once a day or once in 2-3 days.

Product / Ops: From app.adster.tech, navigate to "Managed Ads TXT" section, add your domain name like "<https://adster.tech>" and we will fetch the existing file. And then you can make the entries, and save the same to generate a URL. E.g. URL: <https://storage.googleapis.com/public-assets-adstxtmanage/Citymall> main website-app-ads.txt from where ads.txt needs to be read and updated in the domain


