You have integrated the Mintegral SDK into your AdMob mediation stack. The CPM estimates look promising, and the setup guides seemed straightforward. Yet, upon release, your dashboard tells a different story: high requests, zero impressions, and a plummeting fill rate.
If you check your device logs, you likely see the dreaded generic error: code 3: ERROR_CODE_NO_FILL or, more specifically, Adapter not found despite the dependency being present in your build.
This guide moves beyond generic setup instructions. We will debug the specific versioning conflicts between the Google Mobile Ads (GMA) SDK and Mintegral’s adapter, fix ProGuard stripping issues on Android, and resolve SKAdNetwork failures on iOS.
The Root Cause: Why Mediation Fails Silently
AdMob mediation does not simply "load" another SDK. It relies on a strict translation layer—the Mediation Adapter. This adapter implements the MediationAdapter interface provided by Google and translates Mintegral’s ad events (load, show, click) into signals AdMob understands.
The failure usually stems from one of three architectural breaks:
- Semantic Versioning Misalignment: AdMob adapters utilize a specific versioning scheme (e.g.,
16.3.41.0). The first three numbers (16.3.41) must match the Mintegral SDK version exactly. The last number (0) is the Google adapter patch version. If these drift apart, the adapter fails to instantiate class members required by the underlying SDK. - R8/ProGuard Stripping (Android): Mintegral uses reflection and dynamic class loading. If your
proguard-rules.prois not explicitly configured to keep Mintegral's internal classes, the compiler strips the code the adapter is trying to call. - Initialization Race Conditions: The Mintegral SDK must be initialized with specific App IDs and Keys before an ad request is made. If AdMob’s auto-initialization fails due to incorrect credentials in the AdMob console, the adapter remains in a dormant state.
Step 1: Enforcing Strict Version Dependency (Android)
On Android, Gradle often attempts to resolve dependencies to the newest version, which can be dangerous for mediation adapters. You must strictly pin the adapter version to the SDK version.
Check your build.gradle.kts (Kotlin DSL) or build.gradle. Do not use + or dynamic versions.
dependencies {
// 1. Core Google Mobile Ads SDK
implementation("com.google.android.gms:play-services-ads:23.0.0")
// 2. Mintegral SDK
// Ensure this version matches the adapter's base version below
implementation("com.mbridge.msdk.oversea:mbridge_sdk_android:16.7.21")
// 3. AdMob Mediation Adapter for Mintegral
// Syntax: [Mintegral SDK Version].[Adapter Patch Version]
implementation("com.google.ads.mediation:mintegral:16.7.21.0")
}
The ProGuard Fix
This is the most common reason for "Adapter not found" in release builds while debug builds work perfectly. Add the following to your proguard-rules.pro. Mintegral requires keeping specific packages to facilitate the bidirectional communication between the ad server and the client.
# Keep Mintegral SDK classes
-keep class com.mbridge.** { *; }
-keep interface com.mbridge.** { *; }
# Keep Android Support/Jetpack classes required by Mintegral
-keep class androidx.localbroadcastmanager.** { *; }
# Prevent obfuscation of JNI methods
-keepclasseswithmembernames class * {
native <methods>;
}
Step 2: iOS SKAdNetwork and Pod Compatibility
On iOS, privacy frameworks define the success of ad retrieval. If Mintegral’s SKAdNetwork ID is missing from your Info.plist, bidders (advertisers) will not bid on your inventory, resulting in a logical "No Fill" even if the technical integration is correct.
Update Podfile
Ensure the adapter and SDK versions are locked in your Podfile.
source 'https://github.com/CocoaPods/Specs.git'
target 'YourAppTarget' do
use_frameworks!
# Google Mobile Ads
pod 'Google-Mobile-Ads-SDK', '~> 11.2.0'
# Mintegral Adapter (Automatically pulls the correct Mintegral SDK dependency)
pod 'GoogleMobileAdsMediationMintegral', '7.5.1.0'
end
Configure SKAdNetworkItems
Open your Info.plist as source code and verify the Mintegral ID (glqzh8vgby.skadnetwork) is present. Without this, conversion tracking fails, and demand sources cut off traffic.
<key>SKAdNetworkItems</key>
<array>
<!-- Google SKAdNetwork ID -->
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<!-- Mintegral SKAdNetwork ID -->
<dict>
<key>SKAdNetworkIdentifier</key>
<string>glqzh8vgby.skadnetwork</string>
</dict>
<!-- Add other network IDs as needed -->
</array>
Step 3: Debugging Initialization Status
Never assume MobileAds.initialize() succeeded for all networks. The initialization listener provides a map of the status of every adapter configured in your mediation stack.
Use this code to pinpoint exactly why Mintegral is failing (e.g., NOT_READY vs INVALID_ADAPTER).
Android (Kotlin)
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.initialization.AdapterStatus
import android.util.Log
fun initAdMob(context: Context) {
MobileAds.initialize(context) { initializationStatus ->
val statusMap = initializationStatus.adapterStatusMap
// Inspect Mintegral specifically
val mintegralStatus = statusMap["com.google.ads.mediation.mintegral.MintegralMediationAdapter"]
if (mintegralStatus != null) {
when (mintegralStatus.initializationState) {
AdapterStatus.State.READY -> {
Log.d("AdMob", "Mintegral Adapter Initialized Successfully")
}
AdapterStatus.State.NOT_READY -> {
// This often indicates credential issues in the AdMob Console
Log.e("AdMob", "Mintegral Failed: ${mintegralStatus.description}")
}
}
}
// Log all adapters for full visibility
statusMap.forEach { (className, status) ->
Log.d("AdMob", "Adapter: $className, State: ${status.initializationState}, Desc: ${status.description}")
}
}
}
iOS (Swift)
import GoogleMobileAds
func initializeAds() {
GADMobileAds.sharedInstance().start { status in
let adapterStatuses = status.adapterStatusesByClassName
// Specific check for Mintegral
if let mintegralStatus = adapterStatuses["GADMAdapterMintegral"] {
if mintegralStatus.state == .ready {
print("Mintegral Adapter Ready")
} else {
print("Mintegral Adapter Failed: \(mintegralStatus.description)")
}
}
// comprehensive log
for (adapterName, adapterStatus) in adapterStatuses {
print("Adapter: \(adapterName), State: \(adapterStatus.state.rawValue), Description: \(adapterStatus.description)")
}
}
}
Step 4: Configuring the AdMob Console
Code is only half the battle. If the server-side mapping is incorrect, the adapter rejects the request immediately.
- App Key vs. App ID: Mintegral requires both an
App Keyand anApp ID. In the AdMob dashboard (Mediation -> Waterfall Sources -> Mintegral), ensure you haven't swapped these two strings. This is the most frequent configuration error. - Placement ID: Ensure the Placement ID entered corresponds to the correct ad format. Using a Rewarded Video Placement ID for an Interstitial unit will result in immediate No Fill errors.
- Currency Settings: In your Mintegral dashboard, check your floor price settings. If you set a high floor (e.g., $20.00) in Mintegral but your AdMob mediation group is targeting a global audience, Mintegral will have no inventory to serve, returning
ERROR_CODE_NO_FILL.
Common Pitfalls and Edge Cases
The "Test Mode" Trap
Mintegral does not automatically serve test ads simply because you are using AdMob test unit IDs.
- Solution: You must enable "Test Mode" inside the Mintegral dashboard for your specific App ID, or use Mintegral's dedicated test credentials during development. Using live credentials while side-loading apps often triggers fraud filters, resulting in zero fill.
iOS App Transport Security (ATS)
Mintegral, like many ad networks, may attempt to load assets over HTTP. While HTTPS is standard, ensure your NSAppTransportSecurity allows arbitrary loads for specific domains if you see network connection errors in Xcode logs.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Note: While NSAllowsArbitraryLoads is permissible, it is better practice to whitelist specific ad domains if strict security is required.
Privacy Consent (GDPR/CCPA)
If you are using a Consent Management Platform (CMP) like Google's UMP SDK, the consent string is written to SharedPreferences (Android) or UserDefaults (iOS). The Mintegral adapter automatically reads the TCF v2.0 strings. However, if you are manually handling consent, you must forward the consent status to the Mintegral helper classes before initialization, or it will refuse to serve ads in regulated regions.
Conclusion
Fixing mediation issues requires treating the adapter as a strict bridge between two distinct SDK architectures. By locking your dependencies to matching versions, adding the correct ProGuard rules, and validating the initialization callbacks, you eliminate the technical blockers causing "Adapter not found" errors. Once the code is stable, focus on the AdMob console configuration to ensure your floors and IDs map correctly to generate the fill rates your application expects.