Rendering contracts
Ad formats
Every format uses the same core auction and tracking pipeline. Format modules translate approved OpenRTB markup into a bounded Android lifecycle and expose callbacks that keep the publisher in control.
Banner and MRECT
Use a banner for persistent, non-blocking inventory. The same module supports a standard 320x50 placement and a 300x250 MRECT. MRAID markup is rendered in a guarded WebView and impressions are viewability-gated.
val banner = BannerAd.Builder("article-footer")
.adSize(AdSize.BANNER_320x50)
.listener(object : BannerAdListener {
override fun onAdLoaded() = banner.show(bannerView)
override fun onAdFailed(error: AdError) = handle(error)
})
.build()
banner.load()Interstitial
Load before a natural break, retain the object while the screen is alive, and show only after readiness is reported. The SDK does not decide when an interruption is appropriate.
val interstitial = InterstitialAd.Builder("level-complete")
.listener(object : InterstitialAdListener {
override fun onInterstitialLoaded() = enableContinueAction()
override fun onInterstitialFailed(error: AdError) = continueWithoutAd()
})
.build()
interstitial.load()
if (interstitial.isReady()) interstitial.show(activity)IAB Native 1.2
Native ads return structured title, body, image, icon, advertiser, CTA and tracking assets. The publisher owns the final Android layout while the SDK owns parsing, clicks and viewable impression registration.
val nativeAd = NativeAd.Builder("recommendation-card")
.listener(object : NativeAdListener {
override fun onNativeAdLoaded(ad: NativeAd) {
ad.bindTo(nativeAdView)
}
override fun onNativeAdFailed(error: AdError) = hideSlot()
})
.build()
nativeAd.load()Native impression trackers fire after at least 50% of the registered view remains visible for one continuous second.
VAST rewarded video
The video module parses VAST Inline and Wrapper documents and reports start, quartile, completion and skip events. Grant the publisher reward only from onRewardEarned().
val video = VideoAd.Builder("rewarded-session")
.listener(object : VideoAdListener {
override fun onVideoAdLoaded() { watchButton.isEnabled = true }
override fun onRewardEarned() { grantPublisherReward() }
override fun onVideoAdFailed(error: AdError) { handle(error) }
})
.build()
video.load()App Open
App Open listens for background-to-foreground transitions, preloads eligible inventory and applies local frequency and expiry constraints. Configure conservative caps so monetization does not obstruct returning users.
AppOpenAd.initialize(this, "app-open", listener) AppOpenAd.setFrequencyCapHours(1) AppOpenAd.setAdExpiryMinutes(30)
Conversational sponsored suggestions
This module adapts an ordinary Native 1.2 creative for a chat or AI assistant surface. It renders a disclosed card between messages. It does not insert an advertiser claim into the assistant's answer and does not read raw conversation text.
val suggestionAd = ConversationalAd.Builder("assistant-inline-1")
.listener(listener)
.build()
suggestionAd.load()
val suggestion = suggestionAd.suggestion
if (suggestion.hasAction) {
suggestionAd.performAction(context)
} else {
suggestionAd.handleClick(context)
}| Boundary | Enforcement |
|---|---|
| Disclosure | The suggestion contract always includes a sponsored disclosure. |
| Content separation | Ad UI renders between messages, never inside answer text. |
| Context minimization | Only registered taxonomy values may enter the request. |
| Renderable or silent | Missing required Native assets produce no-fill, not a broken card. |
Wallet and intent actions
Wallet is an optional executable capability, not a separate inventory type. Install the module before SDK initialization is used for eligible requests. The request advertises only actions that both publisher policy and the actual application build allow.
ApexAds.init(this, config) WalletAdExtension.install()
If the slot, application build or returned creative cannot execute a Wallet action, Apex keeps the standard Native, MRECT or interstitial click experience available.
In-app bidding
Fetch a bid token before loading the mediation network. If Apex has no eligible bid, continue the host waterfall rather than blocking the placement.
ApexInAppBidder.fetchBidToken(
"placement-001",
AdFormat.INTERSTITIAL,
object : InAppBidListener {
override fun onBidReady(token: BidToken) {
mediationAd.setLocalExtraParameter("apex_bid_token", token.token)
mediationAd.setLocalExtraParameter("apex_bid_cpm", token.cpmUsd.toString())
mediationAd.loadAd()
}
override fun onBidFailed(error: AdError) = mediationAd.loadAd()
}
)