@MainActor. Times are seconds; prices are CPM.
KontextVideo
The entry point, one instance: KontextVideo.shared.
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.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).User?
What you know about the viewer. Set it whenever you learn it; the next ads request carries it.
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).
String?
Selects which type of ad to render, for A/B tests agreed with Kontext.
String
The SDK’s version, as sent with every request. For your logs and crash reports.
KontextVideo.Configuration
String
required
Identifies the publisher. Not a secret. You get a
{publisher}-dev token for testing and a production one.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
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.
String
required
Your own id of the video, any scheme.
String
required
BCP-47, for example
"en" or "pt-BR".Rating?
.safe or .explicit. Leave unset when you don’t know; explicit content gets no ads that require safe content.URL?
The episode’s public page.
String?
[String]?
IAB Content Taxonomy 3.0 ids.
String?
TimeInterval?
Seconds.
Int?
[String]?
String?
For example
"romance".Series?
KontextVideo.User
String?
Your own unique identifier of the viewer.
String?
Plain email address, when consent allows it. The server hashes it on arrival and never stores the plain address.
String?
SHA-256 of the normalized address (trimmed, lowercased, UTF-8), 64 lowercase hex characters.
[String]?
The viewer’s interests, in your own words.
KontextVideo.Regulatory
Bool?
Whether the request is subject to GDPR.
String?
IAB TCF v2 consent string.
Bool?
Whether the request is subject to COPPA. Cannot be read from the device.
String?
IAB Global Privacy Platform string.
[Int]?
GPP section ids that apply.
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.
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.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).method
The player this episode plays in: an
AVPlayer, or any player that conforms to 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.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
What it was created with.
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(_:).
TimeInterval
Where the content is, in seconds of the episode.
Bool
false when the viewer or your app paused the content, or it ended. Buffering and seeking count as playing.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.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.
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
String
AdFormat
Price
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
Bool
load() finished.Bool
Loaded, not shown, not rejected, not expired:
show() can be tried. A hint, not a guarantee; show() still measures the view.InvalidationReason?
Why the ad ended before it was shown, once it did:
.expired, .rejected, .destroyed, .creativeFailed(code:).Bool
true from a successful show() on.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.Bool
Whether the creative ran to its end: a video reached complete, an overlay’s duration elapsed. Separate from how it left the screen.
VideoAdDelegate?
Receives the ad’s moments. Held weakly.
Methods
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:).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.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.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).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.
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.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.
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.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.VideoAd.EndReason
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.