Skip to main content

CloudX Android SDK

Maven Central

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.0.0")

    // Adapters for ad networks
    implementation("io.cloudx:adapter-cloudx:2.0.0")
    implementation("io.cloudx:adapter-meta:2.0.0")       // Meta Audience Network 6.21.0
    implementation("io.cloudx:adapter-vungle:2.0.0")     // Vungle SDK 7.6.1
    implementation("io.cloudx:adapter-inmobi:2.0.0")     // InMobi SDK 11.1.0
}

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

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}")
    }
}

Ad Information (CloudXAd)

The CloudXAd object is passed to listener callbacks and contains information about the loaded/displayed ad:
PropertyTypeDescription
adFormatCloudXAdFormatAd format (BANNER, MREC, INTERSTITIAL, REWARDED)
adUnitIdStringThe ad unit ID
networkNameStringName of the winning ad network
networkPlacementString?Network-specific placement ID
placementString?Custom placement set via setPlacement()
revenueDoubleImpression-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:
PropertyTypeDescription
codeCloudXErrorCodeError category
messageStringHuman-readable description
causeThrowable?Optional underlying exception
formattedMessageStringPre-formatted message including code and description

Error Code Categories

RangeCategoryCommon Codes
0GeneralINTERNAL_ERROR
100-199NetworkNETWORK_ERROR, NETWORK_TIMEOUT, NETWORK_SERVER_ERROR, NETWORK_NO_CONNECTION
200-299InitializationNOT_INITIALIZED, SDK_DISABLED, NO_ADAPTERS_FOUND, INVALID_APP_KEY
300-399Ad LoadingNO_FILL, INVALID_AD_UNIT, ADS_DISABLED
400-499DisplayAD_NOT_READY, AD_ALREADY_SHOWING
600-699AdapterADAPTER_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:
  1. 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)
    
  2. Copy the advertising ID and add it to your device whitelist on the CloudX server dashboard
  3. 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:
  1. EU Users (GDPR): Checks TCF v2 consent for purposes 1-4 and vendor consent (CloudX Vendor ID: 1510)
  2. US Users (CCPA): Checks for sale/sharing opt-out signals
  3. 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

KeyStandardDescription
IABGPP_HDR_GppStringGPPGlobal Privacy Platform string (modern)
IABGPP_GppSIDGPPSection IDs (e.g., “2” for EU, “7” for US-National, “8” for US-CA)
IABTCF_TCStringTCF v2GDPR consent string (legacy)
IABTCF_gdprAppliesTCF v2Whether GDPR applies (1 = yes, 0 = no)
IABUSPrivacy_StringUS PrivacyCCPA privacy string (legacy, e.g., “1YNN”)
Note: The SDK prioritizes GPP (modern standard) over legacy TCF/US Privacy strings when both are available.

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 [email protected]