Ads are an important part of your app's overall user experience. Good ad implementations can effectively contribute to UX and even increase user retention and engagement. For example: Rewarded Video ad enables you to reward users with in-app items for watching video ads, so that users can reach new heights where otherwise they may get stuck and would have churned.

However, a great ad implementation involves of a lot of considerations, such as ad frequency, where and when to show the ad, what the reward should be, etc. On top of this, it differs from app to app, from placement to placement. There is no one-size-fits-all answer.

With Firebase Remote Config, Analytics, and AdMob, finding the sweet spot has become much easier and more streamlined. A/B testing on the fly, or progressively rolling changes out and monitoring important UX metrics, can be set up rather easily and mitigates the risk of introducing new behaviors and changes.

What are you going to be building?

In this codelab, you're going to introduce a new ad placement variant to an existing app, set up test traffic, and roll out it progressively. We will also share with you tips about what metrics to look at, and how to turn them into actions.

What you'll learn

What you'll need

Download the code

Click the following button to download all the code for this codelab:

Download source code

Unpack the downloaded zip file. This will unpack a root folder monetizationcodelab-master. Rename the root folder to monetizationcodelab.

...or clone the GitHub repository from the command line.

$ git clone https://github.com/googlecodelabs/monetizationcodelab

Import the starter app

Launch Android Studio, choose "Import project" on the welcome screen and select the monetizationcodelab/starter directory from the sample code download.

You should now have the project open in Android Studio.

Create Firebase Console Project

  1. Go to the Firebase console.
  2. Select Add Project, and name your project "MonetizationCodelab".

Connect your Android app

  1. From the overview screen of your new project, click Add Firebase to your Android app.
  2. Enter the codelab's package name: com.google.firebase.codelab.monetizationcodelab
  3. Set a nickname for your app: MonetizationCodelab.
  4. Leave the SHA-1 field blank since SHA-1 is not required for this project.
  5. Select Register App to register your app.

Add google-services.json file to your app

Next, you will be prompted a screen where you can download a configuration file that contains all the necessary Firebase metadata for your app. Click Download google-service.json and copy the file into the app directory in your project.

Add google-services plugin to your app

The google-services plugin uses the google-services.json file to configure your application to use Firebase. The following line should already be added to the end of the build.gradle file in the app directory of your project (check to confirm):

apply plugin: 'com.google.gms.google-services'

Sync your project with gradle files

To be sure that all dependencies are available to your app, you should sync your project with gradle files at this point. Select Sync Project with Gradle Files () from the Android Studio tool bar.

Next, create an app and ad unit as the following.

  1. Go to the AdMob front end.
  2. If you have already upgraded to AdMob beta or are using a new AdMob account, from Apps menu, click "Add App", answer "NO" when asked "Have you published your app on Google Play or the App Store," then name the app "MonetizationCodelab", choose "Android" as the Platform, and click "Add". You should see the following screen as a result.

  1. Click NEXT: CREATE AD UNIT, select REWARDED VIDEO, set reward amount to 50, and reward item to "hint" (these are the reward the app current gives to users), name it "game over 1", and save.

  1. When successfully saved, you will see the ad unit id as the following. Modify the GameActivity.java file as the following so that the app refers to the ad unit we just created. (Change the ca-app-pub-3940256099942544/6807086514 part with the ad unit id you just created.)

GameActivity.java

private static final String DEFAULT_AD_UNIT_ID = "ca-app-pub-3940256099942544/6807086514";
  1. Compile and run the project. You should see the following screen when the app starts.

  1. Tap START, and you will see this is an oversimplified "spot-the-difference" game. as time goes by, one of the kiwifruits gradually disappears from the bowl. Tap on that disappearing kiwifruit to win the game.

  1. Start the game again, and tap on anywhere other than the kiwifruit to see the "game over" screen. On the game over screen, you are offered to watch a rewarded video ad to get a hint. Tap "Watch an ad and play again with hint" and confirm the rewarded video loads and plays.

  1. Watch the video to completion. After the rewarded video, you can see 50% of the screen is masked, indicating the right answer is not in that part of the image.

Add a variant Rewarded Video implementation

You now have a reward mechanism in the form of a hint, but you're not sure how a change in the amount of the hint will impact user engagement and gameplay experience in your app. Therefore, you want to be careful and test on a small group of users first. Does the reward still enable users to reach new heights without making it too easy or too difficult? We'll gather data to answer this question.

  1. First, create another Rewarded Video ad unit as a test ad unit. From Apps Menu, click Apps, choose MonetizationCodelab (the app you created earlier), click Ad units, and click the ADD AD UNIT button.

  1. Choose Rewarded video, set reward amount to 30, and reward item to "hint". The reward amount is the percent of the screen that will be covered in your hint. Note that for this new ad unit, the reward amount value is different from that of the existing ad unit. Name the ad unit "game over 2" and save.

That's it on the AdMob front end.

Now we have a separate Rewarded Video ad unit that gives a hint that covers less of the screen. The next thing you will do is to set up an experiment so that you can progressively ramp up the new ad unit and sunset the existing one, while monitoring user engagement metrics. This experiment involves changes to both your project code and the Firebase console.

To achieve this, you will change your project code so that the app retrieves the ad unit ID dynamically. On the Firebase console, you will create a test user group that sees the new ad unit, and ramp this group up from 20% of all users to 100%.

Modify build.gradle

  1. Update your app module build.gradle file. This is app/build.gradle in your project. Add the following line to your dependencies block.
compile 'com.google.firebase:firebase-config:10.2.1'
  1. Sync Project with Gradle Files (click Sync Now in the IDE prompt.)

Initialize Firebase Components

  1. As you will work with Google Analytics for Firebase and Remote Config in multiple points, in your code (e.g. GameActivity and FailActivity), create references to the singleton Remote Config object and Firebase Analytics object, as shown in the following.

FailActivity.Java

public class FailActivity extends AppCompatActivity {
   ...
   private FirebaseAnalytics mFirebaseAnalytics;
   ...
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);

   ...
}

GameActivity.Java

public class GameActivity extends AppCompatActivity {
   ...
   private FirebaseAnalytics mFirebaseAnalytics;
   private FirebaseRemoteConfig mFirebaseRemoteConfig;
   ...
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
        mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
   ...
}
  1. Enable developer mode for RemoteConfig for test purposes.

GameActivity.Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...
   mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
   FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
               .setDeveloperModeEnabled(true)
               .build();
   mFirebaseRemoteConfig.setConfigSettings(configSettings);
   ...
}
  1. Next, enable in-app default values for RemoteConfig. Set the in-app default values for RemoteConfig variables so that even if the device is offline, the app can still run. In this example, you will set a default for the ad unit ID in the onCreate method in GameActivity.java.

GameActivity.java

protected void onCreate(Bundle savedInstanceState) {
   ...
   mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
   mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
   FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
           .setDeveloperModeEnabled(true)
           .build();
   mFirebaseRemoteConfig.setConfigSettings(configSettings);

   HashMap<String, Object> defaults = new HashMap<>();
   defaults.put("game_over_rewarded_video_adunit_id", DEFAULT_AD_UNIT_ID);
   mFirebaseRemoteConfig.setDefaults(defaults);

Log Events in code

Google Analytics for Firebase automatically logs a number of generic events. In order to measure how many users have cleared the game or failed the game, you will log two more custom events - stage_clear and stage_failed, so that you can evaluate the experiment. You will log the events using the following names.

Go to GameActivity.java and add the following code.

  1. Add a logEvent call as the following in the clearStage() method.
private void clearStage () {
   mFirebaseAnalytics.logEvent("stage_clear", null);
...
  1. Add a logEvent call as the following in the failStage() method.
private void failStage () {
   mFirebaseAnalytics.logEvent("stage_failed", null);
...

Fetch values from server

  1. Go to GameActivity.java and create a new method that fetches and applies all server-side parameters. In a later step in this codelab, you will define a server-side parameter for the ad unit ID.

GameActivity.java

private void fetchSettings() {
   OnCompleteListener<Void> onCompleteListener = new OnCompleteListener<Void>() {
       @Override
       public void onComplete(@NonNull Task<Void> task) {
           if (task.isSuccessful()) mFirebaseRemoteConfig.activateFetched();
       }
   };

   if (mFirebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled()) {
       // This forces Remote Config to fetch from server every time.
       mFirebaseRemoteConfig.fetch(0).addOnCompleteListener(this, onCompleteListener);
   } else {
       mFirebaseRemoteConfig.fetch().addOnCompleteListener(this, onCompleteListener);
   }
}
  1. Fetch the RemoteConfig values at onCreate (in FailActivity), as the following. Keep in mind that once the values are fetched, they will be cached. See help center article for more details. In this codelab, you will fetch the value only within onCreate. Also note that, since fetchSettings() refers to mFirebaseRemoteConfig, make sure it is called after mFirebaseRemoteConfig is initialized and developer mode is enabled.

GameActivity.java

protected void onCreate(Bundle savedInstanceState) {
    ... 
    fetchSettings();
}

Apply Remote Config values to app logic

Next, when requesting ads, instead of using the static DEFAULT_AD_UNIT_ID constant, use the the ad unit id remotely fetched, and apply it to the ad request.

String adUnitID = mFirebaseRemoteConfig.getString("game_over_rewarded_video_adunit_id");
...
mAd.loadAd(
   adUnitID,
   new AdRequest.Builder().build()
);
...

User Property Tracking

To help Firebase Analytics record the setting for the reward issued to this user, store the reward value into a user property so that gets associated with all of this user's events.

Add the following code in the onRewarded method in FailActivity.

FailActivity.java

public void onRewarded(RewardItem reward) {
   mRewardItem = reward;
   mFirebaseAnalytics.setUserProperty(
      "reward_amount",
      new Integer(reward.getAmount()).toString()
   );
}

In this step, you will create a test user group on the Firebase console that sees the new ad unit. Users in this group will see the ad unit with 30 units of reward as an experiment, and the rest of the users will still see 50 units of reward. You will then ramp this group from 20% to 100%.

Create Remote Config parameter in Firebase

  1. Go to the Firebase console and select the MonetizationCodelab project you created earlier. Click Remote Config -> Add Your First Parameter. We create this remote parameter to dynamically change the app's behavior (in this case, the ad unit ID) for test users and default users.
  2. Name the parameter "game_over_rewarded_video_adunit_id" and set its value to the ad unit ID for the "game over 1" ad unit you created earlier.

Note this is the the same as the string you passed to the Firebase Remote Config API in the previous step.

String adUnitID = mFirebaseRemoteConfig.getString("game_over_rewarded_video_adunit_id");
  1. Click ADD PARAMETER and you should see the following.

  1. Click the parameter to trigger the edit mode, choose Add value for condition and then Define new condition.

  1. Name this condition "Reward Amount Test 30". Make this condition apply if "User in random percentile <= 20%" to create a randomly chosen 20% user group. Then click CREATE CONDITION.

  1. Next, set the ad unit ID of AdMob ad unit "game over 2" as the value for "Reward Amount Test 30". Then click UPDATE.

Finally, push the PUBLISH CHANGES button to make this configuration live to the users of the app.

Testing the app

Once the app is pushed live on the app store (in this codelab, compile the project and test the app on your test device), 20% of your users will see rewarded ads through "game over 2" ad unit, with a reward that hides 30% of the screen; 80% of of your users will be seeing ads through "game over 1" ad unit as before. Test your app on your test device and see which group your app instance falls in.

Test User Group (20%)

Default User Group (80%)

Monitor User Engagement Metrics (optional)

Goto Firebase console, from Analytics -> Dashboard -> Add Filter, choose user property reward_amount 30 as the filter, and compare this against reward_amount 50.

Look at whether the test group shows a lift or drop in terms of User Engagement (Daily Engagement, Daily Engagement per user) and in-app purchases (ARPU and ARPPU).

Since this is a codelab, you will not see data on real users and traffic, but to get a flavor of this, you can access the Firebase demo project to see a live sample. From Analytics -> Dashboard -> Add Filter, choose different user properties, such as ad_frequency=2 and ad_frequency=3 as the filter, and see how user engagement metrics change.

Ramp up the change from 20% to 100%

Now let's say you see good results with the new implementation and decide to roll this out to all of your users.

  1. Go to Firebase console for the project we created. Click Remote Config -> Conditions.
  2. Edit "Reward Amount Test 30" condition, change "User in random percentile <= 20%" to "User in random percentile <= 100%".

  1. Save condition and click PUBLISH CHANGES.

Now, restart your app on test device and you (as well as all your users) should see the new implementation.

Test User Group (100%)

Default User Group (0%)

Ramp down the change to 0%

In the other possible scenario, when you see negative results about your new implementation, and you decide to ramp down the experiment group and roll back to 100% existing implementation. Go to the same place: Remote Config -> Conditions and change "Reward Amount Test 30" condition, so that it contains "User in random percentile <= 0%". Push the change live and run the game again to see it is back to the existing implementation.

Test User Group (0%)

Default User Group (100%)

You've reached the end of the codelab, you now can make go/no-go decisions on a new ad implementation based on data.

Learn More