> ## 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 Flutter SDK setup and core features

[![pub package](https://img.shields.io/pub/v/cloudx_flutter)](https://pub.dev/packages/cloudx_flutter)

The CloudX Flutter SDK enables monetization of your Flutter apps with banner, MREC, interstitial, and rewarded ads on iOS and Android.

<Info>
  Prefer AI-assisted setup? Point your coding agent at the CloudX agent package — see [AI-assisted integration](/en/ai-integration).
</Info>

## Installation

### Requirements

These match the published package constraints on [pub.dev](https://pub.dev/packages/cloudx_flutter):

| Requirement  | Version                |
| ------------ | ---------------------- |
| **Dart SDK** | `>=2.17.1 <4.0.0`      |
| **Flutter**  | `>=3.0.0`              |
| **iOS**      | 13.0+                  |
| **Android**  | minSdk **23** (API 23) |

The **Dart** range is intentionally wide so apps on older Flutter LTS lines can add `cloudx_flutter` without upgrading the whole toolchain.

Add the SDK to your `pubspec.yaml`:

```yaml theme={null}
dependencies:
  cloudx_flutter: ^2.2.3
```

Then run:

```bash theme={null}
flutter pub get
```

### iOS Setup

Add ad network adapter pods to your `ios/Podfile`:

```ruby theme={null}
target 'Runner' do
  # ... existing config ...

  # CloudX ad network adapters (add as needed; match your native stack version)
  pod 'CloudXMetaAdapter', '~> 2.2.3'
  pod 'CloudXVungleAdapter', '~> 2.2.3'
  pod 'CloudXInMobiAdapter', '~> 2.2.3'
  pod 'CloudXMintegralAdapter', '~> 2.2.3'
  pod 'CloudXUnityAdsAdapter', '~> 2.2.3'
  pod 'CloudXRenderer', '~> 2.2.3'
end
```

Then install pods:

```bash theme={null}
cd ios && pod install
```

<Note>
  The `CloudXCore` pod is automatically included as a dependency of the `cloudx_flutter` package. You only need to add the adapter pods you want.
</Note>

#### App Transport Security

If your ads use HTTP URLs, add the following to your `ios/Runner/Info.plist`:

```xml theme={null}
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>
```

### Android Setup

Add CloudX SDK and adapter dependencies to your app module — typically `android/app/build.gradle` or `android/app/build.gradle.kts`:

```kotlin theme={null}
dependencies {
    // CloudX Android SDK (version should match cloudx_flutter’s pinned native release)
    implementation("io.cloudx:sdk:2.2.3")

    // Adapters for ad networks (add as needed)
    implementation("io.cloudx:adapter-meta:2.2.3")
    implementation("io.cloudx:adapter-vungle:2.2.3")
    implementation("io.cloudx:adapter-inmobi:2.2.3")
    implementation("io.cloudx:adapter-mintegral:2.2.3")
    implementation("io.cloudx:adapter-unityads:2.2.3")
}
```

<Note>
  At least one adapter is required for the SDK to serve ads. Remove adapter lines you do not use.
</Note>

#### Mintegral adapter and Maven repository

If you include **`io.cloudx:adapter-mintegral`**, Gradle must resolve Mintegral’s SDK from **Mintegral’s own Maven server** (not Maven Central). Add their repository in your Android Gradle **`repositories`** configuration (usually the **project-level** `build.gradle` / `build.gradle.kts`, e.g. inside `allprojects { repositories { … } }` in Flutter apps).

Full steps, Kotlin/Groovy snippets, and troubleshooting are in the **[Android integration guide — Mintegral Maven repository](/en/android/integration#mintegral-maven-repository)**.

## Initialization

Initialize the SDK before loading any ads. Typically in your main widget's `initState`:

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

// Optional: enable verbose logging (development only)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);

// Initialize with your app key
final config = await CloudX.initialize(appKey: 'YOUR_APP_KEY');
if (config != null) {
  print('CloudX initialized');
} else {
  print('CloudX init failed');
}
```

`CloudX.initialize()` returns a non-null `CloudXConfiguration` on success, or `null` on failure. The configuration object has **no properties** today—use the return value only as a success signal.

Other initialization utilities:

```dart theme={null}
final initialized = await CloudX.isInitialized();
final version = await CloudX.getVersion();
```

## Ad Integration

### Banner Ads (320x50)

Banners use the **programmatic overlay** approach — they overlay your content at a fixed screen position.

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'home_banner';

// Set up event listener
CloudX.setBannerListener(CloudXAdViewListener(
  onAdLoaded: (ad) {
    print('Banner loaded from ${ad.networkName}');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Banner failed: ${error.code} ${error.message}');
  },
  onAdClicked: (ad) {
    print('Banner clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Banner revenue: ${ad.revenue}');
  },
));

// Create and show
CloudX.createBanner(adUnitId: adUnitId, position: CloudXAdViewPosition.bottomCenter);
CloudX.showBanner(adUnitId: adUnitId);

// Hide / destroy when done
CloudX.hideBanner(adUnitId: adUnitId);
CloudX.destroyBanner(adUnitId: adUnitId);
```

Auto-refresh is enabled by default. To control it manually:

```dart theme={null}
CloudX.stopBannerAutoRefresh(adUnitId: adUnitId);
CloudX.startBannerAutoRefresh(adUnitId: adUnitId);
```

#### Banner Position

Use `CloudXAdViewPosition` to place the banner:

`topLeft`, `topCenter`, `topRight`, `centerLeft`, `centered`, `centerRight`, `bottomLeft`, `bottomCenter`, `bottomRight`

To update the position after creation:

```dart theme={null}
CloudX.updateBannerPosition(adUnitId: adUnitId, position: CloudXAdViewPosition.topCenter);
```

#### Additional Banner APIs

```dart theme={null}
CloudX.setBannerPlacement(adUnitId: adUnitId, placement: 'home_screen');
CloudX.setBannerCustomData(adUnitId: adUnitId, customData: 'custom_data');
CloudX.loadBanner(adUnitId: adUnitId); // manual reload
```

#### Banner Events

| Callback          | Type                           |
| ----------------- | ------------------------------ |
| `onAdLoaded`      | `CloudXAd`                     |
| `onAdLoadFailed`  | `String adUnitId, CloudXError` |
| `onAdClicked`     | `CloudXAd`                     |
| `onAdExpanded`    | `CloudXAd` (optional)          |
| `onAdCollapsed`   | `CloudXAd` (optional)          |
| `onAdRevenuePaid` | `CloudXAd` (optional)          |

### MREC Ads (300x250)

MRECs work identically to banners but with a 300x250 size. Use the MREC methods:

```dart theme={null}
const adUnitId = 'home_mrec';

CloudX.setMRecListener(CloudXAdViewListener(
  onAdLoaded: (ad) {
    print('MREC loaded from ${ad.networkName}');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('MREC failed: ${error.code} ${error.message}');
  },
));

CloudX.createMREC(adUnitId: adUnitId, position: CloudXAdViewPosition.centered);
CloudX.showMREC(adUnitId: adUnitId);

// Destroy when done
CloudX.destroyMREC(adUnitId: adUnitId);
```

The MREC API is identical to the Banner API — all the same methods and events are available, including `updateMRECPosition`, `setMRECPlacement`, `setMRECCustomData`, auto-refresh control, and all event listeners.

### Interstitial Ads

Full-screen ads shown at natural transition points.

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'level_complete';

// Set up event listener
CloudX.setInterstitialListener(CloudXInterstitialListener(
  onAdLoaded: (ad) {
    print('Interstitial loaded');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Interstitial load failed: ${error.code} ${error.message}');
  },
  onAdDisplayed: (ad) {
    print('Interstitial displayed');
  },
  onAdDisplayFailed: (ad, error) {
    print('Interstitial display failed: ${error.code} ${error.message}');
  },
  onAdHidden: (ad) {
    // Reload for next use
    CloudX.loadInterstitial(adUnitId: adUnitId);
  },
  onAdClicked: (ad) {
    print('Interstitial clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Revenue: ${ad.revenue}');
  },
));

// Load
CloudX.loadInterstitial(adUnitId: adUnitId);

// Show when ready (with optional placement and custom data)
final isReady = await CloudX.isInterstitialReady(adUnitId: adUnitId);
if (isReady) {
  CloudX.showInterstitial(adUnitId: adUnitId);
  // or: CloudX.showInterstitial(adUnitId: adUnitId, placement: 'placement_name', customData: 'custom_data');
}

// Destroy when done
CloudX.destroyInterstitial(adUnitId: adUnitId);
```

#### Interstitial Events

| Callback            | Type                           |
| ------------------- | ------------------------------ |
| `onAdLoaded`        | `CloudXAd`                     |
| `onAdLoadFailed`    | `String adUnitId, CloudXError` |
| `onAdDisplayed`     | `CloudXAd`                     |
| `onAdDisplayFailed` | `CloudXAd, CloudXError`        |
| `onAdClicked`       | `CloudXAd`                     |
| `onAdHidden`        | `CloudXAd`                     |
| `onAdRevenuePaid`   | `CloudXAd` (optional)          |

### Rewarded Ads

Full-screen ads that grant users a reward upon completion.

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

const adUnitId = 'rewarded_coins';

// Set up event listener
CloudX.setRewardedAdListener(CloudXRewardedListener(
  onAdLoaded: (ad) {
    print('Rewarded loaded');
  },
  onAdLoadFailed: (adUnitId, error) {
    print('Rewarded load failed: ${error.code} ${error.message}');
  },
  onAdDisplayed: (ad) {
    print('Rewarded displayed');
  },
  onAdDisplayFailed: (ad, error) {
    print('Rewarded display failed: ${error.code} ${error.message}');
  },
  onAdReceivedReward: (ad, reward) {
    print('Earned ${reward.amount} ${reward.label}');
  },
  onAdHidden: (ad) {
    // Reload for next use
    CloudX.loadRewardedAd(adUnitId: adUnitId);
  },
  onAdClicked: (ad) {
    print('Rewarded clicked');
  },
  onAdRevenuePaid: (ad) {
    print('Revenue: ${ad.revenue}');
  },
));

// Load
CloudX.loadRewardedAd(adUnitId: adUnitId);

// Show when ready (with optional placement and custom data)
final isReady = await CloudX.isRewardedAdReady(adUnitId: adUnitId);
if (isReady) {
  CloudX.showRewardedAd(adUnitId: adUnitId);
  // or: CloudX.showRewardedAd(adUnitId: adUnitId, placement: 'placement_name', customData: 'custom_data');
}

// Destroy when done
CloudX.destroyRewardedAd(adUnitId: adUnitId);
```

#### Rewarded Events

| Callback             | Type                           |
| -------------------- | ------------------------------ |
| `onAdLoaded`         | `CloudXAd`                     |
| `onAdLoadFailed`     | `String adUnitId, CloudXError` |
| `onAdDisplayed`      | `CloudXAd`                     |
| `onAdDisplayFailed`  | `CloudXAd, CloudXError`        |
| `onAdClicked`        | `CloudXAd`                     |
| `onAdHidden`         | `CloudXAd`                     |
| `onAdReceivedReward` | `CloudXAd, CloudXReward`       |
| `onAdRevenuePaid`    | `CloudXAd` (optional)          |

The `CloudXReward` object contains:

* `label` — the label of the reward (e.g., "coins")
* `amount` — the reward quantity

### Widget-Based Ad Views

In addition to the programmatic overlay approach, you can embed banner and MREC ads directly in your widget tree using `CloudXAdView`:

```dart theme={null}
CloudXAdView(
  adUnitId: 'home_banner',
  adFormat: CloudXAdFormat.banner,
  listener: CloudXAdViewListener(
    onAdLoaded: (ad) => print('Widget banner loaded'),
    onAdLoadFailed: (adUnitId, error) => print('Widget banner failed'),
  ),
)
```

This uses Flutter's platform view system (`AndroidView` / `UiKitView`) to embed the native ad view inline with your Flutter widgets.

## Advanced Features

### Error Handling

All error callbacks receive a `CloudXError` with `code` and `message` properties:

| Range   | Category       | Common Codes                                                                          |
| ------- | -------------- | ------------------------------------------------------------------------------------- |
| 0       | General        | `internalError`                                                                       |
| 100-199 | Network        | `networkError`, `networkTimeout`, `networkServerError`, `networkNoConnection`         |
| 200-299 | Initialization | `notInitialized`, `noAdaptersFound`, `sdkDisabled`, `invalidAppKey`                   |
| 300-399 | Ad Loading     | `noFill`, `invalidAdUnit`, `adsDisabled`                                              |
| 400-499 | Display        | `adNotReady`, `adAlreadyShowing`, `dontKeepActivitiesEnabled`                         |
| 600-699 | Adapter        | `adapterNoFill`, `adapterLoadTimeout`, `adapterTimeout`, `adapterInitializationError` |

See `CloudXErrorCode` for the full list of error codes.

### Revenue Tracking

All ad formats provide revenue callbacks. `CloudXAd` includes `adUnitId`, `adFormat`, `networkName`, `revenue` (USD), optional `placement`, and optional `networkPlacement`:

```dart theme={null}
CloudX.setInterstitialListener(CloudXInterstitialListener(
  onAdRevenuePaid: (ad) {
    trackRevenue(ad.revenue, ad.networkName, ad.adUnitId);
  },
  // ... other callbacks
));
```

### User Targeting

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

// Set hashed user ID (pass null to clear)
CloudX.setHashedUserId('hashed-user-id');

// Set custom key-value pairs
CloudX.setUserKeyValue('age_group', '25-34');
CloudX.setAppKeyValue('app_version', '1.0.0');

// Clear all custom key-values
CloudX.clearAllKeyValues();
```

The hashed user ID is a publisher-provided pseudonymous identifier. When applicable privacy signals allow it, CloudX captures the value at auction time and returns it as `hashed_user_id` in the [impression-level revenue export](/en/cli/reporting#cloudx-report-impressions-export). Use it to join CloudX revenue to cohorts in your own user data. The export value is empty when no ID was set, persistence was suppressed by privacy signals, or the value exceeded 128 characters. Do not pass raw personal data.

### Privacy Compliance

Reads IAB GPP, TCF v2, and US Privacy strings from `NSUserDefaults` / `SharedPreferences` (typically set by a CMP).

| Key                    | Standard   | Description                    |
| ---------------------- | ---------- | ------------------------------ |
| `IABGPP_HDR_GppString` | GPP        | Global Privacy Platform string |
| `IABGPP_GppSID`        | GPP        | Section IDs                    |
| `IABTCF_TCString`      | TCF v2     | GDPR consent string            |
| `IABUSPrivacy_String`  | US Privacy | CCPA string                    |

**Manual APIs:** `CloudX.setHasUserConsent(bool?)` and `CloudX.setDoNotSell(bool?)` when you do not use a CMP, or to override until cleared. **`null`** removes the override; resolution order matches the native SDK (stored IAB strings and these overrides). Callable before **`CloudX.initialize()`**.

```dart theme={null}
CloudX.setHasUserConsent(true);
CloudX.setDoNotSell(false);
CloudX.setHasUserConsent(null);
```

### Test Mode

Test mode is **server-controlled** via device whitelisting:

1. Initialize the SDK with verbose logging enabled
2. Find your device advertising ID in the console logs
3. Add the device to your whitelist on the CloudX dashboard

### Debug Logging

```dart theme={null}
import 'package:cloudx_flutter/cloudx.dart';

// Enable verbose logging (call before initialize)
CloudX.setMinLogLevel(CloudXLogLevel.verbose);

// Available levels: verbose, debug, info, warn, error, none
```

### Visual Debugging

Enable visual debugging overlays to see ad unit boundaries and network info (iOS only):

```dart theme={null}
CloudX.setVisualDebuggingEnabled(true);
```

## Support

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