Adding Google AdMob to Expo Apps
Tags: expo, admob, monetization, reactnative
Published: 2024-01-21 10:48:37


## Table of Contents
[1. Getting Started](#getting-started)
[2. Using Expo Development Builds](#using-expo-development-builds)
[3. Preparing AdMob](#preparing-admob)
[4. Using React Native Google Mobile Ads ](#using-react-native-google-mobile-ads)
[5. Creating a Banner Ad](#creating-a-banner-ad)
[6. Creating an Interstitial Ad](#creating-an-interstitial-ad)
[7. Configure Ads for Production](#configure-ads-for-production)
[8. Common Problems with Google Admob for Expo/React Native](#common-problems-with-google-admob-for-expo-react-native)

---



### Getting Started

This post is a brief guide on adding banner ads and interstitial ads to a simple Expo project using Google AdMob and React Native Google Mobile Ads. 

1. Create your [Expo project](https://docs.expo.dev/tutorial/create-your-first-app/).
2. Create a [Google AdMob](https://apps.admob.com/v2/home) account and make sure to complete the verification process. 


---


### Using Expo Development Builds

Since we will later install React Native Google Mobile Ads, we will not be able to use the Expo Go app to test. As a result, we will need to use the Expo development builds to test our app. 

You can follow [this tutorial](https://docs.expo.dev/develop/development-builds/create-a-build/) from Expo to setup a development build.

Add the following lines to your `package.json` (after following the tutorial steps) so that you can easily build development models from your command line.

```
  "scripts": {
     ...
     "dev:build:ios": "eas build --profile development --platform ios",
     "dev:build:android": "eas build --profile development --platform android",
  },

```

---

### Preparing AdMob

Since React Native is a cross-platform framework, you will need to create an app for both iOS and Android. You will need to have apps already published on the App and Play stores to register them with AdMob. If you are following this guide before registering your app on any stores, make sure to just use the test IDs. 

After creating the apps in Google AdMob, select the app and then select 'App Settings'. Get the App ID for both Android and iOS. The format of the App ID is always `ca-app-pub-12345678910~123456459`. 


![Google AdMob app view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvec8ju403f8nwghebdc.png)

In your `app.json`/`app.config.js`, outside of "expo", add a new object with the following structure:

```
{
  "expo": ...
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-12345678910~123456459",
    "ios_app_id": "ca-app-pub-12345678910~123456459",
  }
}
```

You will also need to register your test devices if you are not using emulators. You can follow [this guide](https://support.google.com/admob/answer/9691433#add) to register your devices with AdMob.

#### Don't Forget to Follow Advertising Regulations

Many countries around the world now have explicit consent requirements to display any ads at all. Luckily, Google AdMob and React Native Google Mobile Ads make this easy to do. From the Google AdMob dashboard:

1. Click Privacy & Messaging
2. Create messaging for European Regulations, US State Regulations, and any other options. 
3. Click "Publish" for each message.

---


### Using React Native Google Mobile Ads

Start by installing React Native Google Mobile Ads with `npm install react-native-google-mobile-ads`

If you need to use static frameworks, you should follow an additional step and add this to your plugins in `app.json`/`app.config.js`:

```
 "plugins": [
      [
        "expo-build-properties",
        {
          "ios": {
            "useFrameworks": "static"
          }
        }
      ]
    ]
```

Next, we need to initialize the ads when the app first loads, so on your `App.js` or your root `_layout.jsx`/`_layout.tsx`, add the following code:

```
import mobileAds from 'react-native-google-mobile-ads';

// Go inside your component/function

// Initialize Google Mobile Ads SDK
useEffect(() => {
    (async () => {
      // Google AdMob will show any messages here that you just set up on the AdMob Privacy & Messaging page
      const { status: trackingStatus } = await requestTrackingPermissionsAsync();
      if (trackingStatus !== 'granted') {
        // Do something here such as turn off Sentry tracking, store in context/redux to allow for personalized ads, etc.
      }

      // Initialize the ads
      await mobileAds().initialize();
    })();
}, [])
```

We are now ready to create our first ad! 

---


### Creating a Banner Ad

Banner ads are one of the easiest ways to insert ads into your app without severely interrupting the user experience. You can easily insert them at natural breakpoints in your Views/components.

To insert a banner ad into your app, you must first create one on Google AdMob. For both iOS and Android, go to each App -> Ad Units -> Add Ad Unit -> Select Banner Ad.

You can give the ad any name and adjust the advanced settings to your preferences.


![Google AdMob ad view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ny4rev2dlkdfq1gu1noq.png)

You will be using the Ad ID for the next stage. The Ad ID is *different* from the App ID. The Ad ID always has a structure of `ca-app-pub-12345678910/12345678910`. An easy way to tell the difference is that the App ID has a ~ and the Ad ID has a /. 


First, install Expo device to be able to display the correct banners: `npx expo install expo-device`.

Next, let's create a special component to hold our banner ad so that we can easily reuse it anywhere in our app. 

Create a new file called `InlineAd.tsx` (or `InlineAd.jsx`) and use something like the below code.

By using `isAdLoaded` and the View style, we can minimize the amount of blank space showing on the app when an ad has not loaded.

*Remember, you should put your Ad IDs in environmental variables. The fake IDs below are for display purposes only.*


```
// InlineAd.tsx

import { View } from 'react-native';
import * as Device from 'expo-device';
import React, { useState } from 'react';
import { BannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads';

const iosAdmobBanner = "ca-app-pub-12345678910/12345678910";
const androidAdmobBanner = "ca-app-pub-12345678910/12345678910";
const productionID = Device.osName === 'Android' ? androidAdmobBanner : iosAdmobBanner;

const InlineAd = () => {
  const [isAdLoaded, setIsAdLoaded] = useState<boolean>(false);
  return (
    <View style={{ height: isAdLoaded ? 'auto' : 0 }}>
      <BannerAd
        // It is extremely important to use test IDs as you can be banned/restricted by Google AdMob for inappropriately using real ad banners during testing
        unitId={__DEV__ ? TestIds.BANNER : productionID}
        size={BannerAdSize.ANCHORED_ADAPTIVE_BANNER}
        requestOptions={{
          requestNonPersonalizedAdsOnly: true, 
          // You can change this setting depending on whether you want to use the permissions tracking we set up in the initializing
        }}
        onAdLoaded={() => {
          setIsAdLoaded(true);
        }}
      />
    </View >
  );
};

export default InlineAd;

```

Now you can insert `InlineAd` anywhere in your app `<InlineAd />`.

Here's how it looks!

![Google AdMob test banner ad](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o77jtfiy15q7mfv35nhp.png)

---



### Creating an Interstitial Ad

Interstitial ads are adverts that take up the entire screen and should be used sparingly as they can dissuade users from using your app if they are overused. 

As with the banner ads above, you need to create an interstitial ad for each app and then get the Ad ID in the following format `ca-app-pub-12345678910/12345678910`.

One of the best way to use interstitial ads is with pagination (i.e.) moving from one page to another. 

Below, I will update an existing pagination function to show interstitial ads whenever the user moves to the next page or the previous page.

First, create your `Pagination.tsx` or `Pagination.jsx` file. Then, prepare your interstitial Ad IDs. Next, prepare an ad request with keywords or personalized ads.

Then, inside the component itself, use useEffect to load/unload the actual interstitial ad.

The code below prepares the interstitial ad and only shows it (using `interstitial.show();`)  if an ad is loaded and the button is clicked. Sometimes there are no ads available, or the user is offline, so we don't want to cause an accidental error. 

We also use the `unsubscribeClosed` to set the `loaded` state to false after the interstitial ad has been closed and reload a new ad. This means that no matter how many times a user clicks Previous or Next, there will always be a new ad for them. 

*Remember, you should put your Ad IDs in environmental variables. The fake IDs below are for display purposes only.*

```
// Pagination.tsx

import { AntDesign } from '@expo/vector-icons';
import * as Device from 'expo-device';
import { Link } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { View, Button, Text } from 'react-native';
import { AdEventType, InterstitialAd, TestIds } from 'react-native-google-mobile-ads';

const iosAdmobInterstitial = "ca-app-pub-12345678910/12345678910";
const androidAdmobInterstitial = "ca-app-pub-12345678910/12345678910";
const productionID = Device.osName === 'Android' ? androidAdmobInterstitial : iosAdmobInterstitial;
const adUnitId = __DEV__ ? TestIds.INTERSTITIAL : productionID;
// Make sure to always use a test ID when not in production 


const interstitial = InterstitialAd.createForAdRequest(adUnitId, {
  keywords: ['food', 'cooking', 'fruit'], // Update based on the most relevant keywords for your app/users, these are just random examples
  requestNonPersonalizedAdsOnly: true, // Update based on the initial tracking settings from initialization earlier
});


const Pagination = ({ }) => {

  const [loaded, setLoaded] = useState<boolean>(false);

  useEffect(() => {
    // Event listener for when the ad is loaded
    const unsubscribeLoaded = interstitial.addAdEventListener(AdEventType.LOADED, () => {
      setLoaded(true);
    });

    // Event listener for when the ad is closed
    const unsubscribeClosed = interstitial.addAdEventListener(AdEventType.CLOSED, () => {
      setLoaded(false);

      // Load a new ad when the current ad is closed
      interstitial.load();
    });

    // Start loading the interstitial ad straight away
    interstitial.load();

    // Unsubscribe from events on unmount
    return () => {
      unsubscribeLoaded();
      unsubscribeClosed();
    };
  }, []);


  return (
    <View
      style={{
        width: '100%',
        flexDirection: 'row',
        justifyContent: 'space-evenly',
        alignItems: 'center',
        marginVertical: 8,
        paddingHorizontal: 10,
      }}>
      
        <Link asChild href="/previous-page">
          <Button onPress={() => {
            if (loaded) { interstitial.show(); }
          }}>
            <>
              <AntDesign name="arrowleft" size={24} color="#fdb833" />
              <Text>
                Previous
              </Text>
            </>
          </Button>
        </Link>
      

      
        <Link asChild href="/next-page">
          <Button onPress={() => {
            if (loaded) { interstitial.show(); }
          }}>
            <>
              <Text>
                Next
              </Text>
              <AntDesign name="arrowright" size={24} color="#fdb833" />
            </>
          </Button>
        </Link>
      
    </View>
  );
};

export default Pagination;

```

Now you will have functioning interstitial ads on your app!

Here's how it will look:


![Google AdMob test interstitial ad](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qprdjb0ekvc6cej1ui7e.png)

After following the steps above, you should be able to see test ads in your app. However, if you want to show ads on a production level app, you need to take some additional steps.

---



### Configure Ads for Production

In your `app.json`/`app.config.js` add the below to the `react-native-google-mobile-ads` section. 

`user_tracking_usage_description` will display to users to provide informed consent.
`sk_ad_network_items` includes all of the SKAdNetwork names to make sure that all of the ad impressions and conversions are tracked for your app.
 

```
{
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-12345678910~123456459",
    "ios_app_id": "ca-app-pub-12345678910~123456459",
    "delay_app_measurement_init": true,
    "user_tracking_usage_description": "This identifier will be used to deliver personalized ads to you.",
    "sk_ad_network_items": [
      "cstr6suwn9.skadnetwork",
      "4fzdc2evr5.skadnetwork",
      "4pfyvq9l8r.skadnetwork",
      "2fnua5tdw4.skadnetwork",
      "ydx93a7ass.skadnetwork",
      "5a6flpkh64.skadnetwork",
      "p78axxw29g.skadnetwork",
      "v72qych5uu.skadnetwork",
      "ludvb6z3bs.skadnetwork",
      "cp8zw746q7.skadnetwork",
      "c6k4g5qg8m.skadnetwork",
      "s39g8k73mm.skadnetwork",
      "3qy4746246.skadnetwork",
      "3sh42y64q3.skadnetwork",
      "f38h382jlk.skadnetwork",
      "hs6bdukanm.skadnetwork",
      "v4nxqhlyqp.skadnetwork",
      "wzmmz9fp6w.skadnetwork",
      "yclnxrl5pm.skadnetwork",
      "t38b2kh725.skadnetwork",
      "7ug5zh24hu.skadnetwork",
      "9rd848q2bz.skadnetwork",
      "y5ghdn5j9k.skadnetwork",
      "n6fk4nfna4.skadnetwork",
      "v9wttpbfk9.skadnetwork",
      "n38lu8286q.skadnetwork",
      "47vhws6wlr.skadnetwork",
      "kbd757ywx3.skadnetwork",
      "9t245vhmpl.skadnetwork",
      "a2p9lx4jpn.skadnetwork",
      "22mmun2rn5.skadnetwork",
      "4468km3ulz.skadnetwork",
      "2u9pt9hc89.skadnetwork",
      "8s468mfl3y.skadnetwork",
      "av6w8kgt66.skadnetwork",
      "klf5c3l5u5.skadnetwork",
      "ppxm28t8ap.skadnetwork",
      "424m5254lk.skadnetwork",
      "ecpz2srf59.skadnetwork",
      "uw77j35x4d.skadnetwork",
      "mlmmfzh3r3.skadnetwork",
      "578prtvx9j.skadnetwork",
      "4dzt52r2t5.skadnetwork",
      "gta9lk7p23.skadnetwork",
      "e5fvkxwrpn.skadnetwork",
      "8c4e2ghe7u.skadnetwork",
      "zq492l623r.skadnetwork",
      "3rd42ekr43.skadnetwork",
      "3qcr597p9d.skadnetwork",
      "vutu7akeur.skadnetwork",
      "eh6m2bh4zr.skadnetwork",
      "pwa73g5rt2.skadnetwork"
    ]
  }
}

```

In the "expo" section of your `app.json`/`app.config.js`, you also need to add the following to your "android" and "ios" sections.

```
"android": {
    "versionCode": 1,
    "adaptiveIcon": {
      "foregroundImage": "./assets/adaptive-icon.png",
      "backgroundColor": "#FFFFF"
    },
    "package": "com.fakeapp.name",
    "permissions": ["com.google.android.gms.permission.AD_ID"],
    "googleServicesFile": "./google-services.json"
},
  "ios": {
    "buildNumber": "1",
    "supportsTablet": true,
    "infoPlist": {
      "NSUserTrackingUsageDescription": "Allow this app to collect app-related data that can be used for tracking you or your device and deliver personalized ads to you.",
      "SKAdNetworkItems": [
        {
          "SKAdNetworkIdentifier": [
            "cstr6suwn9.skadnetwork",
            "4fzdc2evr5.skadnetwork",
            "4pfyvq9l8r.skadnetwork",
            "2fnua5tdw4.skadnetwork",
            "ydx93a7ass.skadnetwork",
            "5a6flpkh64.skadnetwork",
            "p78axxw29g.skadnetwork",
            "v72qych5uu.skadnetwork",
            "ludvb6z3bs.skadnetwork",
            "cp8zw746q7.skadnetwork",
            "c6k4g5qg8m.skadnetwork",
            "s39g8k73mm.skadnetwork",
            "3qy4746246.skadnetwork",
            "3sh42y64q3.skadnetwork",
            "f38h382jlk.skadnetwork",
            "hs6bdukanm.skadnetwork",
            "v4nxqhlyqp.skadnetwork",
            "wzmmz9fp6w.skadnetwork",
            "yclnxrl5pm.skadnetwork",
            "t38b2kh725.skadnetwork",
            "7ug5zh24hu.skadnetwork",
            "9rd848q2bz.skadnetwork",
            "y5ghdn5j9k.skadnetwork",
            "n6fk4nfna4.skadnetwork",
            "v9wttpbfk9.skadnetwork",
            "n38lu8286q.skadnetwork",
            "47vhws6wlr.skadnetwork",
            "kbd757ywx3.skadnetwork",
            "9t245vhmpl.skadnetwork",
            "a2p9lx4jpn.skadnetwork",
            "22mmun2rn5.skadnetwork",
            "4468km3ulz.skadnetwork",
            "2u9pt9hc89.skadnetwork",
            "8s468mfl3y.skadnetwork",
            "av6w8kgt66.skadnetwork",
            "klf5c3l5u5.skadnetwork",
            "ppxm28t8ap.skadnetwork",
            "424m5254lk.skadnetwork",
            "ecpz2srf59.skadnetwork",
            "uw77j35x4d.skadnetwork",
            "mlmmfzh3r3.skadnetwork",
            "578prtvx9j.skadnetwork",
            "4dzt52r2t5.skadnetwork",
            "gta9lk7p23.skadnetwork",
            "e5fvkxwrpn.skadnetwork",
            "8c4e2ghe7u.skadnetwork",
            "zq492l623r.skadnetwork",
            "3rd42ekr43.skadnetwork",
            "3qcr597p9d.skadnetwork",
            "vutu7akeur.skadnetwork",
            "eh6m2bh4zr.skadnetwork",
            "pwa73g5rt2.skadnetwork"
          ]
        }
      ]
    },
    "bundleIdentifier": "com.fakeapp"
  }
```

You also need to all the following plugins for transparency:

```
"expo": {
  ...
  plugins: [
      [
        'expo-tracking-transparency',
        {
          userTrackingPermission:
            'Allow this app to collect app-related data that can be used for tracking you or your device and deliver personalized ads to you.',
        },
      ],
      [
        'expo-build-properties',
        {
          ios: {
            useFrameworks: 'static',
          },
          android: {
            extraProguardRules: '-keep class com.google.android.gms.internal.consent_sdk.** { *; }',
          },
        },
      ],
    ],
 }
```

---


### Common Problems with Google AdMob for Expo/React Native

#### 1. My ads are showing during testing but not in production

Usually this means that your App IDs or your Ad IDs are configured incorrectly. Make sure that you have added the correct ones. 

Note: if you are using environmental variables with Expo `eas build`, you need to include the variables in the `eas.json` and also submit the secrets on the Expo website.

##### 2. My ads are showing perfectly but I am not getting any impressions on the AdMob dashboard

Sometimes it take can take a few days for new apps to start registering ads correctly on the dashboard. Make sure that all of your configurations and verifications on the AdMob dashboard are completed properly.

#### 3. My ads are only showing impressions for one of my apps on the AdMob dashboard

This problem is usually caused by accidentally using the same Ad ID for both iOS and Android. Double check that each device type is using its own Ad ID. (i.e. `Device.osName === 'Android' ? androidAdmobInterstitialId : iosAdmobInterstitialId;` )

---

Thanks for following along with this tutorial for adding Google AdMob to Expo devices! If you're interested in learning more about me, you can visit my portfolio [here](https://josiedaw.com).

If you are facing an error anywhere along the way that is not one of the common problems I've already answered, feel free to leave a comment below and we can try to debug it together!