<br />

App open ads are an ad format intended for publishers who want to monetize
their app load screens. Your users can close app open ads at any time. When
users bring your app to the foreground, show app open ads.
For more information, see [App open ad guidance](https://support.google.com/admob/answer/9341964).

This guide explains how to integrate app open ads into an Android app.

## Before you begin

Before you continue, do the following:

- [Set up GMA Next-Gen SDK](https://developers.google.com/admob/android/next-gen/quick-start.md.txt).
- Use the test app open ad unit ID `ca-app-pub-3940256099942544/9257395921`.
  - When building and testing your app, make sure that you use test ads rather than live, production ads. If you don't use the test ad unit ID, Google can suspend your account.
  - Before you publish your app, replace this ID with your ad unit ID.
  - For details on GMA Next-Gen SDK test ads, see [Enable test ads](https://developers.google.com/admob/android/next-gen/test-ads.md.txt).

## Understand ad preloading (beta)

[Video](https://www.youtube.com/watch?v=gtCvIEGOwtA)

Ad preloading in GMA Next-Gen SDK automates ad loading and caching.

Ad preloading provides the following benefits:

- **Reference management**: maintains references until ads are shown.
- **Automatic reloading**: loads a new ad when one is retrieved from the cache.
- **Managed retries**: loads a new ad when one fails to load.
- **Expiration handling**: refreshes ads before expiring.
- **Cache optimization**: optimizes the cache order to deliver the highest priority ad.

> [!NOTE]
> **Note:** To load ads manually, see [Load a single app open ad](https://developers.google.com/admob/android/next-gen/app-open/single-load.md.txt).

## Start ad preloading

To begin preloading ads, call the `start` method once
when you initialize GMA Next-Gen SDK. After you call the
`start` method, GMA Next-Gen SDK automatically preloads ads
and retries failed requests for preloaded configurations.

The following example shows how to start preloading ads:


### Kotlin

```kotlin
val adRequest = AdRequest.Builder(adUnitId).build()
val preloadConfig = PreloadConfiguration(adRequest)
AppOpenAdPreloader.start(adUnitId, preloadConfig)
```

### Java

```java
AdRequest adRequest = new AdRequest.Builder(adUnitId).build();
PreloadConfiguration preloadConfig = new PreloadConfiguration(adRequest);
AppOpenAdPreloader.start(adUnitId, preloadConfig);
```

<br />

Replace <var class="readonly" translate="no">AD_UNIT_ID</var> with your ad unit ID.

The previous example shows how to use the ad unit ID as the preload ID. A
preload ID is a string identifier that you create to identify an ad preloading
configuration. If your app requires multiple targeting configurations for the
same ad unit ID, pass a custom string identifier.

Ad preloading doesn't support changing targeting parameters or ad requests.
If you need to change targeting parameters between requests, use
[single loading](https://developers.google.com/admob/android/next-gen/app-open/single-load.md.txt).

## Get and show the preloaded ad

Before showing the ad, call the `pollAd` method.
Don't store the preloaded ad object. When you call the
`pollAd` method, GMA Next-Gen SDK retrieves an available ad
and automatically preloads the next ad in the background. If no ad is
available, GMA Next-Gen SDK returns no ads.
When you have an available ad object, call the `show` method to display the ad. The following example shows how to retrieve and show a preloaded ad:


### Kotlin

```kotlin
private fun pollAndShowAd(activity: Activity, adUnitId: String) {
  // Polling returns the next available ad and loads another ad in the background.
  val ad = AppOpenAdPreloader.pollAd(adUnitId)
  if (ad == null) {
    Log.e(TAG, "App open ad is not available.")
    return
  }

  // Interact with the ad object as needed.
  Log.d(TAG, "App open ad response info: ${ad.getResponseInfo()}")
  ad.adEventCallback =
    object : AppOpenAdEventCallback {
      override fun onAdImpression() {
        Log.d(TAG, "App open ad recorded an impression.")
      }
    }
  ad.show(activity)
}
```

### Java

```java
private void pollAndShowAd(Activity activity, String adUnitId) {
  // Polling returns the next available ad and loads another ad in the background.
  AppOpenAd ad = AppOpenAdPreloader.pollAd(adUnitId);

  // Interact with the ad object as needed.
  if (ad == null) {
    Log.e(TAG, "App open ad is not available.");
    return;
  }

  Log.d(TAG, "App open ad response info: " + ad.getResponseInfo());
  ad.setAdEventCallback(
      new AppOpenAdEventCallback() {
        @Override
        public void onAdImpression() {
          Log.d(TAG, "App open ad recorded an impression.");
        }
      });

  // Show the ad.
  ad.show(activity);
}
```

<br />

When your app reaches an ad placement and can call the `show` method, call the
`pollAd` method. Don't call the
`pollAd` method in preload callbacks or after checking the
`isAdAvailable` method to hold an ad. If you need
to inspect ad metadata before showing the ad,
[read the response info](https://developers.google.com/admob/android/next-gen/app-open.md.txt#peek-at-ad) without removing the ad from the cache.

## Listen to ad events

Before showing the ad, listen to ad events. The following example
registers callbacks for ad events:


### Kotlin

```kotlin
private fun listenToAdEvents() {
  // Listen for ad events.
  val ad = appOpenAd
  if (ad == null) {
    Log.e(TAG, "App open ad is not ready yet.")
    return
  }

  ad.adEventCallback =
    object : AppOpenAdEventCallback {
      override fun onAdShowedFullScreenContent() {
        // App open ad did show.
      }

      override fun onAdDismissedFullScreenContent() {
        // App open ad did dismiss.
        appOpenAd = null
      }

      override fun onAdFailedToShowFullScreenContent(
        fullScreenContentError: FullScreenContentError
      ) {
        // App open ad failed to show.
        Log.e(TAG, "App open ad failed to show: ${fullScreenContentError.message}")
      }

      override fun onAdImpression() {
        // App open ad did record an impression.
      }

      override fun onAdClicked() {
        // App open ad did record a click.
      }
    }
}
```

### Java

```java
private void listenToAdEvents() {
  // Listen for ad events.
  if (appOpenAd == null) {
    Log.e(TAG, "App open ad is not ready yet.");
    return;
  }

  appOpenAd.setAdEventCallback(
      new AppOpenAdEventCallback() {
        @Override
        public void onAdShowedFullScreenContent() {
          // App open ad did show.
        }

        @Override
        public void onAdDismissedFullScreenContent() {
          // App open ad did dismiss.
          appOpenAd = null;
        }

        @Override
        public void onAdFailedToShowFullScreenContent(
            @NonNull FullScreenContentError fullScreenContentError) {
          // App open ad failed to show.
          Log.e(TAG, "App open ad failed to show: " + fullScreenContentError.getMessage());
        }

        @Override
        public void onAdImpression() {
          // App open ad did record an impression.
        }

        @Override
        public void onAdClicked() {
          // App open ad did record a click.
        }
      });
}
```

<br />

## Optional: Listen to preloading events

When you start preloading ads, register for preload events to get notified
when ads are preloaded successfully, fail to preload, or the ad cache is
exhausted.

The following example shows how to register for preloading ad events:


### Kotlin

```kotlin
val preloadCallback =
  object : PreloadCallback {
    override fun onAdFailedToPreload(preloadId: String, adError: LoadAdError) {
      Log.d(TAG, "App open preload ad $preloadId failed to load with error: ${adError.message}")
    }

    override fun onAdsExhausted(preloadId: String) {
      Log.i(TAG, "App open preload ad $preloadId is not available")
    }

    override fun onAdPreloaded(preloadId: String, responseInfo: ResponseInfo) {
      Log.i(TAG, "App open preload ad $preloadId is available")
    }
  }
val adRequest = AdRequest.Builder(adUnitId).build()
val preloadConfig = PreloadConfiguration(adRequest)
AppOpenAdPreloader.start(adUnitId, preloadConfig, preloadCallback)
```

### Java

```java
PreloadCallback preloadCallback =
    new PreloadCallback() {
      @Override
      public void onAdFailedToPreload(@NonNull String preloadId, @NonNull LoadAdError adError) {
        Log.d(
            TAG,
            String.format(
                "App open preload ad %s failed to load with error: %s",
                preloadId, adError.getMessage()));
      }

      @Override
      public void onAdsExhausted(@NonNull String preloadId) {
        Log.i(TAG, String.format("App open preload ad %s is not available", preloadId));
      }

      @Override
      public void onAdPreloaded(@NonNull String preloadId, @NonNull ResponseInfo responseInfo) {
        Log.i(TAG, String.format("App open preload ad %s is available", preloadId));
      }
    };
AdRequest adRequest = new AdRequest.Builder(adUnitId).build();
PreloadConfiguration preloadConfig = new PreloadConfiguration(adRequest);
AppOpenAdPreloader.start(adUnitId, preloadConfig, preloadCallback);
```

<br />

When an ad fails to load, GMA Next-Gen SDK automatically preloads ads and retries
failed requests for preloaded configurations. Don't invoke manual load
requests in failure callbacks. In preloading event callback methods, don't
call the `pollAd`, `destroy`, or
`start` methods. Calling these methods in callbacks
can invoke recursive load loops.

## Optional: Check for ad availability

If you need to know whether an ad is available, check for ad availability. The
following example checks whether a preloaded ad is available:


### Kotlin

```kotlin
private fun isAdAvailable(adUnitId: String): Boolean {
  return AppOpenAdPreloader.isAdAvailable(adUnitId)
}
```

### Java

```java
private boolean isAdAvailable(String adUnitId) {
  return AppOpenAdPreloader.isAdAvailable(adUnitId);
}
```

<br />

## Optional: Set the buffer size

The buffer size controls the number of preloaded ads held in memory. By
default, Google optimizes buffer size to balance memory consumption and ad
serving latency. You can set a custom buffer size to increase or decrease the
number of ads kept in memory. We recommend a buffer size of two preloaded ads.
If most of your traffic comes from low-memory devices, reduce the buffer size.

The following example shows how to set a buffer size:


### Kotlin

```kotlin
val adRequest = AdRequest.Builder(adUnitId).build()
// Define a PreloadConfiguration and set the buffer size to 2 preloaded ads.
val preloadConfig = PreloadConfiguration(adRequest, bufferSize = 2)
AppOpenAdPreloader.start(adUnitId, preloadConfig)
```

### Java

```java
AdRequest adRequest = new AdRequest.Builder(adUnitId).build();
// Define a PreloadConfiguration and set the buffer size to 2 preloaded ads.
PreloadConfiguration preloadConfig = new PreloadConfiguration(adRequest, 2);
AppOpenAdPreloader.start(adUnitId, preloadConfig);
```

<br />

### Preload cache limits

GMA Next-Gen SDK enforces an app-wide limit on the total number of preloaded ads
across all ad units and preload IDs:

- Default limit: Google holds a maximum of six preloaded ads in memory. This limit is shared across all formats and preload IDs.
- We recommend keeping a buffer size of two for each preload ID.

> [!NOTE]
> **Note:** If your app can benefit from an increased app-wide limit, contact your account manager to request an increase.

## Optional: Stop preloading ads

Keep preloading active while your app serves ads. During this time, don't the
`destroy` method. If you don't need to show ads for a
specific preload ID again in the session, you can stop preloading ads. To stop
loading ads for a specific preload ID, call the `destroy`
method with a preload ID. Calling the `destroy` method
removes all preloaded ads associated with the preload ID from the cache.

The following example shows how to stop preloading ads:


### Kotlin

```kotlin
private fun stopPreloading(adUnitId: String) {
  // Stops the preloading and destroy preloaded ads.
  AppOpenAdPreloader.destroy(adUnitId)
}
```

### Java

```java
private void stopPreloading(String adUnitId) {
  // Stops the preloading and destroy preloaded ads.
  AppOpenAdPreloader.destroy(adUnitId);
}
```

<br />

## Optional: Read the response info

Read the next preloaded ad's response info without removing the ad from the
cache. If you need to inspect ad metadata before you show an ad,
read the response info instead of calling the `pollAd`
method.

The following example shows how to read the next preloaded ad response info:


### Kotlin

```kotlin
val responseInfo = AppOpenAdPreloader.peekAdResponseInfo(preloadId)
if (responseInfo == null) {
  Log.e(TAG, "Failed to peek ad response info.")
  return
}

Log.d(TAG, "Peeked ad response ID: ${responseInfo.responseId}")
```

### Java

```java
ResponseInfo responseInfo = AppOpenAdPreloader.peekAdResponseInfo(preloadId);
if (responseInfo == null) {
  Log.e(TAG, "Failed to peek ad response info.");
  return;
}

Log.d(TAG, "Peeked ad response ID: " + responseInfo.getResponseId());
```

<br />

## Handle cold starts and loading screens

A cold start occurs when your app launches from disk, and a warm start occurs
when you reopen the app from memory. During a cold start, you lack a preloaded
ad to show immediately. During a warm start, you might still have a preloaded
ad ready to show.

During a cold start, users might interact with your app before it loads and
shows an ad. To avoid a poor user experience, show app open ads on cold starts
strictly from a loading screen while app assets load. If asset loading
completes and your user reaches the main content before the ad loads, don't show
the ad.

## Recommendations

Follow these recommendations for app open ads:

- Don't show an app open ad on the very first app start.
- If your loading screen finishes loading while the ad is displayed, dismiss the loading screen in the ad dismissed callback method.
- App open ads expire four hours after loading. Don't show an app open ad that has been loaded for more than four hours.