> ## 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.

# API reference

> Every type, method, callback and error of the Swift Video SDK.

All public types are `@MainActor`. Times are seconds; prices are CPM.

## `KontextVideo`

The entry point, one instance: `KontextVideo.shared`.

**initialize(with:completion:)** `method`

Starts the SDK: stores the configuration and calls the server in the background. Call it once, at app launch; later calls are ignored. `completion` runs on the main thread once the server answered or failed.

```swift theme={null}
KontextVideo.shared.initialize(with: .init(publisherToken: "…")) { state in … }
```

**initialize(with:)** `async method`

The same for `async` code; returns the resulting `State`: `.enabled`, `.disabled(reason:)` (the server switched the SDK off for this launch) or `.failed` (the server could not be reached; every ads request retries first).

```swift theme={null}
let state = await KontextVideo.shared.initialize(with: .init(publisherToken: "…"))
```

**user** `User?`

What you know about the viewer. Set it whenever you learn it; the next ads request carries it.

**regulatory** `Regulatory?`

Privacy and consent signals. The SDK reads TCF values from your consent platform's shared storage; set here what it did not write (COPPA always comes from you).

**variantId** `String?`

Selects which type of ad to render, for A/B tests agreed with Kontext.

**version** `String`

The SDK's version, as sent with every request. For your logs and crash reports.

## `KontextVideo.Configuration`

**publisherToken** `String` *required*

Identifies the publisher. Not a secret. You get a `{publisher}-dev` token for testing and a production one.

**requestTrackingAuthorization** `Bool`

Whether the SDK shows the App Tracking Transparency dialog itself, before its first ads request. Defaults to `false`: the app decides when the dialog appears.

**logLevel** `LogLevel`

How much the SDK prints to the console: `.none`, `.error`, `.warning` (default), `.info`, `.debug`.

## `KontextVideo.Content`

The video the ads are for. Everything beyond `id` and `language` is contextual signal.

**id** `String` *required*

Your own id of the video, any scheme.

**language** `String` *required*

BCP-47, for example `"en"` or `"pt-BR"`.

**mediaRating** `Rating?`

`.safe` or `.explicit`. Leave unset when you don't know; explicit content gets no ads that require safe content.

**url** `URL?`

The episode's public page.

**title** `String?`

**categories** `[String]?`

IAB Content Taxonomy 3.0 ids.

**description** `String?`

**duration** `TimeInterval?`

Seconds.

**episodeNumber** `Int?`

**keywords** `[String]?`

**genre** `String?`

For example `"romance"`.

**series** `Series?`

**Properties**

**id** `String` *required*

**title** `String?`

**description** `String?`

**episodeCount** `Int?`

Total number of episodes.

## `KontextVideo.User`

**id** `String?`

Your own unique identifier of the viewer.

**email** `String?`

Plain email address, when consent allows it. The server hashes it on arrival and never stores the plain address.

**emailHash** `String?`

SHA-256 of the normalized address (trimmed, lowercased, UTF-8), 64 lowercase hex characters.

**keywords** `[String]?`

The viewer's interests, in your own words.

## `KontextVideo.Regulatory`

**gdpr** `Bool?`

Whether the request is subject to GDPR.

**gdprConsent** `String?`

IAB TCF v2 consent string.

**coppa** `Bool?`

Whether the request is subject to COPPA. Cannot be read from the device.

**gpp** `String?`

IAB Global Privacy Platform string.

**gppSid** `[Int]?`

GPP section ids that apply.

**usPrivacy** `String?`

Legacy IAB US Privacy (CCPA) string.

## `AdFormat`

`.overlay`, `.pause`, `.linear`.

## `VideoAds`

The ads of one video. Create one per episode; creating it sends nothing. Any number can be alive at once.

**init(content:labels:)** `initializer`

`labels` is optional: key-values that say where these ads play, such as the viewer's stage in the series or the player's layout. Every request of this `VideoAds` carries them, and your setup on our side decides what they change, such as which formats are offered. They are fixed for the object's life. Keys use `a-z`, `0-9` and `_`; values are not empty; both are at most 64 bytes, with at most 20 pairs. Anything else is dropped with a console warning.

```swift theme={null}
let ads = VideoAds(content: KontextVideo.Content(id: "episode-1", language: "en"))
let firstEpisode = VideoAds(content: content, labels: ["stage": "first_episode", "layout": "fullscreen"])
```

**format(\_:)** `async throwing method`

The ad for one format: the same `VideoAd` as last time while it is unshown and valid, a new one otherwise. A failed request returns the held ad when it is still valid.

Throws `noFill(reason:)`, `request(_:)`, `destroyed`, `disabled(reason:)`, `notInitialized`, `initializationFailed`, or `CancellationError` when your task is cancelled (the request itself continues).

```swift theme={null}
let ad = try await ads.format(.pause)
```

**track(\_:)** `method`

The player this episode plays in: an `AVPlayer`, or any player that conforms to [`VideoAdsPlayer`](#videoadsplayer). The SDK reads its time for requests and events, and follows its playback for an overlay: an overlay shows over playing content only, and ends with `didEnd(.interrupted)` when the content pauses, ends, or the player moves to another item. Held weakly; `destroy()` lets go of it. Call it when this episode starts playing in the player. Without a player, events carry 0 (right for a prefetch) and an overlay runs on its own time.

```swift theme={null}
ads.track(player)
```

**destroy()** `method`

Releases the video's ads. Every held ad is dropped and the advertiser told it was not used; the ad on screen ends with `didEnd(.destroyed)`; a `format()` or `load()` in flight throws `destroyed`. Idempotent. Releasing the object does the same, best effort.

**content** `Content`

What it was created with.

**isDestroyed** `Bool`

`true` after `destroy()`.

## `VideoAdsPlayer`

What the SDK reads from a player that is not an `AVPlayer`. Conform your player, or a small wrapper around it, and pass it to `track(_:)`.

**currentTime** `TimeInterval`

Where the content is, in seconds of the episode.

**isPlaying** `Bool`

`false` when the viewer or your app paused the content, or it ended. Buffering and seeking count as playing.

**isPlayingPublisher** `AnyPublisher\<Bool, Never\>?`

Optional. Emits whenever `isPlaying` changes, so an overlay ends at once. Without it the SDK reads `isPlaying` four times a second while an overlay is on screen.

An overlay's `duration` counts how far `currentTime` moves. The SDK does not know a custom player's seeks or speed, so it treats a jump faster than about 4× real time as a seek and counts nothing for it; a small seek, or one right after a long stall, may count. With an `AVPlayer` the SDK uses the player's own speed and seek events.

```swift theme={null}
extension MyPlayer: VideoAdsPlayer {
    var currentTime: TimeInterval { position }
    var isPlaying: Bool { state == .playing || state == .buffering }
}
```

## `VideoAd`

One ad, from the server's answer to the end of its presentation. Look at its facts, then `load()` or `reject()`, then `show()`, then exactly one `didEnd`. Shown at most once.

### Facts

**id** `String`

**format** `AdFormat`

**price** `Price`

**Properties**

**value** `Double`

CPM.

**currency** `String`

ISO 4217.

**precision** `Precision`

`.exact` (a DSP's clearing price) or `.estimated` (house demand, a forecast).

**duration** `TimeInterval?`

Overlay: how long the SDK keeps it on screen, `nil` when it stays until ended. Linear: the video's length. Always `nil` for a pause ad.

### State

**isLoaded** `Bool`

`load()` finished.

**isReady** `Bool`

Loaded, not shown, not rejected, not expired: `show()` can be tried. A hint, not a guarantee; `show()` still measures the view.

**invalidationReason** `InvalidationReason?`

Why the ad ended before it was shown, once it did: `.expired`, `.rejected`, `.destroyed`, `.creativeFailed(code:)`.

**wasShown** `Bool`

`true` from a successful `show()` on.

**hasEnded** `Bool`

`true` once the ad began to end. `didEnd` follows at once for an overlay or pause ad, and once the dismissal finished for a linear ad.

**isCompleted** `Bool`

Whether the creative ran to its end: a video reached complete, an overlay's duration elapsed. Separate from how it left the screen.

**delegate** `VideoAdDelegate?`

Receives the ad's moments. Held weakly.

### Methods

**load()** `async throwing method`

Renders the creative off screen and returns once the page reports it ready, so `show()` is instant. Throws `creativeFailed(code:)`, `invalidated(_:)`, `destroyed`, `disabled(reason:)`.

**reject(\_:)** `throwing method`

You won't use the ad; the server tells the advertiser. `.notUsed` (default) or `.outbid(winningPrice:winner:)`. Works until `show()`, loaded or not. Throws `alreadyShown` after it, or the invalidation if the ad already ended.

```swift theme={null}
try ad.reject(.outbid(winningPrice: 2.4, winner: "Other network"))
```

**show(in:insets:)** `throwing method`

Shows an overlay or pause ad inside `view`, the one the content plays in. Succeeds once the ad is on screen. The ad follows the view when it resizes or rotates; a view that becomes too small for it ends the ad with `didEnd(.interrupted)`. Throws, with nothing shown: `notLoaded`, `alreadyShown`, `anotherAdShowing`, `invalidated(_:)`, `destroyed`, `disabled(reason:)`, `presenterUnavailable` (the view is not in a window, has no area, or is hidden), `containerTooSmall(minimum:)` and `contentPaused` (an overlay over paused content; the ad stays ready in these three), `wrongPresentation` (a linear ad). With a player given to `track(_:)`, an overlay also ends with `didEnd(.interrupted)` when the content stops.

**Parameters**

**insets** `UIEdgeInsets`

Space to keep free inside `view`, on top of its safe area: `bottom: 80` places a bottom strip 80 points above the safe area's edge. Defaults to `.zero`. Kept while the ad is shown, through resizes and rotations. A full-screen pause ad ignores them. See [Keeping the ad clear of your controls](https://docs.kontext.so/video/sdk/swift/guides.md#keeping-the-ad-clear-of-your-controls).

**show(from:)** `throwing method`

Presents a linear ad full screen: from the given view controller, or with `nil` (the default) from the key window's top view controller. Throws, with nothing shown: the errors above plus `presenterUnavailable` (the ad stays ready), `wrongPresentation` (an overlay or pause ad).

```swift theme={null}
try linear.show()
try linear.show(from: viewController)
```

**dismiss()** `throwing method`

Ends an overlay or pause ad because you say so; `didEnd(.dismissed)` follows, synchronously. Before `show()` and after `didEnd` it does nothing. Throws `wrongPresentation` for a linear ad, which only the SDK dismisses.

## `VideoAdDelegate`

Delivered on the main actor. Every method has an empty default; implement the ones you need. Nothing is delivered before `show()`. After it: the impression and clicks, in no fixed order, then exactly one `didEnd`, always last. Every method gets the ad first, so one delegate can serve several ads.

**videoAdDidRecordImpression(\_ ad: VideoAd)** `method`

The impression was counted: at `show()` for an image or HTML creative, at the first frame for a video. At most once; may not come at all, when the ad ends before.

**videoAd(\_ ad: VideoAd, didClick click: VideoAd.Click)** `method`

The viewer tapped the ad. The SDK recorded the click and started opening its target: the URL, its fallback when the first cannot open, or for an app-install ad the App Store product sheet inside your app. Delivered as the opening starts, so whether anything opened, and which, is not reported. Once per tap.

**click**

**area** `VideoAd.Click.Area`

Where the viewer tapped: `.creative` (the image, the video, the card), `.endCard` (a linear ad's end card, after the video completed), or `.other(String)`, a label of the creative's own such as `"cta"`.

**videoAd(\_ ad: VideoAd, didFail error: VideoAdError)** `method`

The ad broke after `show()` returned. `didEnd(.failed)` follows once the ad is cleaned up: at once for an overlay or pause ad, after its dismissal for a linear ad.

**error**

**.creativeFailed(code:)** `VideoAdError`

The creative failed or stalled on screen. `code` is the VAST error code: the creative's own, or 405.

**.presenterUnavailable** `VideoAdError`

UIKit never presented the linear ad.

**videoAd(\_ ad: VideoAd, didEnd reason: VideoAd.EndReason)** `method`

Presentation is over. Exactly once per successful `show()`, always last. Resume your content here, deciding from the format and `reason`. For an overlay or pause ad it comes synchronously, even from inside your own `dismiss()` or `destroy()`. For a linear ad it comes once the dismissal finished, so you can present your next screen from it.

**reason**

**reason** `VideoAd.EndReason`

Who or what took the ad off the screen; see [`VideoAd.EndReason`](#videoad-endreason). Whether the creative ran to its end is `ad.isCompleted`: a linear ad whose end card the viewer closed is `.closed` with `isCompleted == true`.

## `VideoAd.EndReason`

| Reason | When |
| - | - |
| `.completed` | The ad ended by itself: an overlay's duration elapsed, a linear video finished with no end card. |
| `.skipped` | The viewer tapped Skip on a linear ad before the video ended. |
| `.closed` | The viewer tapped the ad's close control (an overlay's or pause card's ✕, a linear end card's ✕). A pause card's ✕ leaves the content paused. |
| `.resumed` | The viewer tapped Resume on a full-screen pause ad. |
| `.failed` | The creative failed or stalled, or the full-screen ad could not be presented; `didFail` came first. |
| `.interrupted` | The presentation disappeared for a reason the SDK did not cause: the view left the window, the presenting controller was dismissed, or the view became too small for the ad. Noticed within about half a second. For an overlay with a player given to `track(_:)`, also the content pausing, ending or moving to another item. |
| `.dismissed` | You called `dismiss()`. |
| `.destroyed` | You called `destroy()`. |

## `VideoAdError`

Thrown by a call: a thrown error means nothing happened on screen and nothing was fired, except a failed `load()`'s VAST error event. Two are also delivered through `didFail` after a `show()` that succeeded: `.creativeFailed(code:)` and `.presenterUnavailable`; the ad is over then.

| Error | When |
| - | - |
| `.notInitialized` | `initialize(with:)` was never called. |
| `.initializationFailed` | The server could not be reached, and the retry failed too. Every `format()` retries. |
| `.destroyed` | The `VideoAds` was destroyed. Create a new one for the next content. |
| `.disabled(reason:)` | The server switched the SDK off for this launch. |
| `.noFill(reason:)` | The server had nothing for this format. See `NoFillReason`. |
| `.request(Error)` | The request failed and no valid ad was held for the format. |
| `.creativeFailed(code:)` | The creative did not load within 10 s of active time; `code` is the VAST error code. |
| `.alreadyShown` | Shown once; cannot be shown again or rejected. |
| `.anotherAdShowing` | Another ad is on screen, from any `VideoAds`. This ad stays ready. |
| `.invalidated(reason)` | The ad ended before it was shown: `.expired`, `.rejected`, `.destroyed`, `.creativeFailed(code:)`. |
| `.notLoaded` | `show()` before `load()` finished. The ad stays as it was. |
| `.contentPaused` | `show(in:)` on an overlay while the content of its `VideoAds` is paused. The ad stays ready: show it once the content plays. |
| `.containerTooSmall(minimum:)` | The ad would have to shrink below 50 % to fit. `minimum` is the smallest view that holds it, its safe area and your insets included. The ad stays ready. |
| `.presenterUnavailable` | Nothing on screen can hold the ad right now: no view controller can present the linear ad, or the view given for an overlay or pause ad is not in a window, has no area, or is hidden. The ad stays ready. |
| `.wrongPresentation` | `show()` on an overlay or pause ad, `show(in:)` or `dismiss()` on a linear ad. |

## `VideoAdError.NoFillReason`

| Reason | Meaning |
| - | - |
| `.noAdMatch` | No campaign matched the content, the viewer or the moment |
| `.frequencyCap` | The viewer reached the frequency cap set for your app. Only when a cap is configured |
| `.contentUnsafe` | The content is not brand safe |
| `.geoRestricted` | Not served in this country |
| `.formatNotEnabled` | The format is not enabled for your app, or not for the `labels` this `VideoAds` sends |
| `.temporaryError` | Our side; ask again later |
| `.alreadyUsed` | The SDK's own: the answer was an ad you had just shown or rejected |
| `.unknown` | The server gave no reason |
| `.other(String)` | A reason this SDK version does not know, passed through unchanged |


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