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.
- Create your Expo project.
- 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",
},
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
.
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 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:
- Click Privacy & Messaging
- Create messaging for European Regulations, US State Regulations, and any other options.
- 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.
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!
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:
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.
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)
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.
Thanks Shane! I too experienced going through all those guides and decided to make a more definitive one 😅
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:It's the kind of tutorial that you want to start playing!
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.
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.
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
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'
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.
Thank you so much.
You must have been really stupid.
It was a simple one, but I didn't see it.
Will the react-native-google-mobile-ads work on production with the expo framework?
Yes, you can see how to make it work on production here: dev.to/josie/adding-google-admob-t...
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'.
Kindly help if you have faced and solved this kind of error before.
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.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.
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.
)=
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
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.