Ads are a crucial part of your app's overall user experience. Good ad implementations can help improve your overall app experience and even improve user retention and engagement. For example, Rewarded ads enable you to reward users with in-app currency or items for watching video ads, so that users can reach new heights where otherwise they may get stuck and would have churned.

However, making an excellent ads experience isn't easy. You may have questions like: How often should you show these ads? Where and when should you show them? What should the award be? Unfortunately, the answer differs from app to app and from placement to placement. There is no one-size-fits-all answer.

With Google Analytics for Firebase, AdMob, and several other powerful yet easy-to-use tools that Firebase offers, fine tuning your app in a data driven way has become much easier and more streamlined. Today, we'll be showing you how you can get started!

What you'll build

This codelab is the first of three codelabs that will guide you through building an app called Awesome Drawing Quiz, a game that lets players guess the name of the drawing. It will demonstrate how you can incorporate Rewarded Ads and Firebase services in your game.

In this codelab, you'll integrate Google Analytics for Firebase to record some important app events. Also, you'll learn how to read the app analytics shown in the Firebase console.

What you'll learn

What you'll need

How would you rate your level of experience with AdMob?

Novice Intermediate Proficient

How would you rate your level of experience with Firebase?

Novice Intermediate Proficient

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 named admob-firebase-codelabs-android.

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

$ git clone https://github.com/googlecodelabs/admob-firebase-codelabs-android

The repository contains four folders as follows:

Import the starter app

Launch Android Studio, choose "Import project" in the welcome screen. Then select the 101-base directory from the code you have downloaded.

You should now have the project open in Android Studio.

The starter app already includes a dedicated Rewarded Video Ad Unit for your convenience. You are entirely free to skip this step if you don't want to create a new one under your AdMob account.

To create a new AdMob app in your account, please follow the instructions as follows:

  1. Go to the AdMob Console.
  2. From the Apps menu, click "Add App".
  3. When asked "Have you published your app on Google Play or the App Store," answer "NO."
  4. Name the app "Awesome Drawing Quiz," choose "Android" as the Platform, then click "Add".

Once you created an AdMob app in your account, follow the steps as described in the below to create a new Rewarded Video Ad Unit.

  1. Click the Apps menu in AdMob frontend, then select "Awesome Drawing Quiz" from the app list.
  2. Click the Ad units menu, then click ADD AD UNIT to create a new Rewarded Video ad unit.
  3. Select Rewarded for the Ad format.



  4. Provide the name of the ad unit as you prefer. Then, set reward amount to 1, and reward item to "hint" (these are the reward the app currently gives to users). And click CREATE AD UNIT to create a new Rewarded Video ad unit.



  5. When successfully created, you will see the instructions like the following.



  6. Go back to the Android project, and update the AdMob app id and ad unit id constants to the ones that you have created in the previous step.

strings.xml

<!-- Update the value with your AdMob app id -->
<string name="admob_app_id">YOUR_ADMOB_APP_ID</string>

GameActivity.kt

// Update the value with your Rewarded Video ad unit id
private const val AD_UNIT_ID = "<YOUR_AD_UNIT_ID>";

Create a new project from the Firebase Console

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

Add the 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.codelab.awesomedrawingquiz
  3. Set a nickname for your app: Awesome Drawing Quiz
  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 android_studio_folder.pngapp directory in your project.

Declare dependency versions

Let's start by adding the version of each dependency required to integrate Firebase in the project. Open dependencies.gradle file located at the project root, then add google-services plugin, Firebase Analytics SDK and Firebase Core SDK version.

dependencies.gradle

ext {
    ...

    // TODO: Declare google-services plugin version (101)
    googleServicesPluginVersion = '4.2.0'

    ...

    // TODO: Declare Firebase Analytics SDK version (101)                                                                                                                                                                                                   
    firebaseAnalyticsVersion = '16.0.6'

    // TODO: Declare Firebase Core SDK version (101)
    firebaseCoreVersion = '16.0.6'

    ...
}

Apply google-services plugin to your app

The google-services plugin uses the google-services.json file to configure your application to use the Firebase.

Add google-services as a classpath in the build.gradle file located at the project root directory.

build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ...
    
    dependencies {
        classpath "com.android.tools.build:gradle:$androidPluginVersion"

        // TODO: Add google-services plugin (101)
        classpath "com.google.gms:google-services:$googleServicesPluginVersion"

        ...
    }
}

...

Then, apply the google-services plugin by adding a line in app/build.gradle file as follows:

app/build.gradle

apply plugin: 'com.android.application'

android {
    ...
}

dependencies {
    ...
}

// TODO: Apply google-services plugin (101)
apply plugin: 'com.google.gms.google-services'

Add Firebase SDK to the project

Add the Analytics SDK and the Core SDK to the app dependency.

app/build.gradle

apply plugin: 'com.android.application'

android {
    ...
}

dependencies {
    ...

    // TODO: Add Firebase Analytics dependency (101)
    implementation "com.google.firebase:firebase-analytics:$firebaseAnalyticsVersion"

    // TODO: Add Firebase Core dependency (101)
    implementation "com.google.firebase:firebase-core:$firebaseCoreVersion"

    ...
}

...

Sync your project with gradle files

To make sure that all dependencies are available to your app, sync your project with gradle files. Select File > Sync Project with Gradle Files menu to sync your project with gradle files.

Complete the steps below to link your apps to Firebase.

  1. Sign in to your AdMob account at https://apps.admob.com.
  2. Click Apps in the sidebar.
  3. Select "Awesome Drawing Quiz". If you don't see it in the list of recent apps, you can click View all apps to search a list of all of the apps you've added to AdMob.
  4. Click App settings in the sidebar.
  5. Click Link to Firebase.
  6. Select "Link to an existing Firebase project and create a new Firebase app" option. Then Select "Awesome Drawing Quiz" project from the dropdown menu.
  7. Once you click the "CONTINUE" button, you'll see "Successfully linked" message. Click the "DONE" button to finish.

Once you link your AdMob app to Firebase Project, it will unlock some additional features both on AdMob and Firebase console as follows:

Revenue card (AdMob)

From the Revenue card, you can take a holistic look at all possible revenue streams in a single place. Supported revenue sources are as follows:

User metrics card (AdMob)

From the user metrics card, you can see how changes to your ads experience might impact user behavior.

Rewarded Ads Report (AdMob)

The Rewarded Ads Report offers a variety of metrics that will help publishers understand how users are interacting with their rewarded ads.

Total revenue card (Firebase)

After you link your AdMob app to Firebase, Total revenue card on Firebase dashboard will display the revenue from the AdMob along with in-app-purchases and e-commerce purchases.

Ad events reporting (Firebase)

Ad-specific events (click, impression, and reward events) are automatically collected and available for use in Google Analytics for Firebase.

Once you compile and run the project, you'll see the following screen when the app starts.


Once you click ‘START A GAME,' you'll see a drawing on the screen. Your mission is to guess the name of the drawing by using the hint displayed on the top, from which you can infer the first letter and the length of the drawing's name.


If you don't have any idea what the name of the drawing is, you can skip the level by clicking the ‘SKIP' button.

You may want an additional clue that helps you guess the answer. You can get an extra clue by clicking the 'HINT' button and watching a Rewarded Video ad. After you complete watching the ad, one extra letter will be disclosed as a reward.

To deeply understand the user journey in the Awesome Drawing Quiz, you will define a few custom events that track user's behavior in the game as follows:

Event name

Triggered...

Parameters

game_start

when a user starts a new game

none

level_start

when a user starts a new level (a new drawing quiz) within a stage.

(there are 6 levels in one stage)

level_name

level_wrong_answer

when a user submits a wrong answer

level_name

ad_reward_prompt

when a user taps the hint button, and is prompted to watch a Rewarded Video Ad

ad_unit_id

ad_reward_impression

when a user starts to watch a Rewarded Video Ad

ad_unit_id

level_success

when a user submits a correct answer (clears a level)

level_name, number_of_attempts, elapsed_time_sec, hint_used

level_fail

when a user skips a level

level_name, number_of_attempts, elapsed_time_sec, hint_used

game_complete

when the game is over

number_of_correct_answers

Description of each parameter associated with each event is as follows:

Event name

Parameter name

Description

level_start

level_name

Name of the drawing shown in the level (e.g., "banana")

level_wrong_answer

level_name

Name of the drawing shown in the level (e.g., "banana")

ad_reward_prompt

ad_unit_id

An ad unit id used to display a Rewarded Video Ad

ad_reward_impression

ad_unit_id

An ad unit id used to display a Rewarded Video Ad

level_success

level_name

Name of the drawing shown in the level (e.g., "banana")

level_success

number_of_attempts

Number of attempts made to clear a level

level_success

elapsed_time_sec

Elapsed time to clear a level, in seconds

level_success

hint_used

Whether a user used a hint (watched a Rewarded Video Ad) or not to clear a level (1: used a hint / 0: cleared a level without a hint)

level_fail

level_name

Name of the drawing shown in the level (e.g., "banana")

level_fail

number_of_attempts

Number of attempts made to clear a level

level_fail

elapsed_time_sec

Elapsed time to clear a level, in seconds

level_fail

hint_used

Whether a user used a hint (watched a Rewarded Video Ad) or not to clear a level (1: used a hint / 0: cleared a level without a hint)

game_complete

number_of_correct_answers

Number of levels cleared in the game

Create a helper class for logging custom events

To log the analytics event with ease, you will create a helper class to manage custom events.

First, create a new Kotlin file (not a Kotlin Class) and name it QuizAnalytics.kt under com.google.codelab.awesomedrawingquiz package. Create fields that define the name of your custom events and their parameters.

QuizAnalytics.kt

private const val EVENT_AD_REWARD_PROMPT = "ad_reward_prompt"

private const val EVENT_AD_REWARD_IMPRESSION = "ad_reward_impression"

private const val EVENT_LEVEL_FAIL = "level_fail"

private const val EVENT_LEVEL_SUCCESS = "level_success"

private const val EVENT_LEVEL_WRONG_ANSWER = "level_wrong_answer"

private const val EVENT_GAME_START = "game_start"

private const val EVENT_GAME_COMPLETE = "game_complete"

private const val PARAM_AD_UNIT_ID = "ad_unit_id"

private const val PARAM_ELAPSED_TIME_SEC = "elapsed_time_sec"

private const val PARAM_HINT_USED = "hint_used"

private const val PARAM_NUMBER_OF_ATTEMPTS = "number_of_attempts"

private const val PARAM_NUMBER_OF_CORRECT_ANSWERS = "number_of_correct_answers"

Next, add extension functions that help you log custom events in your game. Note that most of the custom events include parameters so you have more context of each event. Also note that a couple of event names and parameters (FirebaseAnalytics.Event.LEVEL_NAME and FirebaseAnalytics.Event.LEVEL_START) are already defined by Analytics, so we're going to use those.

QuizAnalytics.kt

...

fun FirebaseAnalytics.logGameStart() = logEvent(EVENT_GAME_START, null)

fun FirebaseAnalytics.logLevelStart(levelName: String) {
  logEvent(FirebaseAnalytics.Event.LEVEL_START, Bundle().apply {
    putString(FirebaseAnalytics.Param.LEVEL_NAME, levelName)
  })
}

fun FirebaseAnalytics.logLevelWrongAnswer(levelName: String) {
  logEvent(EVENT_LEVEL_WRONG_ANSWER, Bundle().apply {
    putString(FirebaseAnalytics.Param.LEVEL_NAME, levelName)
  })
}

fun FirebaseAnalytics.logAdRewardPrompt(adUnitId: String) {
  logEvent(EVENT_AD_REWARD_PROMPT, Bundle().apply {
    putString(PARAM_AD_UNIT_ID, adUnitId)
  })
}

fun FirebaseAnalytics.logAdRewardImpression(adUnitId: String) {
  logEvent(EVENT_AD_REWARD_IMPRESSION, Bundle().apply {
    putString(PARAM_AD_UNIT_ID, adUnitId)
  })
}

fun FirebaseAnalytics.logLevelSuccess(
    levelName: String,
    numberOfAttempts: Int,
    elapsedTimeSec: Int,
    hintUsed: Boolean
) {
  logEvent(EVENT_LEVEL_SUCCESS, Bundle().apply {
    putString(FirebaseAnalytics.Param.LEVEL_NAME, levelName)
    putInt(PARAM_NUMBER_OF_ATTEMPTS, numberOfAttempts)
    putInt(PARAM_ELAPSED_TIME_SEC, elapsedTimeSec)
    putInt(PARAM_HINT_USED, if (hintUsed) 1 else 0)
  })
}

fun FirebaseAnalytics.logLevelFail(
    levelName: String,
    numberOfAttempts: Int,
    elapsedTimeSec: Int,
    hintUsed: Boolean
) {
  logEvent(EVENT_LEVEL_FAIL, Bundle().apply {
    putString(FirebaseAnalytics.Param.LEVEL_NAME, levelName)
    putInt(PARAM_NUMBER_OF_ATTEMPTS, numberOfAttempts)
    putInt(PARAM_ELAPSED_TIME_SEC, elapsedTimeSec)
    putInt(PARAM_HINT_USED, if (hintUsed) 1 else 0)
  })
}

fun FirebaseAnalytics.logGameComplete(
    numberOfCorrectAnswers: Int
) {
  logEvent(EVENT_GAME_COMPLETE, Bundle().apply {
    putInt(PARAM_NUMBER_OF_CORRECT_ANSWERS, numberOfCorrectAnswers)
  })
}

Log analytics events in the game

In GameActivity, create a lazy property that holds FirebaseAnalytics instance as follows:

GameActivity.kt

class GameActivity : AppCompatActivity(), RewardedVideoAdListener {

  ...

  // TODO: Get a reference to FirebaseAnalytics instance (101)
  private val firebaseAnalytics by lazy {
    FirebaseAnalytics.getInstance(this) 
  }

  private val isHintAvailable: Boolean
    get() = viewModel.isHintAvailable && rewardedVideo.isLoaded
  
  ...
}

Next, in onCreate() function, call logGameStart() to indicate a game has started. Since logGameStart() is an extension function of FirebaseAnalytics class, you can call it from the instance of the FirebaseAnalytics class.

GameActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_game)

  ...

  // TODO: Log game_start event (101)
  firebaseAnalytics.logGameStart()
}

Next, in setupViewModel() function, add calls to log custom events as follows:

GameActivity.kt

private fun setupViewModel() {
  viewModel.registerGameEventListener {
    when (it) {
      is NewLevelEvent -> {
        Log.d(TAG, "Round loaded: $it")
        // TODO: Log level_start event (101)
        firebaseAnalytics.logLevelStart(it.drawing.word)

        ...
      }

      is ClueUpdateEvent -> {
        ...
      }

      is WrongAnswerEvent -> {
        Log.d(TAG, "Wrong Answer: $it")
        // TODO: Log level_wrong_answer event (101)
        firebaseAnalytics.logLevelWrongAnswer(it.drawing.word)

        ...
      }

      is LevelClearEvent -> {
        Log.d(TAG, "Round cleared: $it")
        // TODO: Log level_success event (101)
        firebaseAnalytics.logLevelSuccess(
            it.drawing.word, it.numAttempts, it.elapsedTimeInSeconds, it.isHintUsed
        )

        ...
      }

      is LevelSkipEvent -> {
        Log.d(TAG, "Round skipped: $it")
        // TODO: Log level_fail event (101)
        firebaseAnalytics.logLevelFail(
            it.drawing.word, it.numAttempts, it.elapsedTimeInSeconds, it.isHintUsed
        )

        ...
      }

      is GameOverEvent -> {
        Log.d(TAG, "Game over: $it")
        // TODO: Log game_complete event (101)
        firebaseAnalytics.logGameComplete(it.numCorrectAnswers)

        ...
      }
    }
  }
}

Finally, add a call to logAdRewardPrompt() and logAdRewardImpression() functions to track user's behavior on the Rewarded Video Ad.

GameActivity.kt

private fun showHintConfirmDialog() {
  // TODO: Log ad_reward_prompt event (101)
  firebaseAnalytics.logAdRewardPrompt(AD_UNIT_ID)

  AlertDialog.Builder(this)
      .setTitle(R.string.need_a_hint)
      .setMessage(R.string.need_a_hint_description)
      .setPositiveButton(android.R.string.ok) { _, _ -> showRewardedVideoAd() }
      .setNegativeButton(android.R.string.no, null)
      .show()
}

...

override fun onRewardedVideoStarted() {
  Log.d(TAG, "onRewardedVideoStarted()")
  // TODO: Log ad_reward_impression event (101)
  firebaseAnalytics.logAdRewardImpression(AD_UNIT_ID)
}

You can use DebugView to verify events being correctly logged. DebugView enables you to see the raw event data logged by your app on development devices in near real-time.

This is very useful for validation purposes during the instrumentation phase of development and can help you discover errors and mistakes in your analytics implementation.

Enable debug mode

Generally, events logged in your app are batched together over a period of approximately one hour and uploaded together. To validate your analytics implementation on the fly, you need to enable Debug mode on your development device to upload events with minimal delays.

First, open Terminal tool in Android Studio. It is located at the bottom toolbar.

Then execute the following command (make sure test Android device is connected to your computer or Android Emulator is running):

adb shell setprop debug.firebase.analytics.app com.google.codelab.awesomedrawingquiz

This behavior persists until you explicitly disable Debug mode by executing the following command:

adb shell setprop debug.firebase.analytics.app .none.

Debug Analytics events with DebugView

Once you have enabled Debug mode on your test device, go to the Firebase console and select DebugView from the menu. Then, on your test device, play your game to see events being logged and shown on the DebugView report.

You can access detailed information about each event by clicking the event name. As an example, the following screenshot shows parameter details associated with the level_start event.

Please refer to DebugView help center article for more details.

Google Analytics for Firebase will collect total number of event counts by default, but reporting for custom parameters needs to be turned on explicitly for each event parameter you're interested in. Once this is enabled, Google Analytics for Firebase will display additional cards to show the stats for custom parameters.

To register custom parameters for an event:

  1. Go to the Firebase console and select the Awesome Drawing Quiz project you created earlier.
  2. Click Events from the navigation menu.
  1. In the row for the event you want to modify, click > Edit Parameter reporting.

  1. In the Enter parameter name field, enter the name of the parameter you'd like to register.

    Note: If no match is found, just enter the parameter name then click ADD.
  2. Refer to the table below, and set the Type field to Text or Number accordingly. For numeric parameters, make sure you set the Unit of Measurement field as well.
  3. Click the SAVE button to finish the setup.

Enable parameter reporting on each event listed below.

Event name

Parameter name

Parameter type

Unit of Measurement

level_start

level_name

Text

N/A

level_wrong_answer

level_name

Text

N/A

level_success

level_name

Text

N/A

level_success

number_of_attempts

Number

Standard

level_success

elapsed_time_sec

Number

Seconds

level_success

hint_used

Number

Standard

level_fail

level_name

Text

N/A

level_fail

number_of_attempts

Number

Standard

level_fail

elapsed_time_sec

Number

Seconds

level_fail

hint_used

Number

Standard

game_complete

number_of_correct_answers

Number

Standard

The following example shows custom parameter reporting setup for level_success event:

Once you complete the parameter reporting setup, you'll be able to see parameters associated with each event that has parameter reporting turned on.

As you've added a few events in the game, you should be able to answer the questions regarding the user behavior of the game. Here are a few insights that you can get from the Firebase events report.

Which level has the highest number of wrong answers?

To answer this question, you should find out how many level_wrong_answer events were triggered per each level.

Click the level_wrong_answer from the events report. In the level_wrong_answer event report, find the level_name card. You'll see the values associated to the level_name parameter on that card as follows.

According to the above screenshot, you can easily find out the horizon has the highest number of wrong answers, which means it's difficult to users compared to the other levels.

By using the insight you've got from here, you can decide not to provide difficult levels to novice users to keep a high retention rate.

How many attempts were made to clear a level, on average?

In the Awesome Drawing Quiz, users can submit the answer to each level as much as they want.

Since you've enabled parameter reporting on the number_of_attempts parameter in the level_success event, you can see the detailed metrics for that parameter.

Click the level_success event from the events report. In the level_success event report, find the number_of_attemps card. You'll see the average number of attempts on that card as follows:

You can use the insight from here to optimize the difficulty of the game on average. For example, if the average number of attempts are too close to 1, you may consider making the game a little bit more challenging.

Did users try to solve the question by getting a hint, even though they failed to clear a level at last?

When a user decides to skip a level, a level_fail event is triggered. There can be many reasons for the user's decision.

However, since the game can give them a hint after they watch a Rewarded Video Ad, it's important to know that whether the user tried to clear the level with the help of the hint, at least.

Click the level_fail event from the events report. In the level_fail event report, find the hint_used card. You'll see the average number of hint_used event parameters. Note that when a hint is used it is set to 1 while it is set to 0 when a hint was not used.

If the numbers on the hint_used card are close to 0, it's the signal that the reward (hint) is not quite attractive to the users. Also, you're losing the opportunity to increase the revenue from Rewarded Video Ad.

Therefore, you should consider making the reward to be more helpful to the users, so users can engage the game more deeply as well as the revenue from Rewarded Video Ad can be uplifted.

How many levels were cleared in each game, on average?

There are a total of 6 levels per each game in the Awesome Drawing Quiz. Once the user finishes six levels (no matter they cleared or failed each level), a game_complete event is triggered with number_of_correct_answers as a parameter.

Since number_of_correct_answers indicates how many levels that the user has cleared (provided a correct answer), you can find the answer by looking at the metrics of the number_of_correct_answers parameter.

Click game_complete event from the events report. In the game_complete event report, find the number_of_correct_answers card. You'll see the average number of number_of_correct_answers event parameters.

If the average number of cleared levels is too low, you should consider rearranging the game to help people to beat a level, so they can keep playing your game without losing their interest.

You have completed AdMob+Firebase 101 Android Codelab. You can find the completed code for this Codelab on android_studio_folder.png101-complete_and_102-base folder.

In the next part of the AdMob+Firebase Codelab, you'll learn how to use a funnel to visualize the app event flow. Also, it'll cover how to use the Remote Config and A/B testing to optimize the parameter value in the game without an app update.