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

# Showing your first ad

> Create the video's ads, get an ad, load it early, and show it at the right moment: overlay, pause or linear.

This is the 10-minute integration. Before you start, complete [Installation](https://docs.kontext.so/video/sdk/swift/installation.md) so `KontextVideo.shared.initialize(with:)` runs at launch.

Every format follows the same four steps:

1. `VideoAds(content:)` for the video the viewer is watching.
2. `ads.format()` asks the server and returns a `VideoAd`.
3. `ad.load()` renders the creative off screen, so showing it later is instant. Or `ad.reject()` if you won't use it.
4. `ad.show()` at the moment you choose. One `didEnd` callback when it is over.

## 1. Create the video's ads

One `VideoAds` per video (episode). Creating it sends nothing. Keep it alive as long as you use its ads, for example as a property of your player screen or model: releasing it ends its ads, as `destroy()` does.

```swift theme={null}
import KontextVideoSDK

let content = KontextVideo.Content(
    id: "episode-1234",
    language: "en",
    title: "Episode 1",
    duration: 93,
    genre: "romance",
    series: .init(id: "series-42", title: "My Marionette Lover", episodeCount: 6)
)
let ads = VideoAds(content: content)
```

Only `id` and `language` are required; everything else improves targeting, so send what you have.

Give the SDK your player, so events carry the content playhead and an overlay follows playback:

```swift theme={null}
ads.track(player)   // your AVPlayer, once this episode plays in it
```

For a player that is not an `AVPlayer`, conform it to [`VideoAdsPlayer`](https://docs.kontext.so/video/sdk/swift/api#videoadsplayer) and pass it the same way.

## 2. Get an ad

```swift theme={null}
overlayAd = try await ads.format(.overlay)   // pauseAd with .pause, linearAd with .linear
```

`format()` asks the server for an ad of the format you pass. Ask early, when the episode opens, not at the moment you want to show the ad: the request and the load take a moment, and the ad should appear instantly.

It throws `VideoAdError.noFill(reason:)` when the server has nothing. That is normal, not a failure; ask again later.

## 3. Load it, or reject it

```swift theme={null}
try await overlayAd?.load()
overlayAd?.delegate = self
```

`load()` renders the creative off screen and returns once it is ready, so `show()` is instant. If you decide not to use the ad, call `try overlayAd?.reject()` and the advertiser is told.

## 4. Show it

Each format has its own moment and its own `show()`.

> [tab] Overlay
>
> A strip over the player while the episode plays, at a moment you pick. It goes away by itself after a few seconds, or as soon as the viewer pauses. Show it while the content plays: over paused content `show(in:)` throws `contentPaused`.
>
> ```swift theme={null}
> func showOverlay() {
>     try? overlayAd?.show(in: playerView)   // the view your video plays in
> }
> ```
>
> To take it away earlier, call `dismiss()` on it. If your own controls sit over the player, keep the ad clear of them with `insets`; see [Keeping the ad clear of your controls](https://docs.kontext.so/video/sdk/swift/guides.md#keeping-the-ad-clear-of-your-controls).

> [tab] Pause
>
> A card, or the full player, when the viewer pauses. Take it away when they resume.
>
> ```swift theme={null}
> func viewerPaused() {
>     player.pause()
>     try? pauseAd?.show(in: playerView)   // the view your video plays in
> }
>
> func viewerResumed() {
>     try? pauseAd?.dismiss()
>     player.play()
> }
> ```
>
> The viewer can also tap Resume on a full-screen pause ad; you resume playback in `didEnd`.

> [tab] Linear
>
> A full-screen video between, before or after episodes. Pause your content first; the SDK presents the ad itself.
>
> ```swift theme={null}
> func showLinear() {
>     guard let linearAd else { return }
>     player.pause()
>     do {
>         try linearAd.show()              // from the top view controller; or show(from: viewController)
>     } catch {
>         player.play()                    // it never appeared, so nothing else follows
>     }
> }
> ```
>
> You resume your content in `didEnd`.

`show()` either throws, and nothing happened, or the ad is on screen. From then on the SDK runs it until it ends.

## 5. React to the end

Implement `VideoAdDelegate`. Every method has an empty default; the one you need is `didEnd`. It arrives exactly once per shown ad, whoever ended it, so put your resume logic there and nowhere else, and ask for the next ad from there, so it is ready early.

> [tab] Overlay
>
> Your content kept playing, so there is nothing to resume.
>
> ```swift theme={null}
> extension PlayerController: VideoAdDelegate {
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         overlayAd = nil
>         // prepare the next ad early: format(), then load()
>     }
> }
> ```

> [tab] Pause
>
> When the viewer tapped Resume on a full-screen pause ad, resume playback here. When they resumed through your own control, `viewerResumed()` already did.
>
> ```swift theme={null}
> extension PlayerController: VideoAdDelegate {
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         pauseAd = nil
>         if reason == .resumed { player.play() }        // the viewer tapped Resume on the ad
>         // prepare the next ad early: format(), then load()
>     }
> }
> ```

> [tab] Linear
>
> Your content paused for the ad; resume it, whatever the reason, unless the viewer left. Check `ads.isDestroyed`, not the reason: an ad that was already closing when you called `destroy()` keeps its own reason.
>
> ```swift theme={null}
> extension PlayerController: VideoAdDelegate {
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         linearAd = nil
>         guard !ads.isDestroyed else { return }   // the viewer left: nothing to resume
>         player.play()
>         // prepare the next ad early: format(), then load()
>     }
> }
> ```

## 6. Tear down

Call `destroy()` when the viewer leaves the video. It drops every held ad, tells the server which ones were not used, and ends the one on screen.

```swift theme={null}
ads.destroy()
```

## The whole thing

One controller per episode. Pick the tab for your format:

> [tab] Overlay
>
> ```swift theme={null}
> @MainActor
> final class PlayerController: VideoAdDelegate {
>     let player: AVPlayer
>     let playerView: UIView
>     let ads: VideoAds
>     var overlayAd: VideoAd?
>
>     init(content: KontextVideo.Content, player: AVPlayer, playerView: UIView) {
>         self.player = player
>         self.playerView = playerView
>         ads = VideoAds(content: content)
>         ads.track(player)
>         Task { await prepare() }
>     }
>
>     func prepare() async {
>         do {
>             let ad = try await ads.format(.overlay)
>             try await ad.load()
>             ad.delegate = self
>             overlayAd = ad
>         } catch {
>             // no fill this time; ask again at the next moment
>         }
>     }
>
>     func showOverlay() {                         // a moment you pick
>         try? overlayAd?.show(in: playerView)
>     }
>
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         overlayAd = nil
>         Task { await prepare() }
>     }
>
>     func leave() {
>         ads.destroy()
>     }
> }
> ```

> [tab] Pause
>
> ```swift theme={null}
> @MainActor
> final class PlayerController: VideoAdDelegate {
>     let player: AVPlayer
>     let playerView: UIView
>     let ads: VideoAds
>     var pauseAd: VideoAd?
>
>     init(content: KontextVideo.Content, player: AVPlayer, playerView: UIView) {
>         self.player = player
>         self.playerView = playerView
>         ads = VideoAds(content: content)
>         ads.track(player)
>         Task { await prepare() }
>     }
>
>     func prepare() async {
>         do {
>             let ad = try await ads.format(.pause)
>             try await ad.load()
>             ad.delegate = self
>             pauseAd = ad
>         } catch {
>             // no fill this time; ask again at the next moment
>         }
>     }
>
>     func viewerPaused() {
>         player.pause()
>         try? pauseAd?.show(in: playerView)
>     }
>
>     func viewerResumed() {
>         try? pauseAd?.dismiss()
>         player.play()
>     }
>
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         pauseAd = nil
>         if reason == .resumed { player.play() }   // the viewer tapped Resume on the ad
>         Task { await prepare() }
>     }
>
>     func leave() {
>         ads.destroy()
>     }
> }
> ```

> [tab] Linear
>
> ```swift theme={null}
> @MainActor
> final class PlayerController: VideoAdDelegate {
>     let player: AVPlayer
>     let playerView: UIView
>     let ads: VideoAds
>     var linearAd: VideoAd?
>
>     init(content: KontextVideo.Content, player: AVPlayer, playerView: UIView) {
>         self.player = player
>         self.playerView = playerView
>         ads = VideoAds(content: content)
>         ads.track(player)
>         Task { await prepare() }
>     }
>
>     func prepare() async {
>         do {
>             let ad = try await ads.format(.linear)
>             try await ad.load()
>             ad.delegate = self
>             linearAd = ad
>         } catch {
>             // no fill this time; ask again at the next moment
>         }
>     }
>
>     func showLinear() {                          // a moment you pick
>         guard let linearAd else { return }
>         player.pause()
>         do { try linearAd.show() } catch { player.play() }
>     }
>
>     func videoAd(_ ad: VideoAd, didEnd reason: VideoAd.EndReason) {
>         linearAd = nil
>         guard !ads.isDestroyed else { return }   // after leave(), whatever the reason
>         player.play()
>         Task { await prepare() }
>     }
>
>     func leave() {
>         ads.destroy()
>     }
> }
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.