Skip to content

Show the banner when consent is cached but the consent call fails - #569

Open
andiwand wants to merge 1 commit into
mainfrom
fix-consent-error-path-hides-banner
Open

Show the banner when consent is cached but the consent call fails#569
andiwand wants to merge 1 commit into
mainfrom
fix-consent-error-path-hides-banner

Conversation

@andiwand

@andiwand andiwand commented Aug 5, 2026

Copy link
Copy Markdown
Member

The consent flow decides whether an ad may be requested from whether the UMP call came back clean, rather than from canRequestAds(). Both error paths hide the banner outright, and neither error is a refusal.

{ requestConsentError ->
    crashManager.log("consent info update failed: " + describe(requestConsentError))
    hideGoogleAds()          // <- no canRequestAds() check
},

The SDK caches the user's decision, so a form that fails to show — or an update that times out because the device is offline — still leaves an earlier consent standing. Outside the regions where a form is required at all, there is no decision to fail in the first place. The existing comment already names the common case:

fires for the mundane offline case too - a device that was asleep times out against fundingchoicesmessages.google.com

showGoogleAds() runs at billing setup and again on every onConfigurationChanged, so one timeout blanks the banner for the rest of the session — for users who had already consented, and for users outside the EEA who were never going to be asked.

What changed

Both callbacks now decide on canRequestAds() alone, via a shared showAdsIfConsented(). Errors are still logged as breadcrumbs, but are no longer acted on. This matches Google's documented pattern, which checks canRequestAds() in the success and failure callbacks.

A genuine refusal is unaffected: canRequestAds() returns false, the banner stays hidden, and no ad is requested.

Why it is worth fixing

Android match rate — the share of ad requests Google fills — since the consent form shipped in f6b942b6 (Dec 2023):

2023 2024 2025 2026
Android (consent form) 99.8% 93.6% 87.0% 77.6%
iOS (no consent form) 99.9% 98.7% 95.9% 95.8%

Show rate over the same period improved to ~92%, so this is not a rendering problem. Most of that gap is expected and correct — non-personalised requests are simply filled less often. This change does not address that; it only stops the app discarding inventory it was entitled to serve.

Testing

Not built or run — I have no Java runtime available, so spotlessCheck and the build were not executed. Formatting was matched to ktfmt kotlinlangStyle by hand (4-space indents, under 100 columns); please let CI confirm.

Worth verifying on device:

  • airplane mode on a device that has already consented → banner should now appear (previously hidden)
  • consent declined → banner still hidden, no ad request
  • outside the EEA (ConsentDebugSettings without DEBUG_GEOGRAPHY_EEA) → banner appears as before

The logging added in #516 should show consent info update failed followed by a banner, rather than by silence.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PafKp4GDZk7AYPbSNLTiti

The consent flow decided whether an ad may be requested from whether the
UMP call came back clean, rather than from canRequestAds(). Both error
paths hid the banner outright:

- requestConsentInfoUpdate failing hid it and returned. Its own comment
  notes this fires for the mundane offline case, when a device that was
  asleep times out against fundingchoicesmessages.google.com.
- a non-null FormError from loadAndShowConsentFormIfRequired hid it even
  when canRequestAds() was true.

Neither is a refusal. The SDK caches the user's decision, so a form that
fails to show or an update that times out still leaves an earlier consent
standing, and outside the regions where a form is required at all there is
no decision to fail in the first place. A single timeout therefore blanked
the banner for the whole session, for users who had already said yes and
for users who were never going to be asked.

Decide on canRequestAds() alone in both callbacks, and keep logging the
errors as breadcrumbs rather than acting on them. showGoogleAds() runs at
billing setup and again on every onConfigurationChanged, so this path is
hit on every launch and every rotation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PafKp4GDZk7AYPbSNLTiti
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant