The default generic Google rendered consent form

Setting up the consent SDK for AdMob on Android

Rayan Osseiran
The Startup
Published in
8 min readDec 27, 2019

--

Browsing the Android Dev subreddit, I noticed someone make mention of GDPR compliance and ad consent. I then realized I do not give EU users the option to opt-out of personalized advertising (oops). Luckily, AdMob have a nifty little SDK that makes the process pretty painless.

SUMMARY

Basically, you need to:

  1. Check if a user has already consented to a form of advertising
  2. If they have, display ads based on their consent status. Otherwise, request consent through a consent form.
  3. The form can be implemented manually or you can use one provided by Google. I will be using the Google one. After a user selects their option, go back to step 2.

What you’ll need:

  1. An AdMob account already set up
  2. Assume you already have ads set up on your app. This is not a guide on how to set up ads.
  3. A privacy policy. You should already have one, otherwise you’re at risk of being suspended by Google and should upload one immediately. Check out: https://app-privacy-policy-generator.firebaseapp.com/

A NOTE ON AD TECHNOLOGY PROVIDERS

The Google rendered form is apparently only compatible with at most 12 ad providers (https://github.com/googleads/googleads-consent-sdk-ios/issues/7).

However, I have personally not had any issues with the “commonly used set of technology providers” so this behaviour may have been changed recently. The Google rendered form even mentions the ~200 ad partners used.

Regardless, if you experience any issues, you are supposed to go to AdMob → Blocking Controls → EU User Consent → Select Ad Technology Providers → Select custom set of technology providers.

IMPLEMENTATION

If you work with Kotlin, the implementation should be the exact same aside from syntax differences. You can reference the official documentation here: https://developers.google.com/admob/android/eu-consent. The following code is based on it.

I include sample code at the end of the article for both Kotlin & Java.

  1. Import the SDK library to your app build.gradle
implementation 'com.google.android.ads.consent:consent-library:1.0.8'

Your project build.gradle should also have the Google repository

repositories {
google()
}

2. Declare the following variable in your main activity:

private ConsentForm form;

3. Now, here you can start to make your own design decisions if you wish. I have set up the following method in my main activity and call it inside my onCreate:

getConsentStatus();

You’ll need your publisher ID for this part. You can find your publisher ID by logging into AdMob → Settings → Account Information.

We’re simply checking the user’s consent status. If they are not in the EU, we show personalized ads. Otherwise, we display the appropriate ads if they already have status PERSONALIZED or NON_PERSONALIZED. If the status is UNKNOWN, we display the consent form.

The initializeAds(boolean isPersonalized) method should be based on whatever code you currently use to set up ads. There will simply be one addition (which we’ll get to soon enough).

Some people will opt to check for location inside the consent status switch statement if the status is unknown. This works fine, however, if the user leaves the EU, they will remain on non-personalized advertising. In this method, they are opted back to personalized advertising.

4. Displaying the form

You’ll need your privacy policy here. The basic logic here is that you’ll build the Google provided consent form. When the form is loaded, the onConsentFormLoaded() callback will get called and you’ll call form.show() (this is why we declare the form outside the function).

The next important callback is onConsentFormClosed(). The user will have selected an option, you will need to handle it similar to above and display the appropriate ads through our initializeAds method.

IMPORTANT: There is a third option that I do not include here. You can add the following when building the form (before .build())

.withAdFreeOption()

This is a prompt for the user to purchase a paid ad-free version of the app if they prefer no advertising at all.

Then, in the onConsentFormClosed() callback, you can check the boolean userPrefersAdFree and implement this as you wish depending on however you process in-app purchases.

This is what your form will look like (except it will display your app name and logo) as well as information on your ad technology providers.

The End Product

5. Setting up your ads

Again, I assume you already have ads set up on your app so I won’t go through the whole set up for that. The only change you’ll need is to building the ad request.

And you’re done! It’s that simple. Now, I’ll go through some extra points. You can find a link to the code on GitHub below in both Kotlin & Java.

TESTING

Well, we’re not all in the EU are we? To simulate this, simply add the following two lines after you first call ConsentInformation.getInstance(context) in the getConsent method.

If you are on an emulator, keep AdRequest.DEVICE_ID_EMULATOR as your device ID. Otherwise, if you already have AdMob set up (make sure you use sample test units), the device ID will be listed in logcat.

consentInformation.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
consentInformation.setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_EEA);

CUSTOM CONSENT FORM MESSAGE

As per the AdMob docs:

To update consent text of the Google-rendered consent form, modify the consentform.html file included in the Consent SDK as required.

You can find the default consentform.html here: https://github.com/googleads/googleads-consent-sdk-android/blob/master/consent-library/src/main/assets/consentform.html

Alternatively, if you’ve already set-up the consent SDK and ran the code on your project, it will be generated here: PROJECT/app/build/intermediates/merged_assets/debug/out

To use a custom one:

  1. Create an assets folder if you do not have one. To do this, switch to the project view on Android Studio. Then right click on the app folder → new → folder → asset
  2. Create your own consentform.html and store it in the asset folder.

I personally haven’t found reason to change this except modifying the app name and providing a little more detail to the user.

NON-GOOGLE CONSENT FORM

I do not personally implement this, but you can read more about doing this here. It is easy to implement from a programatic perspective, you’ll probably spend more time working on the UX/UI.

To implement this, we follow the same steps as previously i.e., we call getConsentStatus(), however, you replace displayConsentForm() with your own implementation.

The user needs to give consent to all your Ad providers, get them with the following snippet:

List<AdProvider> adProviders =
ConsentInformation.getInstance(context).getAdProviders();

Once the user sets their consent status, update it through:

ConsentInformation.getInstance(context)
.setConsentStatus(ConsentStatus.STATUS);

CCPA

Using Google’s consent form does not seem to work unless you’re in the EU. So if you’d like to implement this for CCPA, it probably needs to be done with a form you’ve created on your own. As mentioned above, this is pretty easy to implement and is pretty much just a UI job!

If you do not want to implement a custom form, you should:

Go to AdMob → Blocking Controls → CCPA → Restrict data processing

This will automatically show non-personalized ads to Californian users without any work from your side.

Alternatively, if you want to restrict data processing on the request level, please read the following.

USER CUSTOMIZABILITY

It is critical that you give the user the option to change their decision at any time. The default Google form states that this is an option in your settings menu. If you do not put it in the settings menu, make sure to update the default consent form.

You can do this however you want.

  1. A simple preference for which a click will redisplay the consent form
  2. A simple preference for which a click will reset the consent status to UNKNOWN and will thus update on app restart.
  3. A list preference where you set the consent status to whatever the user selects.
  4. Literally anything that works for the way your app is set-up!

I use the second option. If your app is still using preference activities, you’re pretty much stuck keeping this visible to all users (you could remove the preference, but it’s more hackish than what you can do with preference fragments). If you use preference fragments, you can hide it for non-EU users

I do not do anything special to reload the ad. I state that the change will apply after a restart. You can easily implement a dynamic update through a publish subject or any other form of communication you’d like (depending on how your app is set up).

Since this part is very dependant on how your app is set-up, I did not include any sample code. Implementation is very easy and you’re pretty much reusing code in previous sections.

EXTRAS — CONSENT & FIREBASE

Something we overlook is asking for consent when we use Firebase for either analytics or crashlytics. I’m no lawyer, but with the GDPR, you cannot have crashlytics enabled by default. Mentioning it in your privacy policy is not enough. It needs to be an opt-in option, not an opt-out. Plus, GDPR or not, it’s just a nice thing to give your user that level of control over their data.

A simple way to approach this would be similar to ad consent; a dialog asking the user for permission for crash reporting. This is obviously the more critical thing you’ll need as a developer. I don’t know about you but losing analytics is not a huge deal for me, but losing crashlytics is a whole other story.

Regardless, aside from the UI, this is once again very simple in terms of implementation.

First, you’ll want to add the following to your Android Manifest in order to disable both analytics & crashlytics

<meta-data android:name=”firebase_crashlytics_collection_enabled” android:value=”false”/>
<meta-data android:name=”firebase_analytics_collection_enabled” android:value=”false”/>

You can then enable crashlytics programatically if the user has given you consent via:

Fabric.with(this, new Crashlytics());

The same goes for analytics:

FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(true);

Note that once you have enabled crashlytics in an instance of the app, it cannot be disabled. So if a user disables it, the change will only apply on restart.

Personally for me, I have both disabled by default and include an option in the settings menu via a switch to enable them. This is more out of laziness because as I said, crashlytics is very important to me, however implementing this as a dialog would require me to implement a custom consent dialog for ads (since I do not want to display two dialogs). So this is quite a bit less involved than implementing ad consent. Particularly if you elect to be lazy like me.

SAMPLE ACTIVITY — GITHUB

Here is a sample activity implementing the SDK in both Kotlin and Java.

Thanks for tuning in, let me know if something is unclear or incorrect.

REFERENCES

Official AdMob Documentation

Consent SDK GitHub

Google EU Consent Policy

--

--