22

In compliance of the GDPR, Google says that I must 'Select ad technology providers' and get users' consent. But the Google-rendered consent form is not supported if any of the publisher IDs use the commonly used set of ad technology providers. This means that I need to manually choose ad technology providers for my account in order to avoid collecting consent myself with the 'with the Publisher-managed consent collection option'. Here I am blank.

Which ones should I choose, and what difference does it make if I don't use mediation and only use admob? Should I use only one provider i.e. Google?

Edit: Thanks for the downvotes. I honestly don't see why this is not a valid question, except that perhaps this should have been asked somewhere else, for which I seek guidance.

Usman
  • 2,331
  • 2
  • 21
  • 29
  • 1
    I wonder this too. I upvote your question. If you find an answer please post here too. – Thracian May 23 '18 at 16:12
  • I also wonder why it is down voted? I upvote and if you found any solution please post it here – Smeet May 24 '18 at 10:03
  • Upvoted. I ended up doing my own form and using all the providers. – Tim Autin May 29 '18 at 12:30
  • Google-rendered consent form is an open source library limited to 12 providers. So you have 3 options: You limit yourself to use 12 admob providers – Simon May 30 '18 at 01:35
  • Hello Usman, did you figure this out with regards to only picking Google if you are not using mediation ? is this the right thing to do since the other ad technology partners are other ad networks I would assume you only pick more if your using mediation ? – isJulian00 Oct 22 '18 at 23:06
  • I ended up choosing all providers using my own implementation. – Usman Oct 24 '18 at 06:14
  • 1
    @usman could you post an example of what yours looks like ? So I can see what to go off, thanks very much – isJulian00 Nov 01 '18 at 01:45
  • 1
    I have written an answer with all the relevant code. Please check it. – Usman Nov 02 '18 at 08:15

3 Answers3

5

I have been trying to answer myself that question for a week already. This is what I do.

Check on your Adsense Account, go to "Advanced Reports">"Ad Networks" and you will see All the Ad Technologies providers that your app has gotten Ads from, that should give you an idea of which Ad providers would be good for you.

If your app is new and don't have any data, I would suggest to go only with Google(default).

In my particular case, my app has been up for 8 months with 450 installs and 45 active installs.

Google Networks reports a 91.5% on impresions and 97.3% on Estimated Earnings.

IMO having Google as only one provider will look better when the user wants to see who the app shares information with, instead of having a list of 12 of which never heard of. In the beginning I thought on choosing the best 12, but by the numbers it doesn't make much of a sense and chose to stick with Google alone.

DISCLAIMER: I know nothing regarding Ad Networks and I choose Google because of my Admob history and nothing else.

Guanaco Devs
  • 1,822
  • 2
  • 21
  • 38
  • 1
    Indeed, the only selection criterion is income. For this, AdSense is the only one capable of providing us with this information, as you explain it. Thank you! – Kevin Vuilleumier Jun 19 '18 at 13:10
  • Hello does anyone know more about this, why do we pick other Ad Technology Partners if we only use AdMob ? and why are there so many ad technology partners if admob only supportes around 30 mediation partners a bit confused on this ? – isJulian00 Oct 21 '18 at 22:36
1

What you call "Google-rendered consent form" is an open source library made by Google to show and collect users consent.

Acording to GDRP, this consent form should show the privacy policy of all the admob's providers. But this library is limited to show up to 12 providers.

So you have 3 options:

1- You limit yourself to use 12 admob providers.

2- You make your own consent form.

3- You download the google library consent form from github and modify it to show all the ads providers

Simon
  • 1,890
  • 19
  • 26
  • 1
    Yes, we can limit ourself to 12 providers, but which ones? This is precisely his question: how can we choose the correct ad technology providers? On which criteria? I don't think it's a good idea to have hundreds of providers anyway... – Kevin Vuilleumier Jun 19 '18 at 11:29
  • We use Admob exclusively for ad delivery. Our ad technology provider list is close to 400 providers. Users are going to love it ;( – user1608385 Oct 29 '18 at 16:53
  • @user1608385 how are you going to deal with this ? are you going to create your own cmp form ? I was interested because I want to show more than 12 ad technology partners but not sure how to go about it – isJulian00 Nov 01 '18 at 01:32
  • at the bottom of this page https://developers.google.com/admob/android/eu-consent it says FAQ How many ad technology providers does the Consent SDK support? The Consent SDK does not impose a limit on the number of ad technology providers a publisher chooses to enable. where are people getting this limit of 12 ? – isJulian00 Nov 01 '18 at 01:46
  • @izzyMachado Well since we just use Admob, it looks like providers outside of Google/Admob are called in to supply ad technologies by Admob, so we decided to just show Google/Admob. Users can then click the Google link to check out their privacy policy and identify any 3 or 4th party ad technology providers that are called by Admob. – user1608385 Nov 02 '18 at 04:17
  • @user1608385 oh ok so your provider list is still close to 400 ? or how many ad technology partners do you show on your list ? – isJulian00 Nov 04 '18 at 20:19
  • @user1608385 So, you still have 400 partners?? – Mohammedsalim Shivani Nov 22 '18 at 15:39
1

Ok so I ended up implementing my own consent mechanism. I think that it complies with the requirements, so for the benefit of others, here it is:

First, declare these variables. These will be used to decide if you need to show consent form:

boolean shouldShowConsentForm = false;
boolean goAdFreeChosen = false; // to prevent firing the consent dialog when going into settings.

Use this method to tell the user that you are going to ask for consent:

void showConsentDialogIntro(final Context context) {
    Bundle params = new Bundle();
    params.putString("what", "showConsentDialogIntro");
    mFirebaseAnalytics.logEvent(CONSENT_COLLECTION, params);

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("Something important before you continue...").
            setMessage("This app is kept free by showing ads. Tap next to see privacy options regarding this.\n\n(You can change this later in Settings too)").
            setPositiveButton("Next", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    showYesNoDialog(context, true);
                }
            })
            //.setNegativeButton("Cancel", null)
            .show();
}

Then this method will give the user 3 choices - Give consent, don't give consent, or remove ads altogether:

private void showYesNoDialog(final Context context, boolean shouldReportInFirebase) {
    if (shouldReportInFirebase) {
        Bundle params = new Bundle();
        params.putString("what", "showYesNoDialog");
        mFirebaseAnalytics.logEvent(CONSENT_COLLECTION, params);
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    final CharSequence[] items = {"Yes - Shows relevant ads", "No - Shows less relevant ads", "Go Ad free",
            "Learn how our partners collect and use your data"};
    builder.setTitle("Can THIS_APP_NAME use your data to tailor ads for you?").
            setItems(items, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Bundle params = new Bundle();
                    switch (which) {
                        case 0: // yes
                            ConsentInformation.getInstance(context)
                                    .setConsentStatus(ConsentStatus.PERSONALIZED);
                            shouldShowConsentForm = false;

                            mInterstitialAd.loadAd(new AdRequest.Builder()
                                    .addTestDevice(TEST_DEVICE_FOR_ADS)
                                    .build());

                            params.putString("what", "yes");
                            break;
                        case 1: // no
                            ConsentInformation.getInstance(context)
                                    .setConsentStatus(ConsentStatus.NON_PERSONALIZED);
                            shouldShowConsentForm = false;

                            Bundle extras = new Bundle();
                            extras.putString("npa", "1");
                            mInterstitialAd.loadAd(new AdRequest.Builder()
                                    .addNetworkExtrasBundle(AdMobAdapter.class, extras)
                                    .addTestDevice(TEST_DEVICE_FOR_ADS)
                                    .build());

                            params.putString("what", "no");

                            Snackbar.make(myToolbar, "We'll partner with Google and use a unique identifier to respect your choice.",
                                    Snackbar.LENGTH_LONG).addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {
                                @Override
                                public void onDismissed(Snackbar transientBottomBar, int event) {
                                    super.onDismissed(transientBottomBar, event);
                                    Snackbar.make(myToolbar, "You can change your choice later in Settings.", Snackbar.LENGTH_LONG).show();
                                }
                            })
                                    //.setDuration(3500)
                                    .show(); // 3500 is perhaps the duration for LENGTH_LONG.
/*
                            new Handler().postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    Snackbar.make(myToolbar, "You can change your choice later in Settings.", Snackbar.LENGTH_LONG).show();
                                }
                            }, 3500);
*/
                            break;
                        case 2: // ad free
                            // drawer.setSelection(settings, true);
                            goAdFreeChosen = true;
                            drawer.setSelection(DRAWER_IDENTIFIER_SETTINGS, true);

                            params.putString("what", "ad_free");
                            break;
                        case 3: // learn more
                            showLearnMoreDialog(context);

                            params.putString("what", "showLearnMoreDialog");
                            break;
                    }
                    mFirebaseAnalytics.logEvent(CONSENT_COLLECTION, params);
                }
            })
            // .setNegativeButton("Cancel", null)
            .show();
}

If user taps Learn More (the 4th option in the menu above), they will be presented a list of all providers which they can tap to view their respective privacy policies:

private void showLearnMoreDialog(final Context context) {
    List<AdProvider> adProviders =
            ConsentInformation.getInstance(context).getAdProviders();

    final CharSequence[] itemsName = new CharSequence[adProviders.size()];
    final String[] itemsURL = new String[adProviders.size()];

    int i = 0;
    for (AdProvider adProvider : adProviders) {

        itemsName[i] = adProvider.getName();
        itemsURL[i] = adProvider.getPrivacyPolicyUrlString();
        i++;
    }

    ArrayAdapter adapter = new ArrayAdapter<>(context,
            android.R.layout.simple_list_item_1, itemsName);

    AlertDialog.Builder builder = new AlertDialog.Builder(context);

    builder.setTitle("Tap on our partners to learn more about their privacy policies")
            .setNegativeButton("Back", null)
            .setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                            /*        Toast.makeText(context,
                                            "URL: " + itemsURL[which].toExternalForm(), Toast.LENGTH_SHORT).show();*/
                    Intent browserIntent = new Intent(Intent.ACTION_VIEW,
                            Uri.parse(itemsURL[which]));
                    startActivity(browserIntent);

                    Bundle params = new Bundle();
                    params.putString("what", "showLearnMoreDialog_open_privacy_policy");
                    mFirebaseAnalytics.logEvent(CONSENT_COLLECTION, params);
                }
            })
            .setCancelable(true)
            .setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialog) {
                    showYesNoDialog(context, false);
                }
            })
            .show();
}

Note that I have also implemented firebase analytics in this but you can remove the lines relating to "params" if you don't want to log these events.

You can see the status of consent using this method:

private void getConsentStatusAndLoadAdAccordingly(final Context context) {
    ConsentInformation consentInformation = ConsentInformation.getInstance(context);
    //   consentInformation.addTestDevice(TEST_DEVICE_FOR_ADS);
    //   consentInformation.setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_EEA); // for forcing Europe area; testing.
    //   consentInformation.setConsentStatus(ConsentStatus.UNKNOWN); // useful for triggering it after saving status; testing.

    String[] publisherIds = {MY_PUBLISHER_ID};
    consentInformation.requestConsentInfoUpdate(publisherIds, new ConsentInfoUpdateListener() {
        @Override
        public void onConsentInfoUpdated(ConsentStatus consentStatus) {
            loog("consentInformation", "onConsentInfoUpdated");
            // User's consent status successfully updated.
            if (ConsentInformation.getInstance(context).isRequestLocationInEeaOrUnknown()) {
                loog("consentInformation", "isRequestLocationInEeaOrUnknown = true");
                    /* If the isRequestLocationInEeaOrUnknown() method returns false, the user is not
                    located in the European Economic Area and consent is not required under the EU User Consent Policy.

                    If the isRequestLocationInEeaOrUnknown() method returns true:
                    If the returned ConsentStatus is PERSONALIZED or NON_PERSONALIZED, the user has already provided consent.
                    You can now forward consent to the Google Mobile Ads SDK.
                    If the returned ConsentStatus is UNKNOWN, you need to collect consent. */
                loog("consentInformation", "consentStatus = " + consentStatus);

                if (consentStatus == ConsentStatus.UNKNOWN) {
                    // showGoogleConsentForm(DrawerAndFragmentActivity.this);
                    shouldShowConsentForm = true;
                } else if (consentStatus == ConsentStatus.NON_PERSONALIZED) {
                        /* The default behavior of the Google Mobile Ads SDK is to serve personalized ads. If a user
                    has consented to receive only non-personalized ads, you can configure an AdRequest object
                    with the following code to specify that only non-personalized ads should be returned: */
                    Bundle extras = new Bundle();
                    extras.putString("npa", "1");
                    mInterstitialAd.loadAd(new AdRequest.Builder()
                            .addNetworkExtrasBundle(AdMobAdapter.class, extras)
                            .addTestDevice(TEST_DEVICE_FOR_ADS)
                            .build());
                } else if (consentStatus == ConsentStatus.PERSONALIZED) {
                    mInterstitialAd.loadAd(new AdRequest.Builder()
                            .addTestDevice(TEST_DEVICE_FOR_ADS)
                            .build());
                }
            } else {
                loog("consentInformation", "isRequestLocationInEeaOrUnknown = false");
                mInterstitialAd.loadAd(new AdRequest.Builder()
                        .addTestDevice(TEST_DEVICE_FOR_ADS)
                        .build());
            }
        }

        @Override
        public void onFailedToUpdateConsentInfo(String errorDescription) {
            // User's consent status failed to update.
            loog("consentInformation", "onFailedToUpdateConsentInfo: errorDescription = " + errorDescription);

            mInterstitialAd.loadAd(new AdRequest.Builder()
                    .addTestDevice(TEST_DEVICE_FOR_ADS)
                    .build());
        }
    });
}

Finally, when you need to decide whether to show ad or show consent form, you can use a logic like this: (shouldShowAd is an optional boolean which I like to put for more clarity)

if (shouldShowAd) {
                            if (shouldShowConsentForm) {
                                if (!goAdFreeChosen)
                                    showConsentDialogIntro(DrawerAndFragmentActivity.this);
                                goAdFreeChosen = false;
                            } else {
                                if (mInterstitialAd != null)
                                    if (mInterstitialAd.isLoaded()) {
                                        mInterstitialAd.show();
                                    }
                            }
                        }
Usman
  • 2,331
  • 2
  • 21
  • 29