DEV Community

Cover image for Adding Google AdMob to Expo Apps
Josie Daw
Josie Daw

Posted on • Edited on

Adding Google AdMob to Expo Apps

Table of Contents

1. Getting Started
2. Using Expo Development Builds
3. Preparing AdMob
4. Using React Native Google Mobile Ads
5. Creating a Banner Ad
6. Creating an Interstitial Ad
7. Configure Ads for Production
8. 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.
  2. Create a Google AdMob 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 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",
  },



Enter fullscreen mode Exit fullscreen mode

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

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",
  }
}


Enter fullscreen mode Exit fullscreen mode

You will also need to register your test devices if you are not using emulators. You can follow this guide 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"
          }
        }
      ]
    ]


Enter fullscreen mode Exit fullscreen mode

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();
    })();
}, [])


Enter fullscreen mode Exit fullscreen mode

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

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;



Enter fullscreen mode Exit fullscreen mode

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

Here's how it looks!

Google AdMob test banner ad


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;



Enter fullscreen mode Exit fullscreen mode

Now you will have functioning interstitial ads on your app!

Here's how it will look:

Google AdMob test interstitial ad

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"
    ]
  }
}



Enter fullscreen mode Exit fullscreen mode

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"
  }


Enter fullscreen mode Exit fullscreen mode

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.** { *; }',
          },
        },
      ],
    ],
 }


Enter fullscreen mode Exit fullscreen mode

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.

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!

Top comments (19)

Collapse
 
shanejones profile image
Shane • Edited

Hey Josie!

Thanks for this, I rarely comment on posts but wanted to let you know after following FAR TOO MANY guides around getting Ads in my Expo app your straightforward guide was the only one that made sense and now works for me.

Collapse
 
josie profile image
Josie Daw

Thanks Shane! I too experienced going through all those guides and decided to make a more definitive one 😅

Collapse
 
leandro_cunha profile image
Leandro Cunha

Hey @josie thank you for the article, helped a lot. Just an update about the app.json config, the app_ids should be placed inside the plugins sections, like:



// <project-root>/app.json
{
  "expo": {
    "plugins": [
      [
        "react-native-google-mobile-ads",
        {
          "androidAppId": "ca-app-pub-xxxxxxxx~xxxxxxxx",
          "iosAppId": "ca-app-pub-xxxxxxxx~xxxxxxxx"
        }
      ]
    ]
  }
}



Enter fullscreen mode Exit fullscreen mode
Collapse
 
ppillo profile image
José Carlos López

It's the kind of tutorial that you want to start playing!

Collapse
 
enegraso profile image
Federico Ortiz

Thanks to this tutorial I was able to add the ads although in test form, for now. I have 2 queries:

How to obtain the googleadsmobile.json for my next apps, since in the app I am testing I use an old file obtained from a previous app made with Android Studio (I hope not to use it again), I don't know if it will work in production.
The other question is whether with the command: eas build -p android (or ios), the release for the desired store will be generated correctly.

Thank you so much.

Collapse
 
josie profile image
Josie Daw

Hello Federico,
For the first question, I am not sure about googleadsmobile.json because it is not included in the guide above. You may be following a slightly different or older integration strategy.
For the second question, the eas build command will build the app properly but you will need to submit it to the App Store and Play Console after the build is finished.

Collapse
 
enegraso profile image
Federico Ortiz

Hello, I tell you that I generated the file from firebase.io for the app by entering the package name as it appears in app.json and it was a 10!
And indeed the compilation also looks very good.
Now the issue is that since it is an app from a news agency, Google Play has not yet published it to me, since it requests several modifications to ensure that the app adheres to its policies.
Thank you so much

Collapse
 
mihyo profile image
minyo

I'm going crazy. Please help me.
I'm proceeding with the post you wrote, but I keep getting the following errors.
Is admob unavailable on expo...

should NOT have additional property 'react-native-google-mobile-ads'

Collapse
 
josie profile image
Josie Daw

When you use Admob with Expo, you cannot use the normal Expo development process. You have to use Expo development builds as outlined in this step.

Collapse
 
mihyo profile image
minyo

Thank you so much.
You must have been really stupid.
It was a simple one, but I didn't see it.

Collapse
 
tosey profile image
Tosin Seyi

Will the react-native-google-mobile-ads work on production with the expo framework?

Collapse
 
josie profile image
Josie Daw

Yes, you can see how to make it work on production here: dev.to/josie/adding-google-admob-t...

Collapse
 
tosey profile image
Tosin Seyi • Edited

Yes. Thank you. So i have followed your instructions accordingly on how to make it work on production but when i build my project, i'm getting the following error:

A problem occurred evaluating project ':react-native-google-mobile-ads'.

Cannot get property 'googleMobileAdsJson' on extra properties extension as it does not exist

Kindly help if you have faced and solved this kind of error before.

Thread Thread
 
josie profile image
Josie Daw

It looks like you have added googleMobileAdsJson somewhere? That is not something included in the guide above. If you can find that by searching your project, that should help you to debug the problem.

Thread Thread
 
tosey profile image
Tosin Seyi

I didn't add it. It came with the react-native-google-mobile-ads package after the installation. Because it gave me reference to the error in the 'build.gradle' file of the package and i found it there.

But now, i honestly don't know what to do to make the 'googleMobileAdsJson' error disappear so that i can have a successful build to production. I have tried a few things but none of them worked so far.

Collapse
 
antonio_oliveira_6343ec0c profile image
Antonio Oliveira • Edited

I have a app that was only on pure native java, recently I change everything and did a version using expo/react native and implemented ads with this tutorial.
Apparently everything is working fine, but my ads performance is 80% lower and becoming worst each new day. What could be? 🥲🥲
Please, help.

Collapse
 
antonio_oliveira_6343ec0c profile image
Antonio Oliveira

)=
Image description

Collapse
 
david_khayutin_4c149c365c profile image
David Khayutin

Thanks for the article Josie

One question - will real ads show in staging environment or is it right that they will only show in production when app is on app store / google play store

Collapse
 
josie profile image
Josie Daw

When you are in the staging environment, it should show test ads as long as you have correctly registered your devices on AdMob. If you are seeing real ads in staging, make sure that the devices are registered properly on AdMob.