Skip to main content

Fixing InMobi Android 13+ Crashes: AD_ID and Manifest Permissions

 Few things are more frustrating than a stable monetization stack breaking immediately after updating your targetSdkVersion. If you have recently targeted Android 13 (API Level 33) or higher and noticed your InMobi fill rates dropping to zero—or worse, your app crashing with security exceptions—you are likely a victim of Google's privacy sandbox tightening.

The issue stems from a fundamental change in how the Google Advertising ID (GAID) is accessed, combined with strict location enforcement. This guide provides the root cause analysis and the specific code implementation required to stabilize your InMobi integration.

The Root Cause: Google Play Services API 33 Changes

Prior to Android 13, any application could access the user's Advertising ID provided they had the Google Play Services client library. The ID was used by ad networks like InMobi for frequency capping, attribution, and personalized targeting.

With the introduction of API 33, Google declared the Advertising ID a privileged identifier.

1. The AD_ID Permission

If your app targets Android 13 but does not explicitly request the com.google.android.gms.permission.AD_ID permission, the Advertising ID API will zero out the identifier.

When the InMobi SDK attempts to fetch the GAID to request an ad, it receives a string of zeros (00000000-0000-0000-0000-000000000000). Depending on the SDK version, this results in either:

  • No Fill: The ad server rejects the request because the device fingerprint is invalid.
  • Crash: Older SDK versions may throw a SecurityException or a NullPointerException when failing to parse the ID.

2. Location Permission Tightening

InMobi, like many ad networks, attempts to pass location data (ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION) to advertisers to increase eCPM.

On Android 13+, the system is more aggressive about killing background processes or denying requests that attempt to access location without runtime checks. If the InMobi SDK is configured to automatically pull location data but the manifest is misconfigured, the app may crash during SDK initialization.

The Solution: Updating the Android Manifest

To resolve this, you must explicitly declare the usage of the Advertising ID. This is not a runtime permission (the user does not see a popup), but it is a build-time declaration required for the OS to release the ID to your app.

Step 1: Inject the AD_ID Permission

Open your AndroidManifest.xml (usually located in src/main/) and add the following line inside the <manifest> tag, parallel to your other permissions.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.package.name">

    <!-- REQUIRED for Android 13+ (API 33) to access GAID -->
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <!-- Standard Internet permissions usually already present -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application ... >
        <!-- Application components -->
    </application>
</manifest>

Step 2: Handle Location Dependencies

If you do not use location services for your core app functionality, it is best practice to block the ad network from requesting these permissions implicitly. This prevents store rejection due to undeclared data usage.

Add tools:node="remove" to the location permissions to ensure they are stripped during the manifest merge process, preventing third-party libraries (like InMobi) from sneaking them in.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.your.package.name">

    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <!-- Explicitly remove location permissions if not core to your app -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove" />

</manifest>

Configuring the InMobi SDK (Kotlin)

Once the permissions are in place, you must ensure the SDK is initialized correctly. Modern Android development uses Coroutines; ensure you are not initializing the SDK on the UI thread, although the InMobi SDK handles most threading internally, the initial config setup should be precise.

If you previously relied on InMobi to collect location automatically, explicitly disable it to prevent SecurityException crashes on Android 13 devices where permissions are revoked.

import android.app.Application
import com.inmobi.sdk.InMobiSdk
import com.inmobi.sdk.SdkInitializationListener
import org.json.JSONObject

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        initInMobi()
    }

    private fun initInMobi() {
        // Create a consent object (GDPR compliance)
        // Note: For actual GDPR, use a CMP (Consent Management Platform)
        val consentObject = JSONObject()
        try {
            consentObject.put(InMobiSdk.IM_GDPR_CONSENT_AVAILABLE, true)
            consentObject.put("gdpr", "1")
        } catch (e: Exception) {
            e.printStackTrace()
        }

        // Disable automatic location collection to prevent Android 13 crashes
        // if runtime permissions aren't granted.
        InMobiSdk.setLogLevel(InMobiSdk.LogLevel.ERROR)

        // Initialize SDK
        // Replace "YOUR_ACCOUNT_ID" with your actual InMobi Account ID
        InMobiSdk.init(
            this,
            "YOUR_ACCOUNT_ID",
            consentObject,
            object : SdkInitializationListener {
                override fun onInitializationComplete(error: Error?) {
                    if (error == null) {
                        // SDK initialized successfully
                        // Safe to load ads now
                    } else {
                        // Handle initialization failure
                        // Log error: error.message
                    }
                }
            }
        )
    }
}

Verifying the Advertising ID (Deep Dive)

To confirm that your Manifest fix is working and that Google Play Services is returning a valid ID, you can use the following utility class. This uses Kotlin Coroutines to fetch the ID off the main thread (which is required by the GMS API).

Dependency Requirement: Ensure you have the Play Services Ads Identifier library in your build.gradle.kts:

implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")

The Verification Utility:

import android.content.Context
import android.util.Log
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

object AdvertisingIdHelper {

    /**
     * Fetches the GAID.
     * Returns null if the user has limited ad tracking or permission is missing.
     */
    suspend fun getAdvertisingId(context: Context): String? {
        return withContext(Dispatchers.IO) {
            try {
                val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
                
                // If isLimitAdTrackingEnabled is true, the ID might be zeroed out
                // regardless of permissions.
                if (adInfo.isLimitAdTrackingEnabled) {
                    Log.d("AdIdHelper", "User has limited ad tracking.")
                    return@withContext null 
                }
                
                val id = adInfo.id
                Log.d("AdIdHelper", "GAID Retrieved: $id")
                
                // If this logs 00000000-0000..., your Manifest permission is missing
                id
            } catch (e: GooglePlayServicesNotAvailableException) {
                Log.e("AdIdHelper", "Google Play Services not available", e)
                null
            } catch (e: Exception) {
                Log.e("AdIdHelper", "Failed to get Advertising ID", e)
                null
            }
        }
    }
}

Common Pitfalls and Edge Cases

1. Conflict with Google Play Data Safety

Adding the AD_ID permission changes your app's privacy footprint. When you upload this build to the Google Play Console, you must update your Data Safety form.

You need to declare that your app collects "Device or other IDs." Under the purpose, select "Advertising or Marketing." Failure to do this will result in your app update being rejected.

2. Mediation Adapters

If you are using InMobi via mediation (e.g., AdMob, AppLovin MAX, or LevelPlay), simply updating the main SDK might not be enough. The mediation adapter acts as the bridge.

Check your build.gradle and ensure the adapter matches the underlying SDK version. Older adapters might invoke deprecated methods that trigger crashes on API 33.

// Example: Ensure consistency
implementation("com.inmobi.monetization:inmobi-ads:10.6.0")
implementation("com.google.ads.mediation:inmobi:10.6.0.0") // AdMob adapter

3. COPPA and Children's Apps

If your app targets children (participation in the Designed for Families program), strictly avoid requesting the AD_ID permission. Google policy forbids transmitting GAID for children.

In this scenario, you must create a separate build flavor or use a manifest merger strategy to ensure the AD_ID permission is not included in the child-directed version of your app.

<!-- In the child-directed variant AndroidManifest.xml -->
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>

Conclusion

Android 13's privacy changes are not suggestions; they are strict enforcement mechanisms. For InMobi and other ad networks to function, the bridge between the app and the Google Play Services ID must be explicitly built via the AD_ID permission.

By updating your manifest and sanitizing your location permissions, you resolve the immediate crash and ensure your fill rates return to normal. Remember to sync these changes with your Data Safety declarations in the Play Console to avoid administrative blockers during your next release.