Ad feed

Ad feeds are units that consist of a sequence of ads. Feeds can be added to your app as its main content, or they may come after the existing content. Feeds may contain dozens of ads, which are loaded sequentially (several ads are loaded at once).

This guide shows how to integrate the ad feed into an iOS app. In addition to code examples and instructions, it includes format recommendations and links to additional resources.

Appearance

Prerequisite

  1. Follow the SDK integration steps described in Quick start.
  2. Initialize your ad SDK in advance.
  3. Make sure you're running the latest Yandex Mobile Ads SDK version. If you're using mediation, make sure you're also running the latest version of the unified build.

Implementation

Main steps to integrate the ad feed:

  1. Configure the ad feed appearance using a FeedAdAppearance object.
  2. Create a FeedAd object, set its delegate, and implement the required FeedAdDelegate methods.
  3. Load the ad.
  4. Create a FeedAdCollectionViewAdapter and connect it to a UICollectionView.

Ad feed integration specifics

  • All Yandex Mobile Ads SDK API calls must be made on the main thread.
  • Keep a strong reference to the FeedAd and FeedAdCollectionViewAdapter objects for the full lifetime of the screen where the user interacts with ads.

Appearance configuration

Create a FeedAdAppearance object to configure the ad feed UI.

The following parameters are available:

  • cardWidth (required): width of the ad card in points. Calculate it from the screen width minus horizontal margins.
  • cardCornerRadius: corner radius of the ad card in points.
let feedMargin: CGFloat = 24
let cardWidth = view.bounds.width - 2 * feedMargin
let appearance = FeedAdAppearance(cardWidth: cardWidth, cardCornerRadius: 16)

Loading ads

Create a FeedAd using the ad placement ID (adUnitId) from the Yandex Advertising Network interface.

You can extend the ad request with an AdRequest by passing user interests, page context, location, or other data. Extra context can improve ad quality. Read more in Ad targeting.

Set a delegate and implement FeedAdDelegate to receive load and ad lifecycle events:

final class FeedAdViewController: UIViewController {
    private var feedAd: FeedAd?

    func loadAd() {
        let request = AdRequest(adUnitID: "R-M-XXXXXX-Y")
        let appearance = FeedAdAppearance(cardWidth: view.bounds.width)
        let feedAd = FeedAd(requestConfiguration: request, appearance: appearance)
        feedAd.delegate = self
        self.feedAd = feedAd
        feedAd.loadAd()
    }
}

extension FeedAdViewController: FeedAdDelegate {
    func feedAdDidLoad(_ feedAd: FeedAd) {
        // Called when an ad is successfully loaded
    }

    func feedAd(_ feedAd: FeedAd, didFailToLoadWithError error: Error) {
        // Called when ad loading fails
    }

    func feedAdDidClick(_ feedAd: FeedAd) {
        // Called when the user taps the ad
    }

    func feedAd(_ feedAd: FeedAd, didTrackImpression impressionData: ImpressionData?) {
        // Called when an impression is tracked
    }

    func feedAdDidUpdateDataSource(_ feedAd: FeedAd) {
        // Called when new ads are available — reload collection view
        collectionView.reloadData()
    }
}

Displaying the ad feed

Use FeedAdCollectionViewAdapter to provide a dataSource and delegate for a UICollectionView.

Register cell types with registerCells(in:) before you set the collection view’s dataSource and delegate.

As the main list

Set the adapter’s dataSource and delegate directly on the UICollectionView:

final class FeedAdViewController: UIViewController {
    private let collectionView = UICollectionView(
        frame: .zero,
        collectionViewLayout: UICollectionViewFlowLayout()
    )
    private var feedAdAdapter: FeedAdCollectionViewAdapter?

    func setupAdapter() {
        guard let feedAd else { return }
        let adapter = FeedAdCollectionViewAdapter(feedAd: feedAd)
        adapter.registerCells(in: collectionView)
        collectionView.dataSource = adapter.dataSource
        collectionView.delegate = adapter.delegate
        feedAdAdapter = adapter
    }
}

Alongside existing content

To show the ad feed together with your own content, implement UICollectionViewDataSource yourself and delegate the feed section to the adapter:

final class FeedAdViewController: UIViewController {
    private enum Section: Int, CaseIterable {
        case content
        case feed
    }

    private var contentItems: [ContentItem] = []
    private var feedAdAdapter: FeedAdCollectionViewAdapter?

    func setupAdapter() {
        guard let feedAd else { return }
        let adapter = FeedAdCollectionViewAdapter(feedAd: feedAd)
        adapter.registerCells(in: collectionView)
        feedAdAdapter = adapter

        collectionView.dataSource = self
        collectionView.delegate = self
    }
}

extension FeedAdViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        Section.allCases.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch Section(rawValue: section) {
        case .content:
            return contentItems.count
        case .feed:
            return feedAdAdapter?.dataSource.collectionView(collectionView, numberOfItemsInSection: section) ?? 0
        case .none:
            return 0
        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        switch Section(rawValue: indexPath.section) {
        case .content:
            // Return your content cell
            return dequeueContentCell(for: indexPath)
        case .feed:
            return feedAdAdapter?.dataSource.collectionView(collectionView, cellForItemAt: indexPath)
                ?? UICollectionViewCell()
        case .none:
            return UICollectionViewCell()
        }
    }
}

extension FeedAdViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAt indexPath: IndexPath
    ) -> CGSize {
        switch Section(rawValue: indexPath.section) {
        case .feed:
            return feedAdAdapter?.delegate.collectionView?(
                collectionView,
                layout: collectionViewLayout,
                sizeForItemAt: indexPath
            ) ?? .zero
        default:
            return CGSize(width: collectionView.bounds.width, height: 80)
        }
    }
}

Testing ad feed integration

Using demo ad units for ad testing

Use test ads to verify your ad feed integration and test your app.

To make sure that test ads are returned for every ad request, we provide a special demo ad placement ID. Use it to verify that your ad integration is correct.

Demo ad placement ID: demo-feed-yandex.

Warning

Before publishing your app in the store, make sure to replace the demo ad placement ID with a real one from the Yandex Advertising Network interface.

The full list of demo ad placement IDs is available in Demo ad units for testing.

Verifying the ad integration

You can test your ad integration using the native Console tool.

To view detailed logs, call the YMAMobileAds class's enableLogging method.

YMAMobileAds.enableLogging()

To view SDK logs, go to the Console tool and set Subsystem = com.mobile.ads.ads.sdk. You can also filter logs by category and error level.

If you're having problems integrating ads, you'll get a detailed report on the issues and recommendations for how to fix them.

Additional resources