Boost Engagement with the new AdMob Next Gen Ad Interstitials in Jetpack Compose

Mobile advertising in today’s dynamic market is seen everywhere from your favorite website till your Android or iOS apps. This is used as strategy to keep some content free of charge in exchange of in-app ads to the users.

Google dominates the digital advertising market holding most of the global advertising revenue. Hence, they develop an SDK for developer to integrate and displaying in-app ads easier which is the Google AdMob. It is mobile advertising platform that helps app developer monetize their apps by displaying these in-app ads. In such manner developers can earn some revenue from a vast network of advertisers, while enabling advertisers to reach their target audience within the mobile apps.

AdMob simplifies this complex process of in-app advertising by providing developers with an AdMob SDK (Software Developer Kit). That enables them to integrate it into their applications, creating designated “ad units” where ads can be displayed. Ones integrated it leverages Google’s immense advertising ecosystem to automatically deliver relevant and high-performing ads to app users. These ads are generated and paid for by advertisers (in most cases are companies), with developers earning revenue for impressions, clicks or other user interactions with the ads.

Beside simply showing ads, AdMob also offers a suite of tools and feature to optimize monetization, enhance user experience and provide valuable insight into ad performance. The goal is to empower developers to focus on building the app while AdMob handles the task of ad serving, targeting and payment.

In this way any app developer looking into transform their passion into a profitable venture, AdMob provides a robust and accessible solution for generating sustainable income through in-app advertising.

AdMob Next Gen Ads SDK

The current Android AdMob SDK provide such feature and ability. Recently Google introduce a brand new AdMob SDK called AdMob Next Gen Ads which improve ads loading performance and the ability to pre-fetch ads for a smoother ad display experience.

Configure your app

To configure your app, add the corresponding dependency and initialize MobileAd by following the steps in the following link simplification reasons, we are going to use the dedicated sample AdMob app ID: 

ca-app-pub-3940256099942544~3347511713

UMP SDK implementation (Important)

Before implementing the Next Gen Ads SDK in your Android app, you must get consent from the user before proceeding. This is important for data collection, especially under regulations like GDPR (General Data Protection Regulation) in the EEA (European Economic Area) and the CCPA (California Consumer Privacy Act).

To comply with these regulations, Google introduced the UMP (User Messaging Platform) SDK for developers.    

For the full guide on how to implement it, read the following article.

Interstitial ads (using AdMob Next Gen Ad SDK)

An interstitial ad in AdMob is a full-screen ad that covers the entire screen and appears at natural transition points in an app. Such a transition can be a news article, a game level or a task completion.

Interstitial ads have some key features:

  • Full-screen format: To ensure the user’s full attention
  • Skippable or non-skippable: It can be configured to enable the user to skip the ad after a few seconds.
  • Triggered at logical breaks: Ensures it doesn’t ruin the user experience
  • Effective monetization: They generate higher revenue (eCPMs) because of their visibility and engagement potential, often higher revenue compared to banner Ads

Full-screen format

As the name “interstitial” already refers to something between things. In the context of Android Development, it covers the screen when transitioning between two activities, fragment or Composables. Due to its full-screen nature, it covers the interface of its host app, which leads to higher user engagement. When an app shows such an ad, the user has the option to either tap on the ad (which triggers an onClick) or close it and return to the app.

Skippable or non-skippable

The standard interstitial ads can be skippable or non-skippable. When it becomes visible, there is always a clear close button (usually an “X” or “Skip Ad”) that allows a user to dismiss the ad. In case of a video interstitial ads the timing of when this close option appears can vary. In some cases, it can be delayed by 5 seconds. This ensures the user has the time to decide whether to continue or skip it. On the other hand, a rewarded interstitial shows the skip button when the video ends.

Triggered at logical breaks

This is a key decision when implementing interstitial ads in your Android app. Determining the right moment to show them. It is crucial for several key reasons, primarly balancing user experience (UX) with monetization goals:

  • User Experience (UX) preservation

Interstitial ads by their nature interrupt the user’s flow. Showing them at inappropriate times can be highly disruptive, frustrating and annoying. Furthermore, users might leave bad reviews if they feel bombarded by ads (not only interstitial but all other ad types). This might also start a downward spiral, from an increase in the number of uninstallations, reduced engagement, until the user abandons your app altogether.

Another important aspect that needs to be considered is poorly timed ads, especially those that appear suddenly when a user is about to tap on something else. This can lead to accidental clicks, and while it might seem like a revenue boost in the short term, it can negatively impact the user experience and also be flagged by ad networks as invalid traffic (in worse cases your AdSense account may be suspended).

  • Ad Effectiveness and Monetization

When done the right way, users are more likely to be receptive or at least less annoyed. Users might be more genuinely interested in ads if they aren’t feeling imposed on. This may lead to a better Click-Through Rates (CTRs) and a higher eCPMs (Effective Cost Per Mille/Thousand Impressions). In such a scenario, the ad network often rewards apps that provide good user experiences and genuine engagement with higher paying ads. One thing to avoid is Ad Blindness, this happens if ads are shown too frequently or predictably in a disruptive way. Users may automatically ignore or dismiss ads without even processing them so in order to prevent this you have to very strategic on where to place them.

  • Policy Compliance (e.g. Google AdMob/AdSense)

The Google advertising platform also has strict policies regarding the implementation of interstitial ads. Violating these policies can result in ad serving restrictions and Account suspension. Such action can be for example:

  • Showing ads that trigger repeated user actions
  • Ads when app load/exit unexpectedly
  • Showing ads that interfere with normal app usage.

Scenarios when interstitial ads can be shown

As described above it has to be shown at natural breaks or transition points in your app to minimize disruption and maximize engagement. This can be:

  • Between game levels (Natural pause where the user expect a transition)
  • After a significant task completion (After saving a document, finish an edit or successfully uploading a file)
  • When the user is about to receive a bonus reward (Rewarded interstitial)
  • During screen loading (if the load is significant)
  • Moving from one major section of the app to another (e.g. from news list to news detail screen).

Scenarios when not to show interstitial ads

App flows where it is not recommended are:

  • On App Launch (against many ad network policies)
  • On App Exit (disruptive and against policies)
  • Repeatedly after each minor action (can quickly become frustrating)
  • Immediately after clicking a button (leading to accidental clicks and frustration)

Implementation

The implementation of such an ad is straightforward since the Next Gen Ad SDK takes care of everything for you. For our test interstitial ad we will be using the following adUnit:

ca-app-pub-3940256099942544/1033173712
@Composable
fun InterstitialAds() {

    val activity = LocalActivity.current
    val isLoadingAd = remember { mutableStateOf(false) }
    val interstitialAdUnit = NextGenAdUnit.InterstitialAd

    if (activity == null) {
        InterstitialAdViewFailedPlaceHolder()
        return
    }

    Box(modifier = Modifier.fillMaxSize()) {

        Column(
            modifier = Modifier
                .align(Alignment.Center)
                .fillMaxWidth(),
            verticalArrangement = Arrangement.spacedBy(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {

            Text("Interstitial example")
            Button(
                enabled = !isLoadingAd.value,
                onClick = {
                    isLoadingAd.value = true
                    MobileAdsManager.fetchInterstitialAd(adUnit = interstitialAdUnit) { interstitialAd ->
                        isLoadingAd.value = false
                        interstitialAd?.let {

                            it.adEventCallback = object : InterstitialAdEventCallback {

                                override fun onAdShowedFullScreenContent() {
                                    super.onAdShowedFullScreenContent()
                                    println("[interstitial ad] - onAdShowedFullScreenContent")
                                }

                                override fun onAdDismissedFullScreenContent() {
                                    super.onAdDismissedFullScreenContent()
                                    println("[interstitial ad] - onAdDismissedFullScreenContent")
                                }

                                override fun onAdClicked() {
                                    super.onAdClicked()
                                    println("[interstitial ad] - onAdClicked")
                                }

                                override fun onAdFailedToShowFullScreenContent(
                                    fullScreenContentError: FullScreenContentError
                                ) {
                                    super.onAdFailedToShowFullScreenContent(fullScreenContentError)
                                    println("[interstitial ad] - onAdFailedToShowFullScreenContent - ${fullScreenContentError.message}")
                                }

                                override fun onAdImpression() {
                                    super.onAdImpression()
                                    println("[interstitial ad] - onAdImpression")
                                }

                                override fun onAdPaid(value: AdValue) {
                                    super.onAdPaid(value)
                                    println("[interstitial ad] - onAdPaid - ${interstitialAdUnit.id}")
                                    println("[interstitial ad] - onAdPaid (micros: ${value.valueMicros})")
                                    println("[interstitial ad] - onAdPaid (currency code ${value.currencyCode})")
                                    println("[interstitial ad] - onAdPaid (precision type ${value.precisionType})")
                                }
                            }
                            it.show(activity)
                        } ?: run {
                            Toast.makeText(
                                activity,
                                "Failed loading interstitial ad",
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                    }
                }
            ) {
                Text("Show")
            }
        }

        AdLoadingView(
            visible = isLoadingAd.value,
            modifier = Modifier
                .fillMaxSize()
                .align(alignment = Alignment.Center)
        )
    }
}
@Composable
private fun InterstitialAdViewFailedPlaceHolder(modifier: Modifier = Modifier) {

    Box(
        modifier = modifier
            .fillMaxWidth()
            .height(400.dp)
            .background(color = Color.LightGray)
    ) {
        androidx.compose.material.Text(
            "Failed to load interstitial Ad View", color = Color.Black, modifier = Modifier.align(
                Alignment.Center
            )
        )
    }
}

Interstitial ads are a powerful monetization tool due to their higher eCPM (Effective Cost Per Mille/Thousand Impressions). It all comes down to the placement of such ads since it is a very delicate process that determines the long-term app success. The goal is to maximize revenue opportunities without sacrificing the user experience.

One rule of thumb 👍
Always prioritize the user’s journey and analyze your app for natural breaks.

Our final result:

See our GitHub repository for the example code.