Proper Consent Handling for Android SDKs Using Google IDs

Technical Postmortem: Android SDK Consent Management Misconfiguration

Summary

This postmortem documents a common architectural misunderstanding in Android SDK development regarding Google User Messaging Platform (UMP) integration and consent management. The incident occurs when SDK developers incorrectly assume that relying on the host app to provide GAID/ASID absolves them from UMP integration requirements.

Key Takeaway: The location where identifiers are obtained is irrelevant to consent requirements—what matters is whether the SDK uses identifiers that require consent under Google’s policies.

Root Cause

The fundamental misunderstanding stems from a conceptual error in interpreting Google’s consent requirements:

  • Developers assume: “If I don’t fetch GAID myself, I’m not responsible for consent”
  • Reality: Consent is required based on data usage, not data acquisition method

When an SDK receives GAID/ASID from a host app and uses these identifiers for:

  • Advertising purposes
  • User profiling
  • Cross-app tracking
  • Personalization based on advertising identifiers

…then the SDK is subject to the same consent requirements as if it had retrieved the identifiers directly from the device.

Why This Happens in Real Systems

This misconfiguration occurs due to several recurring patterns:

  • Delegation misconception: Developers believe “the host app handles consent, so I’m covered”
  • Parameter passing confusion: Passing GAID as an optional parameter creates ambiguity about responsibility
  • Policy ambiguity: Google’s documentation doesn’t explicitly state “SDKs using received identifiers need UMP”
  • Scope limitation: Teams only analyze their own code’s identifier retrieval, not identifier consumption

Real-World Impact

The consequences of incorrect consent handling include:

  • Policy violations: Google Play Store rejections or warnings
  • Account termination risk: Repeated violations lead to developer account suspension
  • Legal exposure: GDPR/CCPA non-compliance penalties
  • Functional breakage: Devices without proper consent may receive null/zero identifiers, breaking SDK functionality
  • User trust erosion: Improper consent flows create poor user experiences

Example or Code

The following demonstrates the incorrect versus correct implementation patterns:

// INCORRECT: Assuming no UMP needed when GAID is received from host
class SdkInitializer {
    fun initialize(context: Context, gaid: String?, asid: String?) {
        // SDK uses GAID without any consent check
        val advertisingId = gaid ?: "unknown"
        sendToAnalytics(advertisingId) // ❌ Violation: using ad ID without consent
    }
}

// CORRECT: Implementing proper consent checks regardless of GAID source
class SdkInitializer {
    fun initialize(context: Context, gaid: String?, asid: String?) {
        val consentInfo = UserMessagingPlatform.getConsentInformation(context)

        if (consentInfo.isConsentRequired) {
            // Show consent form before using any identifiers
            showConsentForm(context) { 
                proceedWithInitialization(gaid, asid)
            }
        } else {
            proceedWithInitialization(gaid, asid)
        }
    }

    private fun proceedWithInitialization(gaid: String?, asid: String?) {
        val canUseAdId = ConsentInformation.getInstance(context)
            .canUseGoogleIdentifierForAnalytics()

        val advertisingId = if (canUseAdId) gaid else null
        initializeSdk(advertisingId)
    }
}

How Senior Engineers Fix It

Senior engineers address this issue through comprehensive consent architecture:

  • Unified consent layer: Implement consent checks regardless of identifier source
  • Defense in depth: Assume no identifiers are available until consent is confirmed
  • Contract clarity: Document in SDK contracts that host apps must ensure consent before passing identifiers
  • UMP integration: Include Google UMP SDK as a required dependency
  • Runtime verification: Check consent status at runtime before every identifier use

Best practice implementation:

class ConsentManager(private val context: Context) {
    private val consentInformation = UserMessagingPlatform.getConsentInformation(context)

    fun canUseAdvertisingIdentifiers(): Boolean {
        return consentInformation.canUseGoogleIdentifierForAnalytics()
    }

    fun requestConsent(activity: Activity, onComplete: () -> Unit) {
        if (consentInformation.isConsentRequired) {
            val consentForm = UserMessagingPlatform.getConsentForm(activity) { form, error ->
                if (error != null) {
                    handleConsentError(error)
                }
                onComplete()
            }
            consentForm.show()
        } else {
            onComplete()
        }
    }
}

Why Juniors Miss It

Junior engineers and even mid-level developers frequently overlook this issue because:

  • Focus on happy paths: Code works during development when consent is granted
  • Limited policy knowledge: Google’s advertising policies aren’t always required reading
  • Test environment gaps: Development devices often have identifiers pre-enabled
  • Delegation assumption: “The host app handles this” is a reasonable-sounding but incorrect assumption
  • Missing integration experience: Developers without prior advertising SDK work lack the context for proper consent handling

Preventive measures include: mandatory consent management training, security review checklists, and explicit documentation of consent responsibilities in SDK contracts.

Leave a Comment