Android SDK Quickstart
The HypeLab Android SDK allows you to monetize your Android app with banner, native, interstitial, and rewarded ads. The SDK handles ad loading, rendering, viewability tracking, and click handling with a simple callback-based API.
Privacy: Publishers must comply with all regional data protection and privacy laws (GDPR, CCPA, etc.) and obtain necessary user consents prior to using the HypeLab SDK. See Privacy & Compliance for details.
All code examples below are in Kotlin.
Installation
Add the HypeLab Maven repository and SDK dependency to your project.
Requirements
| Requirement | Minimum |
|---|---|
| Android API level | 24 (Android 7.0) |
| Java version | 17 |
| Kotlin version | 1.9+ |
Initialization
Initialize the SDK once in your Application.onCreate() before creating any ad instances.
import com.hypelab.sdk.HypeLab
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
HypeLab.initialize(
context = this,
propertySlug = "your_property_slug"
)
}
}
Don't forget to register your Application class in AndroidManifest.xml:
<application android:name=".MyApplication" ... >
Configuration Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
context | Context | required | Application context |
propertySlug | String | required | Your HypeLab property slug |
environment | Environment | PRODUCTION | Target environment (PRODUCTION, STAGING) |
debug | Boolean | false | Enable verbose logging to Logcat |
You can also initialize with a Config object for more control:
val config = HypeLab.Config(
propertySlug = "your_property_slug",
debug = BuildConfig.DEBUG
)
HypeLab.initialize(this, config)
Test Mode
Enable test mode during development to receive test ads that are safe to click:
HypeLab.setTestMode(true)
Banner Ads
Banner ads display image or rich media content in fixed-size placements. They are a great starting point for ad monetization.
Banner Sizes
| Size | Constant | Dimensions | Description |
|---|---|---|---|
| Standard | BannerSize.STANDARD | 320x50 | Phone banner |
| Large | BannerSize.LARGE | 320x100 | Large phone banner |
| MREC | BannerSize.MREC | 300x250 | Medium rectangle |
| Leaderboard | BannerSize.LEADERBOARD | 728x90 | Tablet leaderboard |
Usage
import com.hypelab.sdk.Banner
import com.hypelab.sdk.BannerSize
class MainActivity : AppCompatActivity() {
private var banner: Banner? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val container = findViewById<FrameLayout>(R.id.banner_container)
banner = Banner("your_banner_slug", BannerSize.STANDARD).apply {
onReady = {
// Ad is loaded — add the view to your layout
view?.let { container.addView(it) }
}
onError = { error ->
Log.e("Ad", "Banner error: ${error.message}")
}
onImpression = {
Log.d("Ad", "Banner impression tracked")
}
onClick = {
Log.d("Ad", "Banner clicked")
}
}
banner?.loadAd()
}
override fun onDestroy() {
super.onDestroy()
banner?.destroy()
}
}
Banner Callbacks
| Callback | Signature | Description |
|---|---|---|
onReady | () -> Unit | Ad is loaded and view is available |
onError | (HypeLabError) -> Unit | Ad failed to load |
onImpression | () -> Unit | Viewable impression tracked (MRC standard) |
onClick | () -> Unit | User clicked the ad |
onClose | () -> Unit | Banner was destroyed |
onExpired | () -> Unit | Loaded ad expired (1-hour TTL) |
Lifecycle: Always call banner.destroy() in your Activity or Fragment's onDestroy() to release resources and prevent memory leaks.
Native Ads
Native ads provide structured data (headline, body, images, etc.) that you render in your own UI, giving you full control over the ad's appearance.
Native Ad Assets
| Property | Type | Description |
|---|---|---|
headline | String | Primary ad title |
advertiser | String | Advertiser/sponsor name |
body | String | Ad description text |
ctaText | String | Call-to-action button text |
displayUrl | String | Display URL for transparency |
iconUrl | String | Advertiser logo/icon URL |
imageUrl | String? | Main image URL (either image or video is present) |
videoUrl | String? | Video URL from VAST (either image or video is present) |
starRating | Double? | App store rating (optional) |
Usage
import com.hypelab.sdk.Native
import com.bumptech.glide.Glide
class NativeAdActivity : AppCompatActivity() {
private var nativeUnit: Native? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_native_ad)
val container = findViewById<ViewGroup>(R.id.native_ad_container)
val headline = findViewById<TextView>(R.id.headline)
val body = findViewById<TextView>(R.id.body)
val ctaButton = findViewById<Button>(R.id.cta_button)
val icon = findViewById<ImageView>(R.id.icon)
val mediaImage = findViewById<ImageView>(R.id.media_image)
nativeUnit = Native("your_native_slug").apply {
onReady = { ad ->
// Bind assets to your views
headline.text = ad.headline
body.text = ad.body
ctaButton.text = ad.ctaText
// Load images with Glide (or your preferred library)
Glide.with(this@NativeAdActivity).load(ad.iconUrl).into(icon)
ad.imageUrl?.let { url ->
Glide.with(this@NativeAdActivity).load(url).into(mediaImage)
}
// Register view for impression and click tracking
ad.registerView(container, listOf(ctaButton, headline))
container.visibility = View.VISIBLE
}
onError = { error ->
Log.e("Ad", "Native error: ${error.message}")
}
onImpression = {
Log.d("Ad", "Native impression tracked")
}
onClick = {
Log.d("Ad", "Native ad clicked")
}
}
nativeUnit?.loadAd()
}
override fun onDestroy() {
super.onDestroy()
nativeUnit?.destroy()
}
}
Registering Views for Tracking
After binding assets to your UI, you must call registerView() on the NativeAd object. This enables:
- Impression tracking - The SDK monitors viewability (MRC standard: 50% visible for 1 second) and fires impression events automatically.
- Click tracking - Taps on the specified clickable views trigger click events and open the destination URL.
ad.registerView(
containerView = nativeAdContainer, // Root view for viewability measurement
clickableViews = listOf(ctaButton) // Views that trigger click events
)
If you omit the clickableViews parameter, the entire container becomes clickable.
Native Callbacks
| Callback | Signature | Description |
|---|---|---|
onReady | (NativeAd) -> Unit | Ad is loaded; bind assets and call registerView() |
onError | (HypeLabError) -> Unit | Ad failed to load |
onImpression | () -> Unit | Viewable impression tracked (MRC standard) |
onClick | () -> Unit | User clicked the ad |
onExpired | () -> Unit | Loaded ad expired (1-hour TTL) |
Image loading: The SDK provides image URLs but does not load images. Use Glide, Coil, or any image loading library you prefer.
Interstitial Ads
Interstitial ads are full-screen ads displayed at natural transition points, such as level completion, app launch, or between content screens.
Usage
Interstitials follow a load-then-show pattern. Load the ad early, then show it when the user reaches a natural break point.
import com.hypelab.sdk.Interstitial
class GameActivity : AppCompatActivity() {
private var interstitial: Interstitial? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
interstitial = Interstitial("your_interstitial_slug").apply {
onReady = {
Log.d("Ad", "Interstitial ready to show")
}
onError = { error ->
Log.e("Ad", "Interstitial error: ${error.message}")
}
onImpression = {
Log.d("Ad", "Interstitial impression tracked")
}
onClick = {
Log.d("Ad", "Interstitial clicked")
}
onClose = {
Log.d("Ad", "Interstitial closed")
// Resume your app flow here
}
}
// Load early so the ad is ready when needed
interstitial?.loadAd()
}
// Show at a natural transition point
private fun onLevelComplete() {
if (interstitial?.isReady == true) {
interstitial?.show()
}
}
override fun onDestroy() {
super.onDestroy()
interstitial?.destroy()
}
}
Interstitial Callbacks
| Callback | Signature | Description |
|---|---|---|
onReady | () -> Unit | Ad is loaded and ready to show |
onError | (HypeLabError) -> Unit | Ad failed to load or show |
onImpression | () -> Unit | Impression tracked |
onClick | () -> Unit | User clicked the ad |
onClose | () -> Unit | User dismissed the ad |
onExpired | () -> Unit | Loaded ad expired (1-hour TTL) |
Best practices:
- Load early (e.g., when the user starts a level) so the ad is ready when needed.
- Always check
isReadybefore callingshow(). - Show only at natural transition points to preserve user experience.
Rewarded Ads
Rewarded ads let users opt in to watch a video ad in exchange for an in-app reward (extra lives, coins, premium content, etc.). The onReward callback fires when the user has earned the reward.
Usage
import com.hypelab.sdk.Rewarded
class RewardedActivity : AppCompatActivity() {
private var rewarded: Rewarded? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rewarded)
val watchAdButton = findViewById<Button>(R.id.watch_ad_button)
watchAdButton.isEnabled = false
rewarded = Rewarded("your_rewarded_slug").apply {
onReady = {
watchAdButton.isEnabled = true
}
onError = { error ->
Log.e("Ad", "Rewarded error: ${error.message}")
watchAdButton.isEnabled = false
}
onVideoStart = {
Log.d("Ad", "Video started playing")
}
onVideoComplete = {
Log.d("Ad", "Video completed")
}
onReward = { reward ->
Log.d("Ad", "Reward earned: ${reward.amount} ${reward.type}")
// Grant the reward to the user
grantReward(reward.amount, reward.type)
}
onClose = {
Log.d("Ad", "Rewarded ad closed")
watchAdButton.isEnabled = false
// Reload for next time
rewarded?.loadAd()
}
}
rewarded?.loadAd()
watchAdButton.setOnClickListener {
if (rewarded?.isReady == true) {
rewarded?.show()
}
}
}
override fun onDestroy() {
super.onDestroy()
rewarded?.destroy()
}
}
Rewarded Callbacks
| Callback | Signature | Description |
|---|---|---|
onReady | () -> Unit | Ad is loaded and ready to show |
onError | (HypeLabError) -> Unit | Ad failed to load or show |
onImpression | () -> Unit | Impression tracked |
onClick | () -> Unit | User clicked the ad |
onVideoStart | () -> Unit | Video started playing |
onVideoComplete | () -> Unit | Video finished playing |
onVideoError | (String) -> Unit | Video playback error |
onReward | (Reward) -> Unit | User earned the reward |
onClose | () -> Unit | User dismissed the ad |
onExpired | () -> Unit | Loaded ad expired (1-hour TTL) |
Reward Object
The onReward callback provides a Reward object:
| Property | Type | Description |
|---|---|---|
type | String | Reward type (e.g., "coins", "gems") |
amount | Int | Reward quantity |
transactionId | String? | Unique ID for server-side verification |
Server-Side Verification (SSV)
To verify rewards server-to-server for fraud prevention, set ssvOptions before calling loadAd():
val rewarded = Rewarded("your_rewarded_slug")
// Set SSV options before loading
rewarded.ssvOptions = SSVOptions(
userID = "user_123",
customData = "level=5&item=boost" // Optional URL-encoded data
)
rewarded.onReward = { reward ->
// The transactionId can be cross-referenced with
// the server-to-server callback to your SSV endpoint
Log.d("SSV", "Transaction ID: ${reward.transactionId}")
}
rewarded.loadAd()
| SSVOptions Property | Type | Description |
|---|---|---|
userID | String | Your unique user identifier |
customData | String? | Optional URL-encoded custom data |
Privacy & Compliance
The SDK provides APIs for GDPR, COPPA, and CCPA compliance. Configure these after initialization and before loading ads.
GDPR / TCF v2.2
If you use a TCF-compliant CMP (e.g., Google UMP, OneTrust), the SDK automatically reads the TC consent string from SharedPreferences. No additional setup is needed.
For manual consent management:
// Set GDPR consent manually HypeLab.setGDPRConsent(granted = true) // Tag users under the EU age of consent (typically 16) HypeLab.setTagForUnderAgeOfConsent(enabled = true)
COPPA
For apps directed at children under 13:
HypeLab.setTagForChildDirectedTreatment(enabled = true)
When enabled, no behavioral targeting or device identifiers are collected.
CCPA / US State Privacy
To enable restricted data processing for users who opt out of data sale:
HypeLab.setRestrictedDataProcessing(enabled = true)
Wallet Addresses
If your app supports crypto wallets, passing wallet addresses enables wallet-targeted ads for higher CPMs:
// When user connects wallet
HypeLab.setWalletAddresses(listOf("0x123...", "0x234..."))
// When user disconnects wallet
HypeLab.clearWalletAddresses()
Error Handling
All onError callbacks receive a HypeLabError sealed class. Use Kotlin's when expression to handle specific cases:
banner.onError = { error ->
when (error) {
is HypeLabError.NoFill -> {
// No ad available — hide the ad container
}
is HypeLabError.NetworkError -> {
// Network issue — retry later
}
is HypeLabError.NotInitialized -> {
// SDK not initialized — call HypeLab.initialize() first
}
else -> {
Log.e("Ad", "Error ${error.code}: ${error.message}")
}
}
}
Error Codes
| Code | Type | Description |
|---|---|---|
| 1001 | NetworkError | Network connectivity or HTTP error |
| 1002 | NoFill | No ad available for this placement |
| 1003 | InvalidPlacement | Invalid or unknown placement slug |
| 1004 | AdExpired | Loaded ad exceeded 1-hour TTL |
| 1005 | AdAlreadyShowing | Attempted to show while another ad is displayed |
| 1006 | NotInitialized | SDK not initialized before use |
| 1007 | ServerError | Server returned an error response |
| 1008 | Timeout | Request timed out |
| 1009 | InvalidResponse | Server response was malformed |
| 1010 | LoadInProgress | Ad load already in progress |
| 1011 | AdLoadingThrottled | Too many requests (rate limited) |
| 1099 | InternalError | Unexpected internal error |