Overview
Overview of CloudX iOS SDK setup and core features
Requires iOS 13.0+, Xcode 16.0+, and Swift 6.0+.
Installation
CocoaPods
platform :ios, '15.0'
target 'YourApp' do
use_frameworks!
# Core SDK
pod 'CloudXCore', '~> 3.9.1'
# Adapters for ad networks (add as needed).
# Each adapter versions independently as <network-sdk-version>.<adapter-revision>
# and is built against that exact network SDK version.
pod 'CloudXAppLovinAdapter', '~> 13.6.3.0' # AppLovinSDK 13.6.3
pod 'CloudXMetaAdapter', '~> 6.22.0.0' # FBAudienceNetwork 6.22.0
pod 'CloudXVungleAdapter', '~> 7.7.6.0' # VungleAds 7.7.6
pod 'CloudXInMobiAdapter', '~> 11.4.1.0' # InMobiSDK 11.4.1
pod 'CloudXMintegralAdapter', '~> 8.1.6.0' # MintegralAdSDK 8.1.6
pod 'CloudXUnityAdsAdapter', '~> 4.20.1.0' # UnityAds 4.20.1
pod 'CloudXMagniteAdapterV2', '~> 1.0.0.2' # MagniteSDK 1.0.0
pod 'CloudXMobileFuseAdapter', '~> 1.11.0.1' # MobileFuseSDK 1.11.0
pod 'CloudXMolocoAdapter', '~> 4.10.0.0' # MolocoSDKiOS 4.10.0
pod 'CloudXVerveAdapter', '~> 3.9.0.0' # HyBid 3.9.0
pod 'CloudXDigitalTurbineAdapter', '~> 8.4.10.0' # Fyber Marketplace SDK 8.4.10
pod 'CloudXGoogleWaterfallAdapter', '~> 13.9.0.0' # Google Mobile Ads SDK 13.9.0
pod 'CloudXPangleAdapter', '~> 8.3.0.6.0' # Ads-Global (Pangle / ByteDance) 8.3.0.6
pod 'CloudXTaurusXAdapter', '~> 1.18.2.0' # TaurusxAdsSDK 1.18.2
endpod install --repo-updateInitialization
#import <CloudXCore/CloudXCore.h>
CLXInitializationConfiguration *config =
[CLXInitializationConfiguration configurationWithAppKey:@"your-app-key-here"];
[[CloudXCore shared] initializeWithConfiguration:config completion:^(CLXSdkConfiguration *sdkConfig, CLXError * _Nullable error) {
if (sdkConfig) {
NSLog(@"CloudX SDK initialized successfully");
} else {
NSLog(@"Failed to initialize CloudX SDK: %@", error.localizedDescription);
}
}];import CloudXCore
let config = CLXInitializationConfiguration.configuration(appKey: "your-app-key-here", builderBlock: nil)
CloudXCore.shared.initialize(with: config) { sdkConfig, error in
if sdkConfig != nil {
print("CloudX SDK initialized successfully")
} else {
print("Failed to initialize CloudX SDK: \(error?.localizedDescription ?? "Unknown error")")
}
}Ad Formats
CloudX supports banner, MREC, interstitial, rewarded, native, and app open ad integrations. Use the format-specific guides for implementation details:
Banner & MREC ads
Create fixed-size display placements with optional refresh control.
Interstitial ads
Load and show full-screen interstitial placements.
Native ads
Render native creatives in custom app layouts.
Rewarded ads
Reward users after completed rewarded ad views.
App Open ads
Full-screen placements for app launch and foreground moments.
Ad Information (CLXAd)
The CLXAd object is passed to delegate callbacks and contains information about the loaded/displayed ad:
| Property | Type | Description |
|---|---|---|
adFormat | CLXAdFormat | Ad format (banner, MREC, interstitial, rewarded, native) |
adUnitId | NSString? | The ad unit ID |
adUnitName | NSString? | The ad unit name |
networkName | NSString? | Name of the winning ad network |
networkPlacement | NSString? | Network-specific placement ID |
placement | NSString? | Custom placement set via placement property |
revenue | NSNumber? | Impression-level revenue in USD |
revenuePrecision | NSString? | Revenue precision, when provided by the winning network |
creativeIdentifier | NSString? | Creative identifier for creative-level issue reporting |
requestLatency | NSTimeInterval | Time in seconds from ad request to ad response |
nativeAd | CLXNativeAd? | Native ad asset container for native ads; nil for non-native formats |
adValues | NSDictionary<NSString *, NSString *> | SDK-defined metadata for the loaded ad; values may be absent by format or network |
- (void)didLoadAd:(CLXAd *)ad {
NSLog(@"Ad format: %ld", (long)ad.adFormat);
NSLog(@"Network: %@", ad.networkName);
NSLog(@"Revenue: %@", ad.revenue);
}func didLoad(_ ad: CLXAd) {
print("Ad format: \(ad.adFormat)")
print("Network: \(ad.networkName ?? "unknown")")
print("Revenue: \(ad.revenue ?? 0)")
}Error Handling
All SDK errors are returned as CLXError objects in delegate callbacks:
| Property | Type | Description |
|---|---|---|
code | CLXErrorCode | Error category |
localizedDescription | NSString | Human-readable description |
underlyingError | NSError? | Optional underlying error |
Error Code Categories
| Range | Category | Common Codes |
|---|---|---|
| 0 | General | CLXErrorCodeInternalError |
| 100-199 | Network | CLXErrorCodeNetworkError, CLXErrorCodeNetworkTimeout, CLXErrorCodeServerError, CLXErrorCodeNoConnection |
| 200-299 | Initialization | CLXErrorCodeNotInitialized, CLXErrorCodeSDKDisabled, CLXErrorCodeNoAdaptersFound, CLXErrorCodeInvalidAppKey |
| 300-399 | Ad Loading | CLXErrorCodeNoFill, CLXErrorCodeInvalidAdUnit, CLXErrorCodeAdsDisabled |
| 400-499 | Display | CLXErrorCodeAdNotReady, CLXErrorCodeAdAlreadyShowing |
| 600-699 | Adapter | CLXErrorCodeAdapterNoFill, CLXErrorCodeAdapterTimeout, CLXErrorCodeAdapterLoadTimeout, CLXErrorCodeAdapterInitializationError |
Advanced Features
Debug Logging
[CloudXCore setMinLogLevel:CLXLogLevelDebug]; // Enable debug logging
[CloudXCore setMinLogLevel:CLXLogLevelNone]; // Disable all loggingCloudXCore.setMinLogLevel(.debug) // Enable debug logging
CloudXCore.setMinLogLevel(.none) // Disable all loggingLog Levels: verbose < debug < info < warn < error < none
Impression-Level Revenue Tracking
Set a revenueDelegate on any ad format to receive impression-level revenue (ILR) callbacks. The CLXAd object contains the revenue value in USD and the winning network name.
self.bannerAd.revenueDelegate = self;
- (void)didPayRevenueForAd:(CLXAd *)ad {
NSLog(@"Revenue: %@ from %@", ad.revenue, ad.networkName);
}bannerAd?.revenueDelegate = self
func didPayRevenue(for ad: CLXAd) {
print("Revenue: \(ad.revenue ?? 0) from \(ad.networkName ?? "unknown")")
}Works with all ad formats (banner, MREC, interstitial, rewarded, native).
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 | CLXRevenuePlatformAdMob, CLXRevenuePlatformInMobi, CLXRevenuePlatformTopOn, or CLXRevenuePlatformCustom(@"MyProvider") in Objective-C; .adMob, .inMobi, .topOn, or .custom("MyProvider") in Swift |
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 | exact, estimated, publisherDefined, 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 iOS AdValue.value is already in the supplied currency units, so pass it directly to CloudX. Do not divide it by 1_000_000.0.
static CLXRevenuePrecision *CLXRevenuePrecisionFromGAD(GADAdValuePrecision precision) {
switch (precision) {
case GADAdValuePrecisionPrecise: return CLXRevenuePrecision.exact;
case GADAdValuePrecisionEstimated: return CLXRevenuePrecision.estimated;
case GADAdValuePrecisionPublisherProvided: return CLXRevenuePrecision.publisherDefined;
case GADAdValuePrecisionUnknown: return CLXRevenuePrecision.undefined;
}
return CLXRevenuePrecision.undefined;
}
- (BOOL)reportAdMobPaidEventWithAdValue:(GADAdValue *)adValue
adFormat:(NSString *)adFormat
adUnitId:(NSString *)adUnitId
responseInfo:(GADResponseInfo *)responseInfo {
GADAdNetworkResponseInfo *servedBy = responseInfo.loadedAdNetworkResponseInfo;
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformAdMob
revenue:adValue.value.doubleValue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = adValue.currencyCode;
builder.precision = CLXRevenuePrecisionFromGAD(adValue.precision);
builder.networkName = servedBy.adSourceName;
builder.adUnitId = adUnitId;
builder.thirdPartyAdPlacementId = servedBy.adSourceInstanceName;
}];
return [[CloudXCore shared] reportRevenueData:data];
}
__weak GADBannerView *weakBannerView = bannerView;
bannerView.paidEventHandler = ^(GADAdValue *adValue) {
[self reportAdMobPaidEventWithAdValue:adValue
adFormat:@"banner"
adUnitId:adUnitId
responseInfo:weakBannerView.responseInfo];
};private func toCloudXRevenuePrecision(_ precision: AdValuePrecision) -> CLXRevenuePrecision {
switch precision {
case .precise:
return .exact
case .estimated:
return .estimated
case .publisherProvided:
return .publisherDefined
case .unknown:
return .undefined
@unknown default:
return .undefined
}
}
private func reportAdMobPaidEvent(
_ adValue: AdValue,
adFormat: String,
adUnitId: String,
responseInfo: ResponseInfo?
) -> Bool {
let servedBy = responseInfo?.loadedAdNetworkResponseInfo
let data = CLXRevenueData.revenueData(
platform: .adMob,
revenue: adValue.value.doubleValue,
adFormat: adFormat
) { builder in
builder.currencyCode = adValue.currencyCode
builder.precision = toCloudXRevenuePrecision(adValue.precision)
builder.networkName = servedBy?.adSourceName
builder.adUnitId = adUnitId
builder.thirdPartyAdPlacementId = servedBy?.adSourceInstanceName
}
return CloudXCore.shared.reportRevenueData(data)
}
bannerView.paidEventHandler = { [weak bannerView] adValue in
_ = reportAdMobPaidEvent(
adValue,
adFormat: "banner",
adUnitId: adUnitId,
responseInfo: bannerView?.responseInfo
)
}InMobi impression events
For InMobi, save the IMAdMetaInfo object from banner(_:didReceiveWithMetaInfo:). When bannerAdImpressed(_:) fires, send the saved metaInfo.getBid() to CloudX, then clear the saved value.
@property (nonatomic, strong, nullable) IMAdMetaInfo *latestInMobiMetaInfo;
- (void)banner:(IMBanner *)banner didReceiveWithMetaInfo:(IMAdMetaInfo *)info {
self.latestInMobiMetaInfo = info;
}
- (void)bannerAdImpressed:(IMBanner *)banner {
if (!self.latestInMobiMetaInfo) {
return;
}
[self reportInMobiImpressionWithMetaInfo:self.latestInMobiMetaInfo
adFormat:@"banner"
placementId:inMobiPlacementId];
self.latestInMobiMetaInfo = nil;
}
- (BOOL)reportInMobiImpressionWithMetaInfo:(IMAdMetaInfo *)metaInfo
adFormat:(NSString *)adFormat
placementId:(NSString *)placementId {
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformInMobi
revenue:[metaInfo getBid]
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.precision = CLXRevenuePrecision.estimated;
builder.thirdPartyAdPlacementId = placementId;
builder.creativeId = metaInfo.creativeID;
}];
return [[CloudXCore shared] reportRevenueData:data];
}private var latestInMobiMetaInfo: IMAdMetaInfo?
func banner(_ banner: IMBanner, didReceiveWithMetaInfo info: IMAdMetaInfo) {
latestInMobiMetaInfo = info
}
func bannerAdImpressed(_ banner: IMBanner) {
guard let metaInfo = latestInMobiMetaInfo else {
return
}
_ = reportInMobiImpression(
metaInfo,
adFormat: "banner",
placementId: inMobiPlacementId
)
latestInMobiMetaInfo = nil
}
private func reportInMobiImpression(
_ metaInfo: IMAdMetaInfo,
adFormat: String,
placementId: String
) -> Bool {
let data = CLXRevenueData.revenueData(
platform: .inMobi,
revenue: metaInfo.getBid(),
adFormat: adFormat
) { builder in
builder.precision = .estimated
builder.thirdPartyAdPlacementId = placementId
builder.creativeId = metaInfo.creativeID
}
return CloudXCore.shared.reportRevenueData(data)
}For interstitial and rewarded InMobi ads, use the same pattern with IMInterstitialDelegate: save IMAdMetaInfo in interstitial(_:didReceiveWithMetaInfo:), then report it in interstitialAdImpressed(_:).
TopOn revenue events
TopOn iOS reports revenue in didRevenueForPlacementID:extra:. Use publisher_revenue from extra as one-impression revenue and currency as the currency code.
static NSString *CLXTopOnStringValue(NSDictionary *extra, NSString *key) {
id value = extra[key];
return [value isKindOfClass:NSString.class] ? value : nil;
}
static CLXRevenuePrecision *CLXRevenuePrecisionFromTopOn(NSString *precision) {
if ([precision isEqualToString:@"exact"]) return CLXRevenuePrecision.exact;
if ([precision isEqualToString:@"estimated"]) return CLXRevenuePrecision.estimated;
if ([precision isEqualToString:@"publisher_defined"]) return CLXRevenuePrecision.publisherDefined;
return CLXRevenuePrecision.undefined;
}
- (BOOL)reportTopOnRevenueForPlacementID:(NSString *)placementID
extra:(NSDictionary *)extra
adFormat:(NSString *)adFormat {
NSNumber *revenue = extra[@"publisher_revenue"];
if (![revenue isKindOfClass:NSNumber.class]) {
return NO;
}
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformTopOn
revenue:revenue.doubleValue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = CLXTopOnStringValue(extra, @"currency");
builder.precision = CLXRevenuePrecisionFromTopOn(CLXTopOnStringValue(extra, @"precision"));
builder.networkName = CLXTopOnStringValue(extra, @"network_name");
builder.adUnitId = placementID;
builder.thirdPartyAdPlacementId = CLXTopOnStringValue(extra, @"network_placement_id");
builder.networkPlacement = CLXTopOnStringValue(extra, @"adsource_id");
builder.countryCode = CLXTopOnStringValue(extra, @"country");
}];
return [[CloudXCore shared] reportRevenueData:data];
}
- (void)didRevenueForPlacementID:(NSString *)placementID extra:(NSDictionary *)extra {
[self reportTopOnRevenueForPlacementID:placementID
extra:extra
adFormat:@"banner"];
}private func topOnRevenuePrecision(_ precision: String?) -> CLXRevenuePrecision {
switch precision {
case "exact":
return .exact
case "estimated":
return .estimated
case "publisher_defined":
return .publisherDefined
default:
return .undefined
}
}
private func reportTopOnRevenue(
placementID: String,
extra: [AnyHashable: Any],
adFormat: String
) -> Bool {
guard let revenue = (extra["publisher_revenue"] as? NSNumber)?.doubleValue else {
return false
}
let data = CLXRevenueData.revenueData(
platform: .topOn,
revenue: revenue,
adFormat: adFormat
) { builder in
builder.currencyCode = extra["currency"] as? String
builder.precision = topOnRevenuePrecision(extra["precision"] as? String)
builder.networkName = extra["network_name"] as? String
builder.adUnitId = placementID
builder.thirdPartyAdPlacementId = extra["network_placement_id"] as? String
builder.networkPlacement = extra["adsource_id"] as? String
builder.countryCode = extra["country"] as? String
}
return CloudXCore.shared.reportRevenueData(data)
}
func didRevenue(forPlacementID placementID: String, extra: [AnyHashable: Any]) {
_ = reportTopOnRevenue(
placementID: placementID,
extra: extra,
adFormat: "banner"
)
}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 CLXRevenuePlatformCustom(@"TradPlus") in Objective-C or CLXRevenuePlatform.custom("TradPlus") in Swift. 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 TradPlus, revenue 0.01, and currency code USD. If your source reports CPM/eCPM, divide by 1_000.0 first.
- (BOOL)reportCustomRevenueEventWithProviderName:(NSString *)providerName
revenue:(double)revenue
adFormat:(NSString *)adFormat
currencyCode:(NSString *)currencyCode
adUnitId:(NSString *)adUnitId
placementId:(NSString *)placementId {
CLXRevenueData *data =
[CLXRevenueData revenueDataWithPlatform:CLXRevenuePlatformCustom(providerName)
revenue:revenue
adFormat:adFormat
builderBlock:^(CLXRevenueDataBuilder *builder) {
builder.currencyCode = currencyCode;
builder.precision = CLXRevenuePrecision.publisherDefined;
builder.adUnitId = adUnitId;
builder.thirdPartyAdPlacementId = placementId;
}];
return [[CloudXCore shared] reportRevenueData:data];
}private func reportCustomRevenueEvent(
providerName: String,
revenue: Double,
adFormat: String,
currencyCode: String,
adUnitId: String,
placementId: String
) -> Bool {
let data = CLXRevenueData.revenueData(
platform: .custom(providerName),
revenue: revenue,
adFormat: adFormat
) { builder in
builder.currencyCode = currencyCode
builder.precision = .publisherDefined
builder.adUnitId = adUnitId
builder.thirdPartyAdPlacementId = placementId
}
return CloudXCore.shared.reportRevenueData(data)
}Delegate Threading
Publisher delegate callbacks are delivered on the main queue and may fire inline relative to the SDK call that triggered them. Keep delegate handlers re-entrant-safe if they call back into the SDK.
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 the logs for your device IFA:
[CloudX][INFO] Device IFA for test whitelisting: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -
Copy the IFA 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
Privacy Compliance
The CloudX SDK supports GDPR and CCPA privacy compliance by reading standard IAB privacy strings from NSUserDefaults. 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 and 2 per the IAB Global Vendor List 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 (IDFA) is cleared
- Geo coordinates (lat/lon) are removed
- User key-values are not sent
- Hashed user ID is removed from bidder-bound requests and suppressed from impression reporting
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”) |
App Tracking Transparency (ATT)
On iOS 14.5+, you must request App Tracking Transparency authorization before the SDK can access the IDFA. Request ATT permission before initializing the CloudX SDK:
#import <AppTrackingTransparency/AppTrackingTransparency.h>
if (@available(iOS 14.5, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
// Initialize CloudX SDK after ATT response
[self initializeCloudX];
}];
} else {
[self initializeCloudX];
}import AppTrackingTransparency
if #available(iOS 14.5, *) {
ATTrackingManager.requestTrackingAuthorization { status in
// Initialize CloudX SDK after ATT response
self.initializeCloudX()
}
} else {
initializeCloudX()
}Add the NSUserTrackingUsageDescription key to your Info.plist with a description of why you need tracking permission.
Manual Privacy API
If you manage user consent yourself (without a CMP), you can set GDPR and CCPA privacy status directly. Call these before initializing the SDK — some ad network SDKs require privacy settings at initialization time and will not apply values set after init.
// Set privacy BEFORE initializing the SDK
[CloudXCore setHasUserConsent:@YES];
[CloudXCore setDoNotSell:@NO];
[[CloudXCore shared] initializeWithConfiguration:config completion:completion];// Set privacy BEFORE initializing the SDK
CloudXCore.setHasUserConsent(true)
CloudXCore.setDoNotSell(false)
CloudXCore.shared.initialize(with: config) { sdkConfig, error in
// ...
}User Targeting
// Set hashed user ID for targeting
[[CloudXCore shared] setHashedUserID:@"hashed-user-id"];
// Set custom user key-value pairs (cleared by privacy regulations)
[[CloudXCore shared] setUserKeyValue:@"age" value:@"25"];
[[CloudXCore shared] setUserKeyValue:@"gender" value:@"male"];
[[CloudXCore shared] setUserKeyValue:@"location" value:@"US"];
// Set custom app key-value pairs for request targeting
[[CloudXCore shared] setAppKeyValue:@"app_version" value:@"1.0.0"];
[[CloudXCore shared] setAppKeyValue:@"user_level" value:@"premium"];
// Clear all custom key-values
[[CloudXCore shared] clearAllKeyValues];// Set hashed user ID for targeting
CloudXCore.shared.setHashedUserID("hashed-user-id")
// Set custom user key-value pairs (cleared by privacy regulations)
CloudXCore.shared.setUserKeyValue("age", value: "25")
CloudXCore.shared.setUserKeyValue("gender", value: "male")
CloudXCore.shared.setUserKeyValue("location", value: "US")
// Set custom app key-value pairs for request targeting
CloudXCore.shared.setAppKeyValue("app_version", value: "1.0.0")
CloudXCore.shared.setAppKeyValue("user_level", value: "premium")
// Clear all custom key-values
CloudXCore.shared.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 request and impression activity exports. Use auction_id to join the exports. Use the ID to join CloudX activity 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.
User and app key-values are also available in the request activity export. Use setUserKeyValue for session-wide user attributes and setAppKeyValue for session-wide app attributes. The SDK sends current values with each later auction request.
Identity passthrough
Pass UID 2.0, EUID, LiveRamp, ID5, and Intent IQ with setUserKeyValue. Set each value when you have it, and again when it refreshes.
| Key | Pass this |
|---|---|
uidapi.com | UID2 advertising token, not the refresh token. Do not decrypt it. UID2 docs |
euid.eu | EUID advertising token, not the refresh token. Do not decrypt it. EUID docs |
liveramp.com | LiveRamp ATS envelope, not a RampID. LiveRamp docs |
id5-sync.com | ID5 universal UID. Do not pass 0. ID5 docs |
intentiq.com | Intent IQ ID (IIQ ID) from your Intent IQ integration. Intent IQ docs |
CloudX does not generate these IDs. Create them with UID2, EUID, LiveRamp ATS, ID5, or Intent IQ, then pass the string. This is separate from hashed user ID.
CloudXCore.shared.setUserKeyValue("uidapi.com", value: uid2Token)
CloudXCore.shared.setUserKeyValue("euid.eu", value: euidToken)
CloudXCore.shared.setUserKeyValue("liveramp.com", value: liveRampEnvelope)
CloudXCore.shared.setUserKeyValue("id5-sync.com", value: id5Id)
CloudXCore.shared.setUserKeyValue("intentiq.com", value: intentIQId)[[CloudXCore shared] setUserKeyValue:@"uidapi.com" value:uid2Token];
[[CloudXCore shared] setUserKeyValue:@"euid.eu" value:euidToken];
[[CloudXCore shared] setUserKeyValue:@"liveramp.com" value:liveRampEnvelope];
[[CloudXCore shared] setUserKeyValue:@"id5-sync.com" value:id5Id];
[[CloudXCore shared] setUserKeyValue:@"intentiq.com" value:intentIQId];For metadata that belongs to one ad object or load, call setExtraParameter before load:
banner?.setExtraParameter("requestId", value: "request-456")
banner?.setExtraParameter("impressionKey", value: "impression-789")
banner?.load()[self.banner setExtraParameter:@"requestId" value:@"request-456"];
[self.banner setExtraParameter:@"impressionKey" value:@"impression-789"];
[self.banner load];Extra parameters remain on that ad object until changed or cleared. The SDK snapshots them for each load. CloudX returns the complete bag in the extra_parameters request-export column. The reserved tags key also controls tag-based routing; use another key for correlation metadata.
CloudX stores each of the three compact JSON bags only when the entire bag is at most 256 UTF-8 bytes. The limit is independent for each export column and includes all combined keys, values, quotes, separators, and braces—not 256 bytes per K/V pair. When privacy rules prohibit publisher-data persistence, or a bag is malformed or too large, its export cell is empty. Do not include raw personal data, secrets, or consent strings.
Support
For support, contact support@cloudx.io