Skip to main content
Every call is main-thread, and every listener and callback is delivered on the main thread. Times are milliseconds; prices are CPM. The package is so.kontext.video.

KontextVideo

The entry point, one object: KontextVideo.
method
Starts the SDK: stores the configuration and calls the server in the background. Call it once, in Application.onCreate; later calls are ignored. listener is optional and is told the resulting State on the main thread once the server answered or failed.
suspend method
Waits until the server answered or failed and returns the State; at once when it already has: Enabled, Disabled(reason) (the server switched the SDK off for this launch) or Failed (the server could not be reached; the next ads request tries again first).
State
The current state; also NotInitialized before initialize and Initializing while the server is asked.
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 the IAB values your consent platform writes to the default SharedPreferences; 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.

Configuration

Configuration("…") { logLevel = … } in Kotlin, new Configuration.Builder("…").logLevel(…).build() in Java.
String
required
Identifies the publisher. Not a secret. You get a {publisher}-dev token for testing and a production one.
LogLevel
How much the SDK prints to Logcat, tag KontextVideo: NONE, ERROR, WARNING (default), INFO, DEBUG.
String
The ad server, by default the production one. Change it only for testing against a server Kontext gives you.

Content

The video the ads are for. Everything beyond id and language is contextual signal. Content(id, language) { title = … } in Kotlin, new Content.Builder(id, language).title(…).build() in Java.
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.
String?
The episode’s public page.
String?
List<String>?
IAB Content Taxonomy 3.0 ids.
String?
Long?
Milliseconds.
Int?
List<String>?
String?
For example "romance".
Content.Series?
Content.Series(id) { title = …; episodeCount = … }.

User

User { id = … } in Kotlin, new User.Builder().id(…).build() in Java.
String?
Your own unique identifier of the viewer.
String?
Plain email address, when consent allows it. Sent as given; 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. Sent as given.
List<String>?
The viewer’s interests, in your own words.

Regulatory

Regulatory { coppa = true } in Kotlin, new Regulatory.Builder().coppa(true).build() in Java.
Boolean?
Whether the request is subject to GDPR.
IAB TCF v2 consent string.
Boolean?
Whether the request is subject to COPPA. Cannot be read from the device.
String?
IAB Global Privacy Platform string.
List<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. Call destroy() when the viewer leaves the video: dropping the reference does not end its ads.
constructor
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 and describe the screen, never the viewer. 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 Logcat warning.
suspend method
The ad for one format: the same VideoAd as last time while it is unshown and valid, a new one otherwise. Calls made while a request runs share it. A failed request returns the held ad when it is still valid.Throws NoFill, Request, Destroyed, Disabled, NotInitialized, InitializationFailed. A cancelled coroutine stops waiting; the request itself continues.
method
The same for Java, or code without coroutines: callback is a VideoAdsCallback<VideoAd> and gets onSuccess(ad) or onError(exception) on the main thread.
method
The player this episode plays in: a Media3 Player (import so.kontext.video.media3.track, from so.kontext:video-media3), or any 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 onAdEnded(INTERRUPTED) when the content pauses, ends, or the player moves to another item. Held until destroy() or the next track; the Media3 adapter holds your player weakly. 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 onAdEnded(DESTROYED); a format() or load() in flight throws Destroyed. Idempotent.
Content
What it was created with.
Boolean
true after destroy().
String?
The id of the latest ads request, null before the first. Quote it to Kontext when an ad or a no-fill looks wrong.

VideoAdsPlayer

What the SDK reads from a player that is not a Media3 Player. Implement it, in a small adapter around your player, and pass it to track(player). The SDK reads it on the main thread.
Long
Where the content is, in milliseconds of the episode.
Boolean
false when the viewer or your app paused the content, or it ended. Buffering and seeking count as playing.
Float?
Optional. The playback speed, 1 being normal, when your player knows it. null (the default) allows up to about 4×.
method
Optional. Tell the VideoAdsPlayer.Listener what the player does, as it happens, so an overlay reacts at once: onIsPlayingChanged(isPlaying), onSeek(), onContentChanged() (another item, or this one played to its end). Without a listener the SDK reads isPlaying four times a second while an overlay is on screen, and estimates seeks from the position.
An overlay’s duration counts milliseconds of video. Without onSeek() and playbackSpeed, the SDK treats a jump faster than about 4× real time as a seek and counts nothing for it. The Media3 adapter reports all of it.

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 onAdEnded. Shown at most once.

Facts

String
AdFormat
VideoAd.Price
Long?
Overlay: how long the SDK keeps it on screen, null when it stays until ended. Linear: the video’s length. Always null for a pause ad.

State

Boolean
load() finished.
Boolean
Loaded, not shown, not rejected, not expired: show() can be tried. A hint, not a guarantee; show() still measures the container.
InvalidationReason?
Why the ad ended before it was shown, once it did: Expired, Rejected, Destroyed, CreativeFailed(code).
Boolean
true from a successful show() on.
Boolean
true once the ad began to end. onAdEnded follows at once for an overlay or pause ad, and once its screen is gone for a linear ad.
Boolean
Whether the creative ran to its end: a video reached complete, an overlay’s duration elapsed. Separate from how it left the screen.
VideoAdListener?
Receives the ad’s moments. Held until onAdEnded has run, then let go.

Methods

suspend method
Renders the creative off screen and returns once it is ready, so show() is instant. Throws CreativeFailed, Invalidated, Destroyed, Disabled. A second call waits for the first. load(callback) is the same for Java: a VideoAdsCallback<VideoAd>.
method
You won’t use the ad; the server tells the advertiser. RejectReason.NotUsed (default) or RejectReason.Outbid(winningPrice, winner). Works until show(), loaded or not. Throws AlreadyShown after it, or Invalidated if the ad already ended.
method
Shows an overlay or pause ad inside container, the ViewGroup the content plays in. Returns once the ad is on screen. The ad follows the container when it resizes or rotates; a container that becomes too small for it ends the ad with onAdEnded(INTERRUPTED). Throws, with nothing shown: NotLoaded, AlreadyShown, AnotherAdShowing, Invalidated, Destroyed, Disabled, PresenterUnavailable (the container is not attached to a window, not shown, or has no area), ContainerTooSmall 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 onAdEnded(INTERRUPTED) when the content stops.
method
Shows a linear ad full screen, in the SDK’s own Activity started from activity. Back does nothing there: the creative’s own controls end the ad. Throws, with nothing shown: the errors above, PresenterUnavailable for an Activity that is finishing or destroyed (the ad stays ready), WrongPresentation (an overlay or pause ad).
method
Ends an overlay or pause ad because you say so; onAdEnded(DISMISSED) follows, synchronously. Before show() and after the end it does nothing. Throws WrongPresentation for a linear ad, which only the SDK dismisses.
reject, show and dismiss are annotated @Throws(VideoAdException::class), so Java code catches the exception.

VideoAdListener

Delivered on the main thread. Every method has an empty default, from Java too; implement the ones you need. Nothing is delivered before show(). After it: the impression and clicks, in no fixed order, then exactly one onAdEnded, always last. Every method gets the ad first, so one listener 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. Delivered as the opening starts, so whether anything opened, and which, is not reported. Once per tap.
method
The ad broke after show() returned. onAdEnded(FAILED) follows.
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 ad’s screen is gone, so you can start your next screen from it.

VideoAd.EndReason

VideoAdException

Thrown by a call: a thrown exception means nothing happened on screen and nothing was fired, except a failed load()’s VAST error event. Two are also delivered through onAdFailed after a show() that succeeded: CreativeFailed and PresenterUnavailable; the ad is over then. Every one is a subclass of VideoAdException.

NoFillReason