# Add IAB Standard Size Experiences to an iOS app

Show IAB banner, medium rectangle, half-page, interstitial, and collapsible ads in an iOS app with the IAB Standard Size Experience SDK 0.0.6. You can also serve ads from Pangle, Meta, and Google Ad Manager by adding their optional modules.

You add a Swift package, initialize it with your brand's API key, and place a SwiftUI view that carries a **tag ID**. The tag identifies an ad placement set up in your Business Account, so campaigns and creatives change without an app update.

## What you'll add

| Product | Import | Use it for |
| --- | --- | --- |
| GenuinSDK | import GenuinSDK | Initializing the SDK (required) |
| GenuinInStreamAds | import GenuinInStreamAds | The six ad views (required) |
| GenuinPangleAds | import GenuinPangleAds | Pangle ads (optional) |
| GenuinMetaAds | import GenuinMetaAds | Meta Audience Network ads (optional) |
| GenuinGMAAds | import GenuinGMAAds | Google Ad Manager ads (optional) |

## Requirements

| | Minimum |
| --- | --- |
| iOS | 16.0 |
| Xcode | 26 or later |
| Devices | iPhone and iPad |
| Package manager | Swift Package Manager |
| UI | SwiftUI. UIKit apps host the views in a UIHostingController. |
| Platforms | iOS only |

You also need an API key and a tag ID from your Genuin account. See [Step 5](#step-5-get-your-credentials).

## Step 1: Add the Genuin package

1. In Xcode, go to **File** > **Add Package Dependencies**.
2. Enter the repository URL `https://github.com/genuininc/ios_sdk`.
3. Set **Dependency Rule** to **Exact Version** and enter `0.0.6`, the latest release.
4. Click **Add Package**.
5. Select `GenuinSDK` and `GenuinInStreamAds`, plus the product for each ad network you want: `GenuinPangleAds`, `GenuinMetaAds`, or `GenuinGMAAds`. Assign them to your app target and click **Add Package**.

## Step 2: Add the Google IMA package

`GenuinInStreamAds` needs Google's Interactive Media Ads (IMA) package, which a binary Swift package can't add for you. Without it the app crashes at launch with `Library not loaded: @rpath/GoogleInteractiveMediaAds.framework`.

1. Go to **File** > **Add Package Dependencies** again.
2. Enter `https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios`.
3. Set **Dependency Rule** to **Branch** and enter `main`.
4. Add the `GoogleInteractiveMediaAds` product to your app target.

Don't add the Google Mobile Ads package yourself. If you use Google Ad Manager ads, GenuinGMAAds already includes it.

## Step 3: Add ad networks (optional)

Skip this step if you only need Genuin ads. Each ad network is a separate, optional module, so apps that don't use it don't carry it. Choose a network to see how to add it:

- [Pangle](https://begenuin.com/developers/developer-resources/sdk/add-pangle-ads-to-an-ios-app): banner and native ads.
- [Meta Audience Network](https://begenuin.com/developers/developer-resources/sdk/add-meta-audience-network-ads-to-an-ios-app): native video, image, and carousel ads.
- [Google Ad Manager](https://begenuin.com/developers/developer-resources/sdk/add-google-ad-manager-ads-to-an-ios-app): banner and native ads.

Each network's page covers its package, its Info.plist keys, and the module to pass in [Step 6](#step-6-initialize-the-sdk). Ask your Genuin team to enable a network for your tag IDs.

## Step 4: Configure Info.plist and tracking

The SDK reads the App Tracking Transparency (ATT) status for ad measurement, but it never shows the ATT prompt. Add the usage description and request authorization yourself, before the first ad view appears:

```xml title="Info.plist"
<key>NSUserTrackingUsageDescription</key>
<string>We use your data to show you more relevant ads.</string>
```

```swift title="Tracking prompt"
import AppTrackingTransparency

ATTrackingManager.requestTrackingAuthorization { _ in }
```

Without authorization, ads still serve but aren't personalized. Ad assets load over HTTPS, so App Transport Security needs no changes.

## Step 5: Get your credentials

| Credential | Purpose | Where to get it |
| --- | --- | --- |
| API key | Authenticates your app. Passed once to initialize. | Business Account > Build > Publish Brand Community > SDK Integration. The Live and QA environments each have their own key. |
| Tag ID | Identifies one ad slot and its campaigns. Passed to each ad view. | The ID of an IAB Standard Tag created in your Business Account under Grow > Off Site > Extended > IAB Standard Tag. Your Genuin team passes it to you. |

Keep the API key out of source control, for example in an `.xcconfig` file or your CI secrets.

## Step 6: Initialize the SDK

Call `Genuin.shared.initialize` once at launch and pass every module you use. Adding a product isn't enough: a module you don't pass isn't registered, and its ads are skipped silently. Without `BGInStreamAds.module`, every ad view fails with `BGTagError.adsManagerUnavailable`.

```swift title="MyApp.swift"
import SwiftUI
import GenuinSDK
import GenuinInStreamAds
// Also import GenuinPangleAds, GenuinMetaAds, or GenuinGMAAds for each ad network you use

@main
struct MyApp: App {
    init() {
        Genuin.shared.initialize(
            modules: [
                BGInStreamAds.module
                // Add BGPangleAds.module, BGMetaAds.module, or BGGMAAds.module for each ad network you use
            ],
            apiKey: "<<YOUR_API_KEY>>"
        ) { result in
            if case .failure(let error) = result { print("Genuin init failed: \(error)") }
        }
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
```

In a UIKit app, make the same call in `application(_:didFinishLaunchingWithOptions:)`.

### Initialization parameters

| Parameter | Required | Description |
| --- | --- | --- |
| modules | Yes | The modules to register: BGInStreamAds.module, plus the module of each ad network you use (BGPangleAds.module, BGMetaAds.module, or BGGMAAds.module). |
| apiKey | Yes | Your brand's API key for the environment. |
| config | No | environment is .prod (default) or .qa. navigationStyle is .system (default), .custom, or .hidden. |
| completion | No | Called once initialization succeeds or fails. |

> **Note** A QA key only works with environment: .qa. Don't ship a build that points at QA; the two environments have separate brands, tags, and campaigns.

## Step 7: Display an ad

Each ad view is a SwiftUI view. Wrap it in `BGNavigationRoot` and pass the tag ID:

```swift title="AdView.swift"
import SwiftUI
import GenuinInStreamAds
import Core

struct ContentView: View {
    var body: some View {
        BGNavigationRoot {
            BG320x50AdView(tagID: "{{TAG_ID}}")
        }
        .padding()
    }
}
```

The view loads as soon as it appears and sets its own height. Give it at least the slot's width: 320 points for the banners and interstitial, 300 points for the medium rectangle and half page. You don't set a frame.

| Ad view | Size (points) | Description |
| --- | --- | --- |
| BG320x50AdView | 320 × 50 | Compact single-row banner |
| BG320x100AdView | 320 × 100 | Large banner |
| BG300x250AdView | 300 × 250 | Medium rectangle |
| BGCollapsibleAdView | 300 × 250, collapsing to a row | Collapses after playback or when the user taps the chevron |
| BG320x480AdView | 320 × 480 | Mobile interstitial |
| BG300x600AdView | 300 × 600 | Half page |

All six take a `tagID` and an optional `delegate`.

### Host an ad view in UIKit

Wrap the view in a `UIHostingController` and add it as a child:

```swift title="UIKit host"
let hosting = UIHostingController(rootView: BGNavigationRoot { BG300x250AdView(tagID: "{{TAG_ID}}") })
addChild(hosting)
hosting.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hosting.view)
NSLayoutConstraint.activate([
    hosting.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    hosting.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    hosting.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
])
hosting.didMove(toParent: self)
```

## Step 8: Observe lifecycle events

Pass an object that conforms to `BGAdDelegate` to react to loading, playback, and taps. Every method is optional. Keep a strong reference to the object, because the view doesn't own its delegate.

```swift title="AdTracker.swift"
import GenuinInStreamAds
import _FeedCore

final class AdTracker: BGAdDelegate {
    func iabAdUnitDidLoad(_ unit: BGAdUnitInfo, mediaCount: Int) {
        print("Loaded \(mediaCount) item(s)")
    }
    func iabAdUnitDidReceiveNoAds(_ unit: BGAdUnitInfo) { /* hide or resize the slot */ }
    func iabAdUnitDidFailToLoad(_ unit: BGAdUnitInfo, error: any Error) { print("Ad failed: \(error)") }
    func iabAdCTATapped(_ mediaItem: BGMediaInfo, url: URL) { print("CTA tapped: \(url)") }
}
```

```swift title="ContentView.swift"
struct ContentView: View {
    @State private var tracker = AdTracker()

    var body: some View {
        BGNavigationRoot {
            BG300x250AdView(tagID: "{{TAG_ID}}", delegate: tracker)
        }
    }
}
```

| Method | Fires when |
| --- | --- |
| iabAdUnitDidLoad(_:mediaCount:) | The unit has ads to show |
| iabAdUnitDidReceiveNoAds(_:) | The unit resolved but has no ads |
| iabAdUnitDidFailToLoad(_:error:) | Loading failed. The error is a BGTagError for tag problems. |
| iabAdMediaDidStart(_:) | An ad started playing |
| iabAdAllMediaDidComplete(_:) | The unit played through once |
| iabAdCTATapped(_:url:) | The user tapped the call to action |
| iabAdDidEnterFullscreen(_:), iabAdDidExitFullscreen(_:) | Full-screen playback opened or closed |
| iabAdDidCollapse(_:reason:), iabAdDidExpand(_:) | A collapsible unit collapsed or expanded |

`BGAdDelegate` has more callbacks than these. When a unit fails or has no ads, it keeps its size and shows a placeholder; to reclaim the space, hide the slot from `iabAdUnitDidReceiveNoAds` or `iabAdUnitDidFailToLoad`.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| The app crashes at launch with Library not loaded: @rpath/GoogleInteractiveMediaAds.framework | The Google IMA package isn't linked to the app target | Complete Step 2. |
| Every slot shows the placeholder and reports .adsManagerUnavailable | initialize was called without BGInStreamAds.module, or after the first ad view appeared | Pass the module and initialize at launch. |
| No ad network ads appear | The network's module isn't passed to initialize, the network isn't enabled for your tag, or its setup is incomplete | Follow the network's page (Step 3), check each step, and ask your Genuin team to enable the network for your tag IDs. |
| .invalidTagID | The tag ID is empty or malformed | Pass the tag ID exactly as your Genuin team provided it. |
| iabAdUnitDidReceiveNoAds fires for a valid tag | The tag has no active campaign, or the key belongs to the other environment | Check the tag in your Business Account and match the environment to the key. |
| Build error: no such module GenuinSDK, GenuinInStreamAds, _FeedCore, or Core | A product isn't added to the app target, the deployment target is below iOS 16, or a shared module isn't imported | Add the products to the target, set iOS 16.0 or later, and add import _FeedCore for BGAdDelegate and import Core for BGNavigationRoot. |
| The ad plays but isn't personalized | ATT authorization wasn't requested or was denied | Request authorization before the first ad view (Step 4). |

## Limitations

- **iOS 16 and later, iOS only:** There's no macOS or Mac Catalyst support.
- **SwiftUI first:** UIKit apps host each slot in a `UIHostingController`.
- **Google IMA is yours to add:** Every app adds the Google IMA package itself.
- **Ad networks are optional:** Each one has its own setup page (Step 3).
- **Six fixed sizes:** There's no flexible or landscape view yet.
- **Tag-only delivery:** Every ad comes from a tag ID managed in your Business Account.
- **Pre-1.0 versioning:** Releases are 0.0.x. Pin an exact version, because 0.x releases can change the API.

## See also

- [Add IAB Standard Size Experiences to an Android app](https://begenuin.com/developers/developer-resources/sdk/integrate-the-genuin-ad-sdk-for-android)
- [Integrate the Genuin iOS SDK](https://begenuin.com/developers/developer-resources/sdk/developer/genuin-sdk/native-compatibility/ios/how-to-integrate-and-power-your-brand-community-in-ios-apps)
- [Integrate the Genuin Android SDK](https://begenuin.com/developers/developer-resources/sdk/how-to-integrate-and-power-your-brand-community-in-android-apps)
- [How the Genuin SDK places ads in a feed](https://begenuin.com/developers/browse-by-products/monetize/how-does-the-genuin-sdk-render-ads-and-deliver-the-consumer-experience)
