CloudX Android SDK
Automated Integration with Claude Code
Integrate CloudX SDK in 15 minutes with AI-powered agents:
Requires Claude Code.
# Install CloudX agents
bash <(curl -fsSL https://raw.githubusercontent.com/cloudx-io/cloudx-sdk-agents/main/scripts/install.sh)
# In your Android project:
claude "Use @agent-cloudx-android-integrator to integrate CloudX SDK with app key: YOUR_KEY"
- First-look CloudX with automatic fallback to existing ad setup
- Privacy compliance validation (GDPR, CCPA)
- Build verification catches errors early
- Preserves existing ad setup as backup
Full Setup Guide
Manual Installation
Requires Android API 23+ and Java 8+.
Add the CloudX SDK to your app’s build.gradle:
dependencies {
implementation("io.cloudx:sdk:2.2.3")
// Adapters for ad networks
implementation("io.cloudx:adapter-meta:2.2.3") // Meta Audience Network 6.20.0
implementation("io.cloudx:adapter-vungle:2.2.3") // Vungle SDK 7.7.1
implementation("io.cloudx:adapter-inmobi:2.2.3") // InMobi SDK 11.1.1
implementation("io.cloudx:adapter-mintegral:2.2.3") // Mintegral SDK 17.0.91
implementation("io.cloudx:adapter-unityads:2.2.3") // Unity Ads SDK 4.17.0
}
Bidder Network Guides
Use the bidder guides for network-side account setup and CloudX dashboard mapping:
This page focuses on SDK installation, initialization, and ad loading.
Mintegral Maven repository
If you add io.cloudx:adapter-mintegral to your dependencies, Gradle must also resolve Mintegral’s mediation SDK artifacts (for example com.mbridge.msdk.oversea:mbridge_android_sdk). Those artifacts are hosted on Mintegral’s Maven repository, not Maven Central. google() and mavenCentral() alone are not enough — builds fail with an error such as Could not find com.mbridge.msdk.oversea:mbridge_android_sdk until this repository is declared.
Add the repository next to your other Maven repos (typical locations: root build.gradle / build.gradle.kts inside allprojects { repositories { … } }, or dependencyResolutionManagement.repositories in settings.gradle, depending on your Gradle template):
maven {
url = uri("https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea")
}
Use the same adapter version as your other io.cloudx:adapter-* lines (for example implementation("io.cloudx:adapter-mintegral:2.2.3") when your CloudX stack is on 2.2.3).
Initialization
// Initialize with app key
CloudX.initialize(
configuration = CloudXInitializationConfiguration.builder("your-app-key-here")
.build(),
listener = object : CloudXInitializationListener {
override fun onInitialized(configuration: CloudXSdkConfiguration) {
Log.d("CloudX", "CloudX SDK initialized successfully")
}
override fun onInitializationFailed(cloudXError: CloudXError) {
Log.e("CloudX", "Failed to initialize CloudX SDK: ${cloudXError.message}")
}
}
)
Ad Integration
Banner Ads (320x50)
class MainActivity : AppCompatActivity(), CloudXAdViewListener, CloudXAdRevenueListener {
private lateinit var bannerAd: CloudXAdView
private fun createBannerAd() {
bannerAd = CloudX.createBanner("your-banner-ad-unit-id")
bannerAd.listener = this
bannerAd.revenueListener = this
val layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
layoutParams.gravity = Gravity.CENTER_HORIZONTAL
findViewById<LinearLayout>(R.id.banner_container).addView(bannerAd, layoutParams)
}
override fun onDestroy() {
super.onDestroy()
bannerAd.destroy()
}
// CloudXAdViewListener callbacks
override fun onAdLoaded(cloudXAd: CloudXAd) {
Log.d("CloudX", "Banner ad loaded from ${cloudXAd.networkName}")
}
override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
Log.e("CloudX", "Banner ad failed to load: ${cloudXError.message}")
}
override fun onAdClicked(cloudXAd: CloudXAd) {
Log.d("CloudX", "Banner ad clicked")
}
override fun onAdExpanded(cloudXAd: CloudXAd) {
Log.d("CloudX", "Banner ad expanded")
}
override fun onAdCollapsed(cloudXAd: CloudXAd) {
Log.d("CloudX", "Banner ad collapsed")
}
// CloudXAdRevenueListener callback
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
Log.d("CloudX", "Banner revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
}
}
Banner ads auto-refresh by default. To control refresh manually:
bannerAd.stopAutoRefresh() // Stop auto-refresh
bannerAd.load() // Manually load a new ad
bannerAd.startAutoRefresh() // Re-enable auto-refresh
Optional placement and custom data for tracking:
bannerAd.setPlacement("home_screen")
bannerAd.setCustomData("level:5,coins:100")
MREC Ads (300x250)
class MainActivity : AppCompatActivity(), CloudXAdViewListener, CloudXAdRevenueListener {
private lateinit var mrecAd: CloudXAdView
private fun createMrecAd() {
mrecAd = CloudX.createMREC("your-mrec-ad-unit-id")
mrecAd.listener = this
mrecAd.revenueListener = this
val layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
layoutParams.gravity = Gravity.CENTER_HORIZONTAL
findViewById<LinearLayout>(R.id.mrec_container).addView(mrecAd, layoutParams)
}
override fun onDestroy() {
super.onDestroy()
mrecAd.destroy()
}
// CloudXAdViewListener callbacks (same as Banner)
override fun onAdLoaded(cloudXAd: CloudXAd) {
Log.d("CloudX", "MREC ad loaded from ${cloudXAd.networkName}")
}
override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
Log.e("CloudX", "MREC ad failed to load: ${cloudXError.message}")
}
override fun onAdClicked(cloudXAd: CloudXAd) {
Log.d("CloudX", "MREC ad clicked")
}
override fun onAdExpanded(cloudXAd: CloudXAd) {
Log.d("CloudX", "MREC ad expanded")
}
override fun onAdCollapsed(cloudXAd: CloudXAd) {
Log.d("CloudX", "MREC ad collapsed")
}
// CloudXAdRevenueListener callback
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
Log.d("CloudX", "MREC revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
}
}
MREC ads also auto-refresh by default. Use the same refresh control methods as Banner ads.
Interstitial Ads
class MainActivity : AppCompatActivity(), CloudXInterstitialListener, CloudXAdRevenueListener {
private lateinit var interstitialAd: CloudXInterstitialAd
private fun createInterstitialAd() {
interstitialAd = CloudX.createInterstitial("your-interstitial-ad-unit-id")
interstitialAd.listener = this
interstitialAd.revenueListener = this
interstitialAd.load()
}
private fun showInterstitialAd() {
if (interstitialAd.isAdReady) {
// Basic show
interstitialAd.show(this)
// Or with optional placement and custom data for tracking
// interstitialAd.show(this, "level_complete", "level:5,score:1000")
} else {
Log.w("CloudX", "Interstitial ad not ready yet")
}
}
override fun onDestroy() {
super.onDestroy()
interstitialAd.destroy()
}
// CloudXInterstitialListener callbacks
override fun onAdLoaded(cloudXAd: CloudXAd) {
Log.d("CloudX", "Interstitial ad loaded from ${cloudXAd.networkName}")
}
override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
Log.e("CloudX", "Interstitial ad failed to load: ${cloudXError.message}")
}
override fun onAdDisplayed(cloudXAd: CloudXAd) {
Log.d("CloudX", "Interstitial ad displayed")
}
override fun onAdDisplayFailed(cloudXAd: CloudXAd, cloudXError: CloudXError) {
Log.e("CloudX", "Interstitial ad failed to display: ${cloudXError.message}")
}
override fun onAdHidden(cloudXAd: CloudXAd) {
Log.d("CloudX", "Interstitial ad hidden")
// Reload for next use
interstitialAd.load()
}
override fun onAdClicked(cloudXAd: CloudXAd) {
Log.d("CloudX", "Interstitial ad clicked")
}
// CloudXAdRevenueListener callback
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
Log.d("CloudX", "Interstitial revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
}
}
Rewarded Ads
class MainActivity : AppCompatActivity(), CloudXRewardedListener, CloudXAdRevenueListener {
private lateinit var rewardedAd: CloudXRewardedAd
private fun createRewardedAd() {
rewardedAd = CloudX.createRewarded("your-rewarded-ad-unit-id")
rewardedAd.listener = this
rewardedAd.revenueListener = this
rewardedAd.load()
}
private fun showRewardedAd() {
if (rewardedAd.isAdReady) {
// Basic show
rewardedAd.show(this)
// Or with optional placement and custom data for tracking
// rewardedAd.show(this, "bonus_coins", "level:5,coins:100")
} else {
Log.w("CloudX", "Rewarded ad not ready yet")
}
}
override fun onDestroy() {
super.onDestroy()
rewardedAd.destroy()
}
// CloudXRewardedListener callbacks
override fun onAdLoaded(cloudXAd: CloudXAd) {
Log.d("CloudX", "Rewarded ad loaded from ${cloudXAd.networkName}")
}
override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
Log.e("CloudX", "Rewarded ad failed to load: ${cloudXError.message}")
}
override fun onAdDisplayed(cloudXAd: CloudXAd) {
Log.d("CloudX", "Rewarded ad displayed")
}
override fun onAdDisplayFailed(cloudXAd: CloudXAd, cloudXError: CloudXError) {
Log.e("CloudX", "Rewarded ad failed to display: ${cloudXError.message}")
}
override fun onAdHidden(cloudXAd: CloudXAd) {
Log.d("CloudX", "Rewarded ad hidden")
// Reload for next use
rewardedAd.load()
}
override fun onAdClicked(cloudXAd: CloudXAd) {
Log.d("CloudX", "Rewarded ad clicked")
}
override fun onUserRewarded(cloudXAd: CloudXAd, reward: CloudXReward) {
Log.d("CloudX", "User rewarded: ${reward.amount} ${reward.label}")
// Grant the reward to the user
}
// CloudXAdRevenueListener callback
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
Log.d("CloudX", "Rewarded revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
}
}
The CloudXAd object is passed to listener callbacks and contains information about the loaded/displayed ad:
| Property | Type | Description |
|---|
adFormat | CloudXAdFormat | Ad format (BANNER, MREC, INTERSTITIAL, REWARDED) |
adUnitId | String | The ad unit ID |
networkName | String | Name of the winning ad network |
networkPlacement | String? | Network-specific placement ID |
placement | String? | Custom placement set via setPlacement() |
revenue | Double | Impression-level revenue in USD |
override fun onAdLoaded(cloudXAd: CloudXAd) {
Log.d("CloudX", "Ad format: ${cloudXAd.adFormat}")
Log.d("CloudX", "Network: ${cloudXAd.networkName}")
Log.d("CloudX", "Revenue: ${cloudXAd.revenue}")
}
Error Handling
All SDK errors are returned as CloudXError objects in listener callbacks:
| Property | Type | Description |
|---|
code | CloudXErrorCode | Error category |
message | String | Human-readable description |
cause | Throwable? | Optional underlying exception |
formattedMessage | String | Pre-formatted message including code and description |
Error Code Categories
| Range | Category | Common Codes |
|---|
| 0 | General | INTERNAL_ERROR |
| 100-199 | Network | NETWORK_ERROR, NETWORK_TIMEOUT, NETWORK_SERVER_ERROR, NETWORK_NO_CONNECTION |
| 200-299 | Initialization | NOT_INITIALIZED, SDK_DISABLED, NO_ADAPTERS_FOUND, INVALID_APP_KEY |
| 300-399 | Ad Loading | NO_FILL, INVALID_AD_UNIT, ADS_DISABLED |
| 400-499 | Display | AD_NOT_READY, AD_ALREADY_SHOWING |
| 600-699 | Adapter | ADAPTER_NO_FILL, ADAPTER_TIMEOUT, ADAPTER_LOAD_TIMEOUT, ADAPTER_INITIALIZATION_ERROR |
Advanced Features
Debug Logging
CloudX.setMinLogLevel(CloudXLogLevel.DEBUG) // Enable debug logging
CloudX.setMinLogLevel(CloudXLogLevel.NONE) // Disable all logging
Log Levels: VERBOSE < DEBUG < INFO < WARN < ERROR < NONE
Filter logcat with tag CloudX to see SDK logs.
Impression-Level Revenue Tracking
Set a revenueListener on any ad format to receive impression-level revenue (ILR) callbacks. The CloudXAd object contains the revenue value in USD and the winning network name.
bannerAd.revenueListener = object : CloudXAdRevenueListener {
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
Log.d("CloudX", "Revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
}
}
Works with all ad formats (banner, MREC, interstitial, rewarded).
Test Mode
Test mode is server-controlled via device whitelisting. This provides better security and control over which devices receive test ads.
To enable test mode:
-
Initialize the SDK and check logcat for your device advertising ID:
[CloudX][AdvertisingIdProvider] Device IFA for test whitelisting: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (LAT: false)
-
Copy the advertising ID and add it to your device whitelist on the CloudX server dashboard
-
The SDK will automatically configure adapters for test mode and include the test flag in bid requests
Note: Test mode is determined by the server, so you don’t need to change any code between development and production builds.
Privacy Compliance
The CloudX SDK supports GDPR and CCPA privacy compliance by reading standard IAB privacy strings from SharedPreferences. These values are typically set automatically by your Consent Management Platform (CMP) such as Google UMP, OneTrust, or Sourcepoint.
How It Works
The SDK automatically detects user location and reads consent signals:
- EU Users (GDPR): Checks TCF v2 consent for purposes 1-4 and vendor consent (CloudX Vendor ID: 1510)
- US Users (CCPA): Checks for sale/sharing opt-out signals
- Other Regions: No restrictions applied
When consent is denied or user opts out, the SDK removes PII from ad requests:
- Advertising ID (GAID) is cleared
- Geo coordinates (lat/lon) are removed
- User key-values are not sent
- Hashed user ID is excluded
Supported Privacy Keys
| Key | Standard | Description |
|---|
IABGPP_HDR_GppString | GPP | Global Privacy Platform string (modern) |
IABGPP_GppSID | GPP | Section IDs (e.g., “2” for EU, “7” for US-National, “8” for US-CA) |
IABTCF_TCString | TCF v2 | GDPR consent string (legacy) |
IABTCF_gdprApplies | TCF v2 | Whether GDPR applies (1 = yes, 0 = no) |
IABUSPrivacy_String | US Privacy | CCPA privacy string (legacy, e.g., “1YNN”) |
Note: The SDK prioritizes GPP (modern standard) over legacy TCF/US Privacy strings when both are available.
Manual Privacy API
If you manage user consent yourself (without a CMP), you can set GDPR and CCPA privacy status directly. These can be called before or after SDK initialization.
// GDPR consent: true, false, or null to defer to CMP
CloudX.setHasUserConsent(true)
// CCPA do-not-sell: true, false, or null to defer to CMP
CloudX.setDoNotSell(true)
When both manual values and CMP signals are present, CMP signals (GPP/TCF/US Privacy) take priority. Manual values act as a fallback when no CMP is integrated.
User Targeting
// Set hashed user ID for targeting
CloudX.setHashedUserId("hashed-user-id")
// Set custom user key-value pairs
CloudX.setUserKeyValue("age", "25")
CloudX.setUserKeyValue("gender", "male")
CloudX.setUserKeyValue("location", "US")
// Set custom app key-value pairs
CloudX.setAppKeyValue("app_version", "1.0.0")
CloudX.setAppKeyValue("user_level", "premium")
// Clear all custom key-values
CloudX.clearAllKeyValues()
Support
For support, contact mobile@cloudx.io