<br />

App open ads appear when your users open or return to your app. Your users can
close app open ads at any time. To monetize your app load screen, use app open
ads. For details, see

[App open ad guidance and best practices](https://support.google.com/admob/answer/9341964).


This guide explains how to integrate app open ads into a React Native app.

## Prerequisites

Before you continue, do the following:

- [Set up Google Mobile Ads SDK for React Native](https://developers.google.com/admob/react-native/quick-start.md.txt).
- [Enable test ads](https://developers.google.com/admob/react-native/test-ads.md.txt) and use the following test ad unit:

### Android

    ca-app-pub-3940256099942544/9257395921

### iOS

    ca-app-pub-3940256099942544/5575463023

## Understand ad preloading

Ad preloading in Google Mobile Ads SDK for React Native 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.

To load ads manually, see the [Load a single app open ad](https://developers.google.com/admob/react-native/app-open/single-load.md.txt) guide.

## Start preloading

To start preloading ads, call the
[`AppOpenAdPreloader.start`](https://developers.google.com/admob/react-native/reference/class/AppOpenAdPreloader#AppOpenAdPreloader.start) method and pass
your `preloadId` value, configuration settings, and event callbacks to monitor
buffer state changes:

```tsx
export function startAppOpenAdPreloader(
  adUnitId: string,
  preloadId: string,
  customPreloadCallback?: PreloadCallback,
): boolean {
  const started = AppOpenAdPreloader.start(
    preloadId,
    {
      request: {adUnitId},
      bufferSize: 2,
    },
    {
      // Called when an ad is preloaded into the buffer.
      onAdPreloaded: (event) => {
        console.log(`App open ad preloaded for ${event.preloadId}`);
        customPreloadCallback?.onAdPreloaded?.(event);
      },
      // Called when an ad fails to preload.
      onAdFailedToPreload: (error: LoadAdError) => {
        console.error('Failed to preload app open ad:', error.message);
        customPreloadCallback?.onAdFailedToPreload?.(error);
      },
      // Called when all preloaded ads in the buffer have been shown.
      onAdsExhausted: () => {
        console.log('App open ad buffer exhausted.');
        customPreloadCallback?.onAdsExhausted?.();
      },
    },
  );
  return started;
}
```

A `preloadId` is a string that uniquely identifies an ad preloading
configuration. If the `adUnitId` is used for only a single preloading
configuration in your app, you can use that ad unit ID as the preload ID. If
your app requires multiple preloaders for the same ad unit ID, pass distinct
strings for each preload ID.

When your app polls a preloaded ad from the buffer, Google Mobile Ads SDK for React Native
requests a replacement ad in the background to refill the buffer. If no
preloaded ads remain in the buffer, Google Mobile Ads SDK for React Native invokes the
[`onAdsExhausted`](https://developers.google.com/admob/react-native/reference/interface/PreloadCallback.md.txt#PreloadCallback.onAdsExhausted) callback.

### Preload cache limits

Google Mobile Ads SDK for React Native enforces an app-wide limit on the total number of preloaded ads:

- Default limit: Google holds a maximum of six preloaded ads in memory.
- We recommend keeping a buffer size of two for each preload ID.

If your app reaches the app-wide limit, background requests for preloaded
ads pause until existing ads are polled and displayed or destroyed.

## Poll and show the ad

To check for available preloaded ads and retrieve an ad instance, call the
[`AppOpenAdPreloader.pollAd`](https://developers.google.com/admob/react-native/reference/class/AppOpenAdPreloader#AppOpenAdPreloader.pollAd) method.

To listen for full-screen presentation events, register callbacks on the
[`adEventCallback`](https://developers.google.com/admob/react-native/reference/class/AppOpenAd.md.txt#AppOpenAd.adEventCallback) property of the returned
[`AppOpenAd`](https://developers.google.com/admob/react-native/reference/class/AppOpenAd.md.txt) instance before calling the
[`show`](https://developers.google.com/admob/react-native/reference/class/AppOpenAd.md.txt#AppOpenAd.show) method:

```tsx
export function showPreloadedAppOpenAd(
  preloadId: string,
  customAdEventCallback?: FullScreenAdEventCallback,
) {
  if (!AppOpenAdPreloader.isAdAvailable(preloadId)) {
    console.log('No preloaded app open ad available right now.');
    return;
  }

  const ad = AppOpenAdPreloader.pollAd(preloadId);
  if (!ad) {
    return;
  }

  ad.adEventCallback = {
    // Called when the ad is presented on screen.
    onAdShowedFullScreenContent: () => {
      console.log('Preloaded app open ad showed full screen content.');
      customAdEventCallback?.onAdShowedFullScreenContent?.();
    },
    // Called when the ad is closed by the user.
    onAdDismissedFullScreenContent: () => {
      console.log('Preloaded app open ad dismissed full screen content.');
      customAdEventCallback?.onAdDismissedFullScreenContent?.();
      ad.destroy();
    },
    // Called when presentation fails.
    onAdFailedToShowFullScreenContent: (error) => {
      console.error('Failed to show preloaded app open ad:', error);
      customAdEventCallback?.onAdFailedToShowFullScreenContent?.(error);
      ad.destroy();
    },
    // Called when an impression is recorded.
    onAdImpression: () => {
      console.log('Preloaded app open ad recorded an impression.');
      customAdEventCallback?.onAdImpression?.();
    },
    // Called when the user taps the ad.
    onAdClicked: () => {
      console.log('Preloaded app open ad was clicked.');
      customAdEventCallback?.onAdClicked?.();
    },
    // Called when the ad is estimated to have earned money.
    onAdPaid: (adValue) => {
      console.log(
        `Preloaded app open ad paid: ${adValue.amountMicros}` +
          ` ${adValue.currencyCode}`,
      );
      customAdEventCallback?.onAdPaid?.(adValue);
    },
  };

  ad.show();
}
```

To release memory and resources, call the `ad.destroy` method in the
[`onAdDismissedFullScreenContent`](https://developers.google.com/admob/react-native/reference/interface/FullScreenAdEventCallback#FullScreenAdEventCallback.onAdDismissedFullScreenContent)
and
[`onAdFailedToShowFullScreenContent`](https://developers.google.com/admob/react-native/reference/interface/FullScreenAdEventCallback#FullScreenAdEventCallback.onAdFailedToShowFullScreenContent)
callbacks when a user dismisses an ad or the ad fails to show.

## Read the response info

To inspect details of the next preloaded ad without removing the ad from the
cache, call the
[`AppOpenAdPreloader.peekAdResponseInfo`](https://developers.google.com/admob/react-native/reference/class/AppOpenAdPreloader#AppOpenAdPreloader.peekAdResponseInfo)
method:

```tsx
export function peekAppOpenAdResponseInfo(
  preloadId: string,
): ResponseInfo | null {
  const responseInfo = AppOpenAdPreloader.peekAdResponseInfo(preloadId);
  if (responseInfo) {
    console.log('Next preloaded app open ad response info:', responseInfo);
  }
  return responseInfo;
}
```

## Manage app open ads with an app-level manager

Because app open ads are presented globally during app launch and foreground
transitions, we recommend managing preloader lifecycle state in an app-level
manager outside the React component tree.

Using an app-level manager offers several key advantages:

- Keeps preloader state independent of individual screen navigation and component lifecycle.
- Centralizes ad event callbacks, state tracking, and cleanup in a single shared instance across your app.
- Controls when foreground events are listened to, preventing duplicate presentations upon ad dismissal.

The following example implements an app-level manager using
the [`AppOpenAdPreloader`](https://developers.google.com/admob/react-native/reference/class/AppOpenAdPreloader) object:

```tsx
export class AppOpenAdManager {
  private adUnitId: string;
  private preloadId: string;
  private appStateSubscription?: NativeEventSubscription;
  private startTimeoutId?: ReturnType<typeof setTimeout>;

  constructor(adUnitId: string, preloadId: string) {
    this.adUnitId = adUnitId;
    this.preloadId = preloadId;
  }

  start(): boolean {
    if (!AppOpenAdPreloader.getConfiguration(this.preloadId)) {
      AppOpenAdPreloader.start(
        this.preloadId,
        {
          request: {adUnitId: this.adUnitId},
          bufferSize: 2,
        },
        {
          onAdPreloaded: (event) => {
            console.log(`App open ad preloaded for ${event.preloadId}`);
          },
          onAdFailedToPreload: (error: LoadAdError) => {
            console.error('Failed to preload app open ad:', error.message);
          },
          onAdsExhausted: () => {
            console.log('App open ad buffer exhausted.');
          },
        },
      );
    }

    if (!this.appStateSubscription && !this.startTimeoutId) {
      // Delay attaching the listener to ensure native dismissal transitions complete
      this.startTimeoutId = setTimeout(() => {
        this.startTimeoutId = undefined;
        if (!this.appStateSubscription) {
          this.appStateSubscription = AppState.addEventListener(
            'change',
            (nextAppState: AppStateStatus) => {
              if (nextAppState === 'active') {
                this.showAdIfAvailable();
              }
            },
          );
        }
      }, APP_STATE_LISTENER_DELAY_MS);
    }

    return true;
  }

  pause(): void {
    if (this.startTimeoutId) {
      clearTimeout(this.startTimeoutId);
      this.startTimeoutId = undefined;
    }
    this.appStateSubscription?.remove();
    this.appStateSubscription = undefined;
  }

  stop(): void {
    this.pause();
    AppOpenAdPreloader.destroy(this.preloadId);
  }

  showAdIfAvailable() {
    if (!AppOpenAdPreloader.isAdAvailable(this.preloadId)) {
      console.log('App open ad is not preloaded or available right now.');
      return;
    }

    const ad = AppOpenAdPreloader.pollAd(this.preloadId);
    if (!ad) {
      return;
    }

    // Pause listener while presenting the ad
    this.pause();

    ad.adEventCallback = {
      onAdShowedFullScreenContent: () => {
        console.log('Preloaded app open ad showed full screen content.');
      },
      onAdDismissedFullScreenContent: () => {
        console.log('Preloaded app open ad dismissed full screen content.');
        ad.destroy();
        this.start();
      },
      onAdFailedToShowFullScreenContent: (error) => {
        console.error('Failed to show preloaded app open ad:', error);
        ad.destroy();
        this.start();
      },
    };

    ad.show();
  }
}
```

## Listen to app foregrounding events

To display ads when your app returns to the foreground, register a `change`
listener on the `AppState` module in your app's root component,
such as `App.tsx`. Check when the state transitions to `active`.
For example, call the `start` method on your ad manager instance in the
`App.tsx` component.

Presenting ad overlays or landing pages, such as showing full-screen ads or
tapping a banner ad, pushes your application to the background. When the user
returns to your application, your app receives a new `active` state event. To
prevent an unintended ad presentation or loop where returning from an ad
presents an app open ad from the cache, do the following:

1. Remove the `AppState` event listener before presenting a full-screen ad.
2. To make sure listening resumes whether a user dismisses the ad or the ad fails to show, add the `AppState` event listener again in the [`onAdDismissedFullScreenContent`](https://developers.google.com/admob/react-native/reference/interface/FullScreenAdEventCallback#FullScreenAdEventCallback.onAdDismissedFullScreenContent) and [`onAdFailedToShowFullScreenContent`](https://developers.google.com/admob/react-native/reference/interface/FullScreenAdEventCallback#FullScreenAdEventCallback.onAdFailedToShowFullScreenContent) callbacks.

For a complete example of controlling when foreground event listeners are paused
and resumed, see the [`AppOpenAdManager`](https://developers.google.com/admob/react-native/app-open.md.txt#app_open_ad_manager) implementation.

## Learn cold starts and loading screens

A cold start occurs when your app launches from scratch, for example, when a
user opens your app for the first time or after the device closes the app to
free memory. During a cold start, you lack a previously loaded app open ad to
show next.

Because of ad request delays, your users might interact with your app before an
ad appears. Show app open ads on cold starts only from a loading screen while
app assets load. If assets finish loading and the user reaches the main content
before the ad loads, don't show the ad.

## Clean up resources

When preloading is no longer required for a screen or ad unit ID, such as when
navigating away from a screen that preloads ads, call the
[`AppOpenAdPreloader.destroy`](https://developers.google.com/admob/react-native/reference/class/AppOpenAdPreloader#AppOpenAdPreloader.destroy) method to
release preloader resources and prevent holding unused ad objects in memory:

```tsx
export function destroyAppOpenAdPreloader(preloadId: string) {
  AppOpenAdPreloader.destroy(preloadId);
}
```

In addition to destroying the preloader queue, make sure to destroy individual
polled ad instances when a user dismisses an ad or the ad fails to show. For
details, see [Poll and show the ad](https://developers.google.com/admob/react-native/app-open.md.txt#poll_and_show).

## View the full example

The following example component starts preloading on mount, tracks available ad
counts, and provides controls to show preloaded app open ads:

```tsx
export function AppOpenScreen() {
  const [numAdsAvailable, setNumAdsAvailable] = useState<number>(0);
  const [status, setStatus] = useState<string>('Preloader idle.');

  const refreshAdCount = () => {
    const count = AppOpenAdPreloader.getNumAdsAvailable(PRELOAD_ID);
    setNumAdsAvailable(count);
  };

  useEffect(() => {
    // Start preloading ads on component mount
    const started = startAppOpenAdPreloader(APP_OPEN_AD_UNIT_ID, PRELOAD_ID, {
      onAdPreloaded: () => {
        refreshAdCount();
        setStatus('App open ad preloaded into buffer.');
      },
      onAdFailedToPreload: (error) => {
        setStatus(`Failed to preload app open ad: ${error.message}`);
      },
      onAdsExhausted: () => {
        refreshAdCount();
        setStatus('Preload buffer exhausted for app open ads.');
      },
    });
    if (started) {
      setStatus('Preloader started.');
    }

    // Clean up preloader resources on component unmount
    return () => {
      destroyAppOpenAdPreloader(PRELOAD_ID);
    };
  }, []);

  const handleShowAd = () => {
    setStatus('Showing preloaded ad...');
    showPreloadedAppOpenAd(PRELOAD_ID, {
      onAdDismissedFullScreenContent: () => {
        setStatus('Ad dismissed.');
      },
      onAdFailedToShowFullScreenContent: (error) => {
        setStatus(`Failed to show preloaded ad: ${error.message}`);
      },
    });
    refreshAdCount();
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Preload App Open Ads</Text>
      <Text style={styles.status}>Status: {status}</Text>
      <Text style={styles.status}>Ads Available: {numAdsAvailable}</Text>
      <View style={styles.buttonGroup}>
        <Button
          title="Show Preloaded Ad"
          onPress={handleShowAd}
          disabled={numAdsAvailable === 0}
        />
      </View>
    </View>
  );
}
```

Replace the following:

- <var class="readonly" translate="no">APP_OPEN_AD_UNIT_ID</var> with your ad unit ID.
- <var class="readonly" translate="no">PRELOAD_ID</var> with your preloader ID.

## Next steps

After you integrate app open ads, explore the following topics:

- [Impression-level ad revenue](https://developers.google.com/admob/react-native/impression-level-ad-revenue.md.txt)
- [User privacy and consent](https://developers.google.com/admob/react-native/privacy.md.txt)