> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Popup Ads

> Guide to implementing popup ads in iOS apps.

## Overview

Popup ads are ad formats that appear on screen at specific moments. They can be displayed at desired timings such as app launch, content load completion, or specific event occurrences. Users can close them by tapping the close button or selecting "Don't show for today."

### Features

* Popup format displayed at center or bottom of screen
* Supports both image and video ads
* Provides close, dim (background) click, and "Don't show for today" options
* Customizable background color, text color, etc.
* Non-intrusive yet effective ad experience

<Note>
  Use test unit IDs in development environment. See the [Test Unit IDs](#test-unit-ids) section.
</Note>

***

## Implementation Steps

Implement popup ads in 4 steps:

1. **Initialize** - Create AdropPopupAd instance
2. **Set Delegates** - Set delegates to receive ad and close events
3. **Load Ad** - Request and receive ad
4. **Show Ad** - Display ad on screen

***

## UIKit Implementation

### Basic Implementation

<CodeGroup>
  ```swift Swift theme={null}
  import AdropAds

  class ViewController: UIViewController {
      private var popupAd: AdropPopupAd?

      override func viewDidLoad() {
          super.viewDidLoad()
          loadPopupAd()
      }

      // 1. Initialize and load ad
      private func loadPopupAd() {
          popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
          popupAd?.delegate = self
          popupAd?.closeDelegate = self
          popupAd?.load()
      }

      // 2. Show ad
      private func showPopupAd() {
          guard let popupAd = popupAd,
                popupAd.isLoaded else { return }
          popupAd.show(fromRootViewController: self)
      }
  }
  ```

  ```objc Objective-C theme={null}
  @import AdropAds;

  @interface ViewController () <AdropPopupAdDelegate, AdropPopupAdCloseDelegate>
  @property (nonatomic, strong) AdropPopupAd *popupAd;
  @end

  @implementation ViewController

  - (void)viewDidLoad {
      [super viewDidLoad];
      [self loadPopupAd];
  }

  // 1. Initialize and load ad
  - (void)loadPopupAd {
      self.popupAd = [[AdropPopupAd alloc] initWithUnitId:@"YOUR_POPUP_UNIT_ID"];
      self.popupAd.delegate = self;
      self.popupAd.closeDelegate = self;
      [self.popupAd load];
  }

  // 2. Show ad
  - (void)showPopupAd {
      if (self.popupAd && self.popupAd.isLoaded) {
          [self.popupAd showFromRootViewController:self];
      }
  }

  @end
  ```
</CodeGroup>

### Delegate Implementation

<CodeGroup>
  ```swift Swift theme={null}
  // Ad delegate implementation
  extension ViewController: AdropPopupAdDelegate {
      // Ad received successfully (required)
      func onAdReceived(_ ad: AdropPopupAd) {
          print("Popup ad received")
          // Show ad when ready
          showPopupAd()
      }

      // Ad receive failed (required)
      func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
          print("Popup ad failed to receive: \(errorCode)")
      }

      // Ad impression (optional)
      func onAdImpression(_ ad: AdropPopupAd) {
          print("Popup ad impression")
      }

      // Ad clicked (optional)
      func onAdClicked(_ ad: AdropPopupAd) {
          print("Popup ad clicked")
      }

      // Before showing popup ad (optional)
      func onAdWillPresentFullScreen(_ ad: AdropPopupAd) {
          print("About to show popup ad")
      }

      // After showing popup ad (optional)
      func onAdDidPresentFullScreen(_ ad: AdropPopupAd) {
          print("Popup ad shown")
      }

      // Before dismissing popup ad (optional)
      func onAdWillDismissFullScreen(_ ad: AdropPopupAd) {
          print("About to dismiss popup ad")
      }

      // After dismissing popup ad (optional)
      func onAdDidDismissFullScreen(_ ad: AdropPopupAd) {
          print("Popup ad dismissed")
          // Preload next ad
          loadPopupAd()
      }

      // Popup ad show failed (optional)
      func onAdFailedToShowFullScreen(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
          print("Popup ad failed to show: \(errorCode)")
      }
  }

  // Close delegate implementation
  extension ViewController: AdropPopupAdCloseDelegate {
      // Close button clicked (optional)
      func onClosed(_ ad: AdropPopupAd) {
          print("Popup ad close button clicked")
      }

      // Dim (background) clicked (optional)
      func onDimClicked(_ ad: AdropPopupAd) {
          print("Popup ad dim area clicked")
      }

      // "Don't show for today" clicked (optional)
      func onTodayOffClicked(_ ad: AdropPopupAd) {
          print("Don't show for today selected")
          // The SDK automatically handles hiding the ad for today.
          // Use this callback for analytics or custom UI updates.
      }
  }
  ```

  ```objc Objective-C theme={null}
  #pragma mark - AdropPopupAdDelegate

  // Ad received successfully (required)
  - (void)onAdReceived:(AdropPopupAd *)ad {
      NSLog(@"Popup ad received");
      // Show ad when ready
      [self showPopupAd];
  }

  // Ad receive failed (required)
  - (void)onAdFailedToReceive:(AdropPopupAd *)ad :(AdropErrorCode)errorCode {
      NSLog(@"Popup ad failed to receive: %ld", (long)errorCode);
  }

  // Ad impression (optional)
  - (void)onAdImpression:(AdropPopupAd *)ad {
      NSLog(@"Popup ad impression");
  }

  // Ad clicked (optional)
  - (void)onAdClicked:(AdropPopupAd *)ad {
      NSLog(@"Popup ad clicked");
  }

  // After dismissing popup ad (optional)
  - (void)onAdDidDismissFullScreen:(AdropPopupAd *)ad {
      NSLog(@"Popup ad dismissed");
      // Preload next ad
      [self loadPopupAd];
  }

  #pragma mark - AdropPopupAdCloseDelegate

  // Close button clicked (optional)
  - (void)onClosed:(AdropPopupAd *)ad {
      NSLog(@"Popup ad close button clicked");
  }

  // Dim (background) clicked (optional)
  - (void)onDimClicked:(AdropPopupAd *)ad {
      NSLog(@"Popup ad dim area clicked");
  }

  // "Don't show for today" clicked (optional)
  - (void)onTodayOffClicked:(AdropPopupAd *)ad {
      NSLog(@"Don't show for today selected");
      // The SDK automatically handles hiding the ad for today.
      // Use this callback for analytics or custom UI updates.
  }
  ```
</CodeGroup>

***

## SwiftUI Implementation

In SwiftUI, use `UIViewControllerRepresentable` or get the rootViewController from UIWindow to display.

### ViewModel Pattern

```swift theme={null}
import SwiftUI
import AdropAds

// ViewModel
class PopupAdViewModel: ObservableObject {
    @Published var isAdReady = false
    @Published var isAdShowing = false

    private var popupAd: AdropPopupAd?

    init() {
        loadAd()
    }

    func loadAd() {
        popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
        popupAd?.delegate = self
        popupAd?.closeDelegate = self
        popupAd?.load()
    }

    func showAd() {
        guard let popupAd = popupAd,
              let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootViewController = windowScene.windows.first?.rootViewController else {
            return
        }

        popupAd.show(fromRootViewController: rootViewController)
    }

}

// Ad delegate
extension PopupAdViewModel: AdropPopupAdDelegate {
    func onAdReceived(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdReady = true
        }
    }

    func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
        print("Ad receive failed: \(errorCode)")
    }

    func onAdDidPresentFullScreen(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdShowing = true
        }
    }

    func onAdDidDismissFullScreen(_ ad: AdropPopupAd) {
        DispatchQueue.main.async {
            self.isAdShowing = false
            self.isAdReady = false
        }
        // Preload next ad
        loadAd()
    }
}

// Close delegate
extension PopupAdViewModel: AdropPopupAdCloseDelegate {
    func onClosed(_ ad: AdropPopupAd) {
        print("Popup ad closed")
    }

    func onDimClicked(_ ad: AdropPopupAd) {
        print("Popup ad dim clicked")
    }

    func onTodayOffClicked(_ ad: AdropPopupAd) {
        print("Don't show for today selected")
        // The SDK automatically handles hiding the ad for today.
        // Use this callback for analytics or custom UI updates.
    }
}

// View
struct ContentView: View {
    @StateObject private var adViewModel = PopupAdViewModel()

    var body: some View {
        VStack {
            Text("Popup Ad Example")
                .font(.title)

            Button("Show Popup Ad") {
                adViewModel.showAd()
            }
            .disabled(!adViewModel.isAdReady)
            .padding()
        }
        .onAppear {
            // Auto show on app start
            if adViewModel.isAdReady {
                adViewModel.showAd()
            }
        }
    }
}
```

***

## Customization

You can customize the appearance of popup ads.

### Set Background Color and Text Color

```swift theme={null}
private func loadPopupAd() {
    popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
    popupAd?.delegate = self
    popupAd?.closeDelegate = self

    // Set background color
    popupAd?.backgroundColor = UIColor.black.withAlphaComponent(0.8)

    // "Don't show for today" text color
    popupAd?.hideForTodayTextColor = UIColor.white

    // Close button text color
    popupAd?.closeTextColor = UIColor.white

    // CTA button text color
    popupAd?.ctaTextColor = UIColor.white

    popupAd?.load()
}
```

### Customization Options

| Property                | Type       | Description                            | Default |
| ----------------------- | ---------- | -------------------------------------- | ------- |
| `backgroundColor`       | `UIColor?` | Action bar background color            | `nil`   |
| `hideForTodayTextColor` | `UIColor?` | "Don't show for today" text color      | White   |
| `closeTextColor`        | `UIColor?` | Close button text color                | White   |
| `ctaTextColor`          | `UIColor?` | CTA (Call to Action) button text color | White   |

***

## Delegate Methods

### AdropPopupAdDelegate (Ad Events)

#### Required Methods

<ParamField body="onAdReceived" type="(AdropPopupAd) -> Void">
  Called when ad is received successfully. You can call `show()` at this point to display the ad.
</ParamField>

<ParamField body="onAdFailedToReceive" type="(AdropPopupAd, AdropErrorCode) -> Void">
  Called when ad fails to load. You can check the cause of failure through the error code.
</ParamField>

#### Optional Methods

<ParamField body="onAdImpression" type="(AdropPopupAd) -> Void">
  Called when ad impression is recorded.
</ParamField>

<ParamField body="onAdClicked" type="(AdropPopupAd) -> Void">
  Called when user clicks the ad.
</ParamField>

<ParamField body="onAdWillPresentFullScreen" type="(AdropPopupAd) -> Void">
  Called just before popup ad is displayed.
</ParamField>

<ParamField body="onAdDidPresentFullScreen" type="(AdropPopupAd) -> Void">
  Called immediately after popup ad is displayed on screen.
</ParamField>

<ParamField body="onAdWillDismissFullScreen" type="(AdropPopupAd) -> Void">
  Called just before popup ad is dismissed.
</ParamField>

<ParamField body="onAdDidDismissFullScreen" type="(AdropPopupAd) -> Void">
  Called immediately after popup ad is dismissed. Good time to preload the next ad.
</ParamField>

<ParamField body="onAdFailedToShowFullScreen" type="(AdropPopupAd, AdropErrorCode) -> Void">
  Called when ad fails to show. You can check the cause of failure through the error code.
</ParamField>

<ParamField body="onAdVideoStart" type="(AdropPopupAd) -> Void">
  Called when a video ad starts playing.
</ParamField>

<ParamField body="onAdVideoEnd" type="(AdropPopupAd) -> Void">
  Called when a video ad finishes playing.
</ParamField>

### AdropPopupAdCloseDelegate (Close Events)

All methods are optional.

<ParamField body="onClosed" type="(AdropPopupAd) -> Void">
  Called when user clicks the close button.
</ParamField>

<ParamField body="onDimClicked" type="(AdropPopupAd) -> Void">
  Called when user clicks outside the popup (dim area).
</ParamField>

<ParamField body="onTodayOffClicked" type="(AdropPopupAd) -> Void">
  Called when user selects "Don't show for today." You can save the date in this callback to prevent showing ads for the rest of the day.
</ParamField>

***

## Custom Click Handling

You can take control of ad click behavior by using `useCustomClick`. When enabled, the SDK will not automatically open the destination URL on click, and you can handle it yourself.

### useCustomClick

```swift theme={null}
popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
popupAd?.useCustomClick = true
popupAd?.delegate = self
popupAd?.load()
```

When `useCustomClick` is `true`, the SDK will not open the destination URL automatically when the ad is clicked. The `onAdClicked` delegate callback will still fire, and you can use the `open()` method or handle navigation yourself.

### open()

Opens the destination URL of the ad. Can optionally pass a custom URL.

```swift theme={null}
// Open the ad's default destination URL
popupAd?.open()

// Open a custom URL
popupAd?.open("https://example.com")

// Open using in-app browser
popupAd?.open(nil, useInAppBrowser: true)
```

### close()

Programmatically dismiss the popup ad.

```swift theme={null}
popupAd?.close()
```

***

## Properties

| Property         | Type             | Description                                   |
| ---------------- | ---------------- | --------------------------------------------- |
| `unitId`         | `String`         | The ad unit ID                                |
| `isLoaded`       | `Bool`           | Whether the ad has been loaded                |
| `useCustomClick` | `Bool`           | Whether to handle ad clicks manually          |
| `destinationURL` | `String?`        | Destination URL of the currently displayed ad |
| `creativeId`     | `String?`        | Creative ID of the currently displayed ad     |
| `txId`           | `String`         | Transaction ID of the currently displayed ad  |
| `txIds`          | `[String]`       | All transaction IDs of loaded ads             |
| `campaignId`     | `String`         | Campaign ID of the currently displayed ad     |
| `campaignIds`    | `[String]`       | All campaign IDs of loaded ads                |
| `creativeIds`    | `[String]`       | All creative IDs of loaded ads                |
| `browserTarget`  | `BrowserTarget?` | How to open URLs on ad click                  |

***

## Closure-based Callbacks

In addition to delegates, you can also use closure-based callbacks. This can be convenient when you don't want to implement a full delegate pattern.

```swift theme={null}
let popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")

// Ad events
popupAd.onAdReceived = { ad in
    print("Ad received")
}
popupAd.onAdFailedToReceive = { ad, errorCode in
    print("Ad failed: \(errorCode)")
}
popupAd.onAdClicked = { ad in
    print("Ad clicked, destination: \(ad.destinationURL ?? "")")
}
popupAd.onAdImpression = { ad in
    print("Ad impression")
}
popupAd.onAdWillPresentFullScreen = { ad in
    print("Will present")
}
popupAd.onAdDidPresentFullScreen = { ad in
    print("Did present")
}
popupAd.onAdWillDismissFullScreen = { ad in
    print("Will dismiss")
}
popupAd.onAdDidDismissFullScreen = { ad in
    print("Did dismiss")
}
popupAd.onAdFailedToShowFullScreen = { ad, errorCode in
    print("Failed to show: \(errorCode)")
}
popupAd.onAdVideoStart = { ad in
    print("Video started")
}
popupAd.onAdVideoEnd = { ad in
    print("Video ended")
}

// Close events
popupAd.onClosed = { ad in
    print("Closed")
}
popupAd.onDimClicked = { ad in
    print("Dim clicked")
}
popupAd.onTodayOffClicked = { ad in
    print("Today off clicked")
}

popupAd.load()
```

<Note>
  Delegate callbacks and closure-based callbacks can be used simultaneously. Both will be called.
</Note>

***

## Implementing "Don't Show for Today"

How to properly handle when users select "Don't show for today."

<Note>The SDK automatically manages the "Don't Show for Today" state. The following example shows how to add custom behavior alongside the built-in handling.</Note>

### Implementation

The SDK automatically skips loading when the user has selected "Don't show for today." Simply call `load()` — the SDK handles the rest.

```swift theme={null}
class PopupAdManager {
    private var popupAd: AdropPopupAd?

    // Load and show ad
    func loadAndShowAd(from viewController: UIViewController) {
        popupAd = AdropPopupAd(unitId: "YOUR_POPUP_UNIT_ID")
        popupAd?.delegate = self
        popupAd?.closeDelegate = self
        popupAd?.load()
    }
}

extension PopupAdManager: AdropPopupAdDelegate {
    func onAdReceived(_ ad: AdropPopupAd) {
        // Auto show after receiving ad
        if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
           let rootViewController = windowScene.windows.first?.rootViewController {
            ad.show(fromRootViewController: rootViewController)
        }
    }

    func onAdFailedToReceive(_ ad: AdropPopupAd, _ errorCode: AdropErrorCode) {
        print("Ad receive failed: \(errorCode)")
    }
}

extension PopupAdManager: AdropPopupAdCloseDelegate {
    func onTodayOffClicked(_ ad: AdropPopupAd) {
        print("Don't show for today selected")
        // The SDK automatically handles hiding the ad for today.
        // Use this callback for analytics or custom UI updates.
    }
}
```

***

## Best Practices

### 1. Appropriate Display Timing

Popup ads are effective when shown at these timings:

```swift theme={null}
// ✅ Good: On app launch
func applicationDidFinishLaunching() {
    loadAndShowPopupAd()
}

// ✅ Good: After content load completes
func onContentLoaded() {
    if shouldShowPopupAd() {
        showPopupAd()
    }
}

// ✅ Good: After specific event completes
func onAchievementUnlocked() {
    showPopupAd()
}

// ❌ Bad: While user is working
func onUserTyping() {
    showPopupAd() // Disrupts user experience
}
```

### 2. Respect "Don't Show for Today"

If user selects "Don't show for today," make sure to honor it.

```swift theme={null}
func shouldShowPopupAd() -> Bool {
    // Check "Don't show for today"
    guard canShowAdToday() else {
        return false
    }

    // Check other conditions
    return true
}
```

### 3. Frequency Capping

Don't show popup ads too frequently.

```swift theme={null}
class PopupAdFrequencyManager {
    private let lastShownKey = "popupAd_lastShown"
    private let minimumInterval: TimeInterval = 3600 // 1 hour

    func canShowAd() -> Bool {
        // Check "Don't show for today"
        guard canShowAdToday() else {
            return false
        }

        // Check minimum time interval
        guard let lastShown = UserDefaults.standard.object(forKey: lastShownKey) as? Date else {
            return true
        }

        return Date().timeIntervalSince(lastShown) >= minimumInterval
    }

    func recordAdShown() {
        UserDefaults.standard.set(Date(), forKey: lastShownKey)
    }
}
```

***

## Test Unit IDs

Use the following test unit IDs during development and testing.

| Ad Type                   | Test Unit ID                                  |
| ------------------------- | --------------------------------------------- |
| Popup (Bottom Image)      | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM`            |
| Popup (Center Image)      | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER`            |
| Popup Video (Bottom 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_16_9` |
| Popup Video (Bottom 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_9_16` |
| Popup Video (Center 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_16_9` |
| Popup Video (Center 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_9_16` |

<Warning>
  Make sure to use actual unit IDs created in Ad Control Console for production deployment.
</Warning>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Getting Started" href="/sdk/ios">
    SDK installation and initialization
  </Card>

  <Card title="Interstitial Ads" href="/sdk/ios/interstitial">
    Implementing interstitial ads
  </Card>

  <Card title="Rewarded Ads" href="/sdk/ios/rewarded">
    Implementing rewarded ads
  </Card>

  <Card title="Banner Ads" href="/sdk/ios/banner">
    Implementing banner ads
  </Card>
</CardGroup>
