> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloudx.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Overview of CloudX Android SDK setup and core features

[![Maven Central](https://img.shields.io/maven-central/v/io.cloudx/sdk)](https://central.sonatype.com/artifact/io.cloudx/sdk)

## Automated Integration with Claude Code

**Integrate CloudX SDK in 15 minutes with AI-powered agents:**

Requires [Claude Code](https://claude.ai/code).

```bash theme={null}
# 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](https://github.com/cloudx-io/cloudx-sdk-agents)**

## Manual Installation

Requires Android API 23+ and Java 8+.

The CloudX SDK and its adapters are published to Maven Central (`https://repo1.maven.org/maven2/`). Make sure your project resolves from it in `settings.gradle.kts`:

```kotlin theme={null}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()   // https://repo1.maven.org/maven2/
    }
}
```

Then add the CloudX SDK to your app's build.gradle:

<CodeGroup>
  ```kotlin Kotlin DSL theme={null}
  dependencies {
      implementation("io.cloudx:sdk:4.4.0")

      // Adapters for ad networks
      implementation("io.cloudx:adapter-digitalturbine:8.4.6.0")     // Digital Turbine Marketplace SDK 8.4.6
      implementation("io.cloudx:adapter-googlewaterfall:25.2.0.1")   // Google Mobile Ads SDK 25.2.0
      implementation("io.cloudx:adapter-inmobi:11.4.0.1")            // InMobi SDK 11.4.0
      implementation("io.cloudx:adapter-magnite:1.0.0.1")            // Magnite Ads SDK 1.0.0
      implementation("io.cloudx:adapter-meta:6.21.0.3")              // Meta Audience Network 6.21.0
      implementation("io.cloudx:adapter-mintegral:17.1.61.2")        // Mintegral SDK 17.1.61
      implementation("io.cloudx:adapter-mobilefuse:1.11.0.1")        // MobileFuse SDK 1.11.0
      implementation("io.cloudx:adapter-moloco:4.10.1.0")            // Moloco SDK 4.10.1
      implementation("io.cloudx:adapter-pangle:8.1.0.5.0")           // Pangle SDK 8.1.0.5
      implementation("io.cloudx:adapter-taurusx:1.18.3.0")           // TaurusX SDK 1.18.3
      implementation("io.cloudx:adapter-unityads:4.19.0.1")          // Unity Ads SDK 4.19.0
      implementation("io.cloudx:adapter-verve:3.9.0.1")              // Verve HyBid SDK 3.9.0
      implementation("io.cloudx:adapter-vungle:7.7.7.0")             // Vungle SDK 7.7.7
  }
  ```

  ```groovy Groovy theme={null}
  dependencies {
      implementation 'io.cloudx:sdk:4.4.0'

      // Adapters for ad networks
      implementation 'io.cloudx:adapter-digitalturbine:8.4.6.0'     // Digital Turbine Marketplace SDK 8.4.6
      implementation 'io.cloudx:adapter-googlewaterfall:25.2.0.1'   // Google Mobile Ads SDK 25.2.0
      implementation 'io.cloudx:adapter-inmobi:11.4.0.1'            // InMobi SDK 11.4.0
      implementation 'io.cloudx:adapter-magnite:1.0.0.1'            // Magnite Ads SDK 1.0.0
      implementation 'io.cloudx:adapter-meta:6.21.0.3'              // Meta Audience Network 6.21.0
      implementation 'io.cloudx:adapter-mintegral:17.1.61.2'        // Mintegral SDK 17.1.61
      implementation 'io.cloudx:adapter-mobilefuse:1.11.0.1'        // MobileFuse SDK 1.11.0
      implementation 'io.cloudx:adapter-moloco:4.10.1.0'            // Moloco SDK 4.10.1
      implementation 'io.cloudx:adapter-pangle:8.1.0.5.0'           // Pangle SDK 8.1.0.5
      implementation 'io.cloudx:adapter-taurusx:1.18.3.0'           // TaurusX SDK 1.18.3
      implementation 'io.cloudx:adapter-unityads:4.19.0.1'          // Unity Ads SDK 4.19.0
      implementation 'io.cloudx:adapter-verve:3.9.0.1'              // Verve HyBid SDK 3.9.0
      implementation 'io.cloudx:adapter-vungle:7.7.7.0'             // Vungle SDK 7.7.7
  }
  ```
</CodeGroup>

## Initialization

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // 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}")
          }
      }
  )
  ```

  ```java Java theme={null}
  // Initialize with app key
  CloudXInitializationConfiguration configuration = CloudXInitializationConfiguration.builder("your-app-key-here")
      .build();

  CloudX.initialize(configuration, new CloudXInitializationListener() {
      @Override
      public void onInitialized(@NonNull CloudXSdkConfiguration configuration) {
          Log.d("CloudX", "CloudX SDK initialized successfully");
      }

      @Override
      public void onInitializationFailed(@NonNull CloudXError cloudXError) {
          Log.e("CloudX", "Failed to initialize CloudX SDK: " + cloudXError.getMessage());
      }
  });
  ```
</CodeGroup>

## Ad Formats

CloudX supports banner, MREC, interstitial, rewarded, native, and App Open ad integrations. Use the format-specific guides for implementation details:

<CardGroup cols={2}>
  <Card title="Banner & MREC ads" href="/en/android/ad-formats/banner-mrec">
    Create fixed-size display placements with optional refresh control.
  </Card>

  <Card title="Interstitial ads" href="/en/android/ad-formats/interstitial">
    Load and show full-screen interstitial placements.
  </Card>

  <Card title="Native ads" href="/en/android/ad-formats/native">
    Render native creatives in custom app layouts.
  </Card>

  <Card title="Rewarded ads" href="/en/android/ad-formats/rewarded">
    Reward users after completed rewarded ad views.
  </Card>

  <Card title="App Open ads" href="/en/android/ad-formats/app-open">
    Show fullscreen ads at natural app-open or app-resume moments.
  </Card>
</CardGroup>

### Ad Information (CloudXAd)

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, NATIVE, APP\_OPEN) |
| `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`              | Bid-time revenue estimate in USD                                    |
| `adValues`         | `Map<String, String>` | SDK-provided ad metadata, used by features such as Trusted Arbiter  |

```kotlin theme={null}
override fun onAdLoaded(cloudXAd: CloudXAd) {
    Log.d("CloudX", "Ad format: ${cloudXAd.adFormat}")
    Log.d("CloudX", "Network: ${cloudXAd.networkName}")
    Log.d("CloudX", "Bid-time 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

<CodeGroup>
  ```kotlin Kotlin theme={null}
  CloudX.setMinLogLevel(CloudXLogLevel.DEBUG)  // Enable debug logging
  CloudX.setMinLogLevel(CloudXLogLevel.NONE)   // Disable all logging
  ```

  ```java Java theme={null}
  CloudX.setMinLogLevel(CloudXLogLevel.DEBUG);  // Enable debug logging
  CloudX.setMinLogLevel(CloudXLogLevel.NONE);   // Disable all logging
  ```
</CodeGroup>

**Log Levels:** `VERBOSE` \< `DEBUG` \< `INFO` \< `WARN` \< `ERROR` \< `NONE`

Filter logcat with tag `CloudX` to see SDK logs.

### Publisher-Reported Revenue Data

If your app receives impression-level revenue callbacks or bid metadata from AdMob, InMobi, TopOn, or another mediation platform outside the CloudX ad flow, forward those events to CloudX after initialization:

| Field                     | Required | Description                                                                                                                                   |
| ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `platform`                | Yes      | `CloudXRevenuePlatform.ADMOB`, `CloudXRevenuePlatform.INMOBI`, `CloudXRevenuePlatform.TOPON`, or `CloudXRevenuePlatform.custom("MyProvider")` |
| `revenue`                 | Yes      | Revenue for one impression in the supplied currency, not CPM/eCPM                                                                             |
| `adFormat`                | Yes      | Ad format string such as `banner`, `mrec`, `interstitial`, `rewarded`, `native`, or `app_open`                                                |
| `currencyCode`            | No       | ISO 4217 currency code, if known                                                                                                              |
| `precision`               | No       | `CloudXRevenuePrecision.EXACT`, `ESTIMATED`, `PUBLISHER_DEFINED`, or `UNDEFINED`                                                              |
| `networkName`             | No       | Winning ad network name, if known                                                                                                             |
| `adUnitId`                | No       | Mediation-platform ad unit ID                                                                                                                 |
| `thirdPartyAdPlacementId` | No       | Network-side ad unit or placement ID                                                                                                          |
| `creativeId`              | No       | Creative ID from the ad network                                                                                                               |
| `networkPlacement`        | No       | Network placement identifier                                                                                                                  |
| `countryCode`             | No       | User country code, if known                                                                                                                   |
| `userSegment`             | No       | User segment, if known                                                                                                                        |

`reportRevenueData()` returns `true` when the event is accepted into the CloudX revenue pipeline. It returns `false` if the SDK is not initialized, server-side revenue tracking is disabled, or the platform name is blank. Acceptance is not a delivery guarantee.

#### AdMob paid events

AdMob Android `AdValue.valueMicros` is reported in micro-units of the supplied currency, so divide it by `1_000_000.0` before passing it to CloudX.

```kotlin theme={null}
private fun Int.toCloudXRevenuePrecision(): CloudXRevenuePrecision = when (this) {
    AdValue.PrecisionType.PRECISE -> CloudXRevenuePrecision.EXACT
    AdValue.PrecisionType.ESTIMATED -> CloudXRevenuePrecision.ESTIMATED
    AdValue.PrecisionType.PUBLISHER_PROVIDED -> CloudXRevenuePrecision.PUBLISHER_DEFINED
    else -> CloudXRevenuePrecision.UNDEFINED
}

private fun reportAdMobPaidEvent(
    adValue: AdValue,
    adFormat: String,
    adUnitId: String,
    responseInfo: ResponseInfo?,
): Boolean {
    val servedBy = responseInfo?.loadedAdapterResponseInfo

    return CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.ADMOB,
            revenue = adValue.valueMicros / 1_000_000.0,
            adFormat = adFormat,
        )
            .currencyCode(adValue.currencyCode)
            .precision(adValue.precisionType.toCloudXRevenuePrecision())
            .networkName(servedBy?.adSourceName)
            .adUnitId(adUnitId)
            .thirdPartyAdPlacementId(servedBy?.adSourceInstanceName)
            .build(),
    )
}

bannerView.setOnPaidEventListener { adValue ->
    reportAdMobPaidEvent(
        adValue = adValue,
        adFormat = "banner",
        adUnitId = adUnitId,
        responseInfo = bannerView.responseInfo,
    )
}
```

#### InMobi impression events

For InMobi, save the `AdMetaInfo` object from `onAdFetchSuccessful`. When `onAdImpression` fires, send the saved `metaInfo.bid` to CloudX, then clear the saved value.

```kotlin theme={null}
private var latestInMobiMetaInfo: AdMetaInfo? = null

override fun onAdFetchSuccessful(ad: InMobiBanner, info: AdMetaInfo) {
    latestInMobiMetaInfo = info
}

override fun onAdImpression(ad: InMobiBanner) {
    latestInMobiMetaInfo?.let { metaInfo ->
        reportInMobiImpression(
            metaInfo = metaInfo,
            adFormat = "banner",
            placementId = inMobiPlacementId.toString(),
        )
    }
    latestInMobiMetaInfo = null
}

private fun reportInMobiImpression(
    metaInfo: AdMetaInfo,
    adFormat: String,
    placementId: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.INMOBI,
            revenue = metaInfo.bid,
            adFormat = adFormat,
        )
            .precision(CloudXRevenuePrecision.ESTIMATED)
            .thirdPartyAdPlacementId(placementId)
            .creativeId(metaInfo.creativeID)
            .build(),
    )
```

For interstitial and rewarded InMobi ads, use the same pattern with `InterstitialAdEventListener`: save `AdMetaInfo` in `onAdFetchSuccessful`, then report it in `onAdImpression`.

#### TopOn revenue events

TopOn Android reports revenue in `onAdRevenuePaid(ATAdInfo)`. Set an `ATAdRevenueListener` on the ad object and pass `adInfo.getPublisherRevenue()` directly to CloudX. Do not divide this value like AdMob micros or CPM.

```kotlin theme={null}
private fun reportTopOnRevenue(
    adInfo: ATAdInfo,
    adFormat: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.TOPON,
            revenue = adInfo.getPublisherRevenue(),
            adFormat = adFormat,
        )
            .currencyCode(adInfo.getCurrency())
            .networkName(adInfo.getNetworkName())
            .adUnitId(adInfo.getPlacementId())
            .thirdPartyAdPlacementId(adInfo.getNetworkPlacementId())
            .networkPlacement(adInfo.getAdsourceId())
            .build(),
    )

mBannerView.setAdRevenueListener(object : ATAdRevenueListener {
    override fun onAdRevenuePaid(adInfo: ATAdInfo) {
        reportTopOnRevenue(
            adInfo = adInfo,
            adFormat = "banner",
        )
    }
})
```

For other TopOn ad formats, set the same listener on the loaded ad object and pass the matching CloudX `adFormat`.

#### Custom platform events

Use `custom` for providers that do not have a CloudX SDK constant like AdMob, InMobi, and TopOn do. The value is only the provider name, such as `CloudXRevenuePlatform.custom("TradPlus")` or `CloudXRevenuePlatform.custom("Nimbus")`. Keep the name stable so CloudX can group that provider's revenue consistently.

Do not include the amount or currency in the provider name. For a TradPlus impression worth USD 0.01, send `platform = CloudXRevenuePlatform.custom("TradPlus")`, `revenue = 0.01`, and `.currencyCode("USD")`. If your source reports CPM/eCPM, divide by `1_000.0` first.

```kotlin theme={null}
private fun reportCustomRevenueEvent(
    providerName: String,
    revenue: Double,
    adFormat: String,
    currencyCode: String,
    adUnitId: String,
    placementId: String,
): Boolean =
    CloudX.reportRevenueData(
        CloudXRevenueData.builder(
            platform = CloudXRevenuePlatform.custom(providerName),
            revenue = revenue,
            adFormat = adFormat,
        )
            .currencyCode(currencyCode)
            .precision(CloudXRevenuePrecision.PUBLISHER_DEFINED)
            .adUnitId(adUnitId)
            .thirdPartyAdPlacementId(placementId)
            .build(),
    )
```

### Impression-Level Revenue Tracking

Set a `revenueListener` on any ad format to receive revenue callbacks. `CloudXAd.revenue` contains the bid-time USD estimate.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  bannerAd.revenueListener = object : CloudXAdRevenueListener {
      override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
          Log.d("CloudX", "Bid-time revenue: ${cloudXAd.revenue} from ${cloudXAd.networkName}")
      }
  }
  ```

  ```java Java theme={null}
  bannerAd.setRevenueListener(new CloudXAdRevenueListener() {
      @Override
      public void onAdRevenuePaid(@NonNull CloudXAd cloudXAd) {
          Log.d("CloudX", "Bid-time revenue: " + cloudXAd.getRevenue() + " from " + cloudXAd.getNetworkName());
      }
  });
  ```
</CodeGroup>

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 and 2 per the [IAB Global Vendor List](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework) and vendor consent ([CloudX Vendor ID: 1510](https://vendor-list.consensu.org/v3/vendor-list.json))
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

| Key                    | Standard                                                                                          | Description                                                        |
| ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `IABGPP_HDR_GppString` | [GPP](https://github.com/InteractiveAdvertisingBureau/Global-Privacy-Platform)                    | 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](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework) | GDPR consent string (legacy)                                       |
| `IABTCF_gdprApplies`   | TCF v2                                                                                            | Whether GDPR applies (1 = yes, 0 = no)                             |
| `IABUSPrivacy_String`  | [US Privacy](https://github.com/InteractiveAdvertisingBureau/USPrivacy)                           | 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 must be called prior to SDK initialization.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // 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)
  ```

  ```java Java theme={null}
  // 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);
  ```
</CodeGroup>

<Note>
  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.
</Note>

### User Targeting

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // 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()
  ```

  ```java Java theme={null}
  // 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();
  ```
</CodeGroup>

## Support

For support, contact [mobile@cloudx.io](mailto:mobile@cloudx.io)
