# React Native

Source: https://docs.ezoic.com/docs/mobileapps/react-native/


The Ezoic React Native SDK lets you display banner, native, outstream video, instream video, rewarded, and interstitial ads in React Native apps with Prebid header bidding, Google Ad Manager, remote configuration, consent handling, and pageview tracking, all from a single JavaScript API.

The package is a thin bridge over Ezoic's native Android and iOS ad stacks, so ad loading and auctions run natively while you write only React Native code. This guide is self-contained: it covers everything you need to ship on both platforms.

## Requirements

- React Native 0.72 or higher
- Node.js 18 or higher
- For Android apps: Android SDK 24 or higher, Android Gradle Plugin 8.0 or higher
- For iOS apps: iOS 14.0 or higher, Xcode 15.0 or higher, CocoaPods 1.12 or higher
- A Google Mobile Ads application ID provided by Ezoic
- A domain configured for your site in Ezoic

Authentication is handled by the app's bundle/package identifier plus the configured domain. There is no client-side API key.

## Installation

Install the package version provided by Ezoic:

```sh
npm install @ezoic/react-native-sdk
```

The package ships the native Android and iOS Ezoic SDKs as transitive dependencies and registers them through React Native autolinking, so you do not add the native ad SDKs yourself.

### iOS pods

For apps that support iOS, install pods after adding the package:

```sh
cd ios
pod install
```

This resolves the native `EzoicAdsSDK` framework along with its Prebid Mobile and Google Mobile Ads dependencies. If your project uses frameworks, make sure `use_frameworks!` in your `Podfile` is compatible with Google Mobile Ads (static linkage is recommended).

## Android Setup

The package's Gradle module declares the Ezoic Android SDK dependency automatically. Your app project must be able to resolve it, which standard React Native apps already do because they include Google's Maven repository and Maven Central.

If your `android/build.gradle` or `android/settings.gradle` customizes repositories, confirm both are present:

```groovy
repositories {
    google()
    mavenCentral()
}
```

### Google Mobile Ads application ID

Add your Google Mobile Ads application ID to `android/app/src/main/AndroidManifest.xml`. This ID is provided by Ezoic and can be found in your Ezoic dashboard. Use the value assigned to your app unless your Ezoic representative gives you a different one.

```xml
<manifest>
    <application>
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX" />
    </application>
</manifest>
```

### Advertising ID permission

If your app targets Android 12 (API 31) or higher and uses the advertising ID, add the permission to `AndroidManifest.xml`:

```xml
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
```

## iOS Setup

### Google Mobile Ads application ID

Add your Google Mobile Ads application ID to `ios/<YourApp>/Info.plist`. This ID is provided by Ezoic and can be found in your Ezoic dashboard. Use the value assigned to your app unless your Ezoic representative gives you a different one.

```xml
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX</string>
```


Also set `GADIsAdManagerApp` to `true` in `Info.plist` so Google Mobile Ads runs in Ad Manager mode.


### App Tracking Transparency

ATT has the single biggest impact on fill and CPM. Without it the IDFA is unavailable and much of programmatic demand will not bid or bids far lower.

Add the tracking usage description to `ios/<YourApp>/Info.plist`. Apple requires this string in the app's `Info.plist` (it appears in the App Store privacy label and system prompt) — it cannot come from the SDK.

```xml
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>
```

**The SDK presents the ATT prompt for you on iOS.** When you call `EzoicAds.initialize`, the native iOS SDK shows the prompt (if undetermined) and waits for the decision before starting the ad stack, so the IDFA (if granted) is attached to the first ad request. You only need to add the `NSUserTrackingUsageDescription` string above.

```tsx
import { EzoicAds } from '@ezoic/react-native-sdk';

// The SDK requests ATT (if undetermined) before loading ads on iOS.
await EzoicAds.initialize({ domain: 'example.com' });
```

To drive ATT yourself instead (for a pre-prompt or custom timing), pass `requestATTBeforeAds: false` and request authorization before initializing — for example with `react-native-tracking-transparency`:

```tsx
import { requestTrackingPermission } from 'react-native-tracking-transparency';
import { EzoicAds } from '@ezoic/react-native-sdk';

await requestTrackingPermission();
await EzoicAds.initialize({ domain: 'example.com', requestATTBeforeAds: false });
```

### SKAdNetwork

`SKAdNetworkItems` lets buyers attribute installs when the IDFA is unavailable; missing identifiers suppress demand. Apple reads this key only from the app's main `Info.plist` — it is **not** aggregated from frameworks or SDKs.

Add the `SKAdNetworkItems` array with Google's published identifiers (`cstr6suwn9.skadnetwork` plus participating third-party buyers). Copy the current, complete list from Google's [Prepare privacy strategies](https://developers.google.com/ad-manager/mobile-ads-sdk/ios/privacy/strategies#enable-skadnetwork-to-track-conversions) page; identifiers must be lowercase.

```xml
<key>SKAdNetworkItems</key>
<array>
    <dict>
        <key>SKAdNetworkIdentifier</key>
        <string>cstr6suwn9.skadnetwork</string>
    </dict>
    <!-- … plus the remaining identifiers from Google's list … -->
</array>
```

## app-ads.txt

For both platforms, host an `app-ads.txt` file at the root of the developer website listed on your app's store page (for example, `https://example.com/app-ads.txt`). It authorizes the buyers that may sell your inventory; a missing or incomplete file causes most programmatic demand to be filtered out. Ezoic provides the required entries — confirm the file is published and current.

## Initialize the SDK

Initialize Ezoic once, early in your app lifecycle, before rendering any ads.

```tsx
import { EzoicAds } from '@ezoic/react-native-sdk';
import { useEffect } from 'react';

export function App() {
    useEffect(() => {
        EzoicAds.initialize({
            domain: 'example.com',
            debugEnabled: false,
            testMode: false
        });
    }, []);

    return null;
}
```

`domain` must match the domain configured for your site in Ezoic. Set `debugEnabled: true` during development to surface verbose native logs in Logcat (Android) and the Xcode console (iOS). Use `testMode: true` only while integrating; remove it for production traffic.

`initialize` resolves once the native SDK has finished bootstrapping. You can await it before rendering ads:

```tsx
await EzoicAds.initialize({ domain: 'example.com' });
```

## Add a Banner Ad

Render `EzoicBannerView` where the banner should appear. Give it explicit dimensions through `style` so the platform view is laid out correctly.

```tsx
import { EzoicBannerView } from '@ezoic/react-native-sdk';
import { SafeAreaView } from 'react-native';

export function ArticleScreen() {
    return (
        <SafeAreaView>
            <EzoicBannerView
                adUnitIdentifier="12345"
                size="300x250"
                style={{ width: 300, height: 250 }}
                onLoad={() => console.log('Ezoic banner loaded')}
                onError={(error) => console.warn('Ezoic banner failed', error)}
            />
        </SafeAreaView>
    );
}
```

Replace `12345` with your Ezoic ad unit identifier. The native SDKs fetch the Google Ad Manager ad unit, Prebid configuration, targeting values, supported sizes, and refresh interval from Ezoic servers, so you do not configure those in the app.


The native Ezoic ad unit identifier is numeric. Pass it as a string in React Native, for example `"12345"`.


## Banner Sizes

Pass `size` as a `widthxheight` string. Common sizes are:

- `"320x50"`: Banner
- `"320x100"`: Large Banner
- `"300x250"`: Medium Rectangle
- `"468x60"`: Full Banner
- `"728x90"`: Leaderboard

You can also pass a comma-separated list to let the auction choose among several sizes, for example `size="300x250,320x50"`. Always size the `style` so the view can hold the largest size you request.

## Banner Events

`EzoicBannerView` supports these event props:

- `onLoad`: the banner received an ad
- `onError`: the banner failed to load; receives an error object
- `onImpression`: an impression was recorded
- `onClick`: the user tapped the ad
- `onOpen`: the ad opened a full-screen overlay
- `onClose`: the full-screen overlay was dismissed

## Add a Native Ad

Native ads deliver ad assets (headline, icon, media, body text, and call to action) rendered in a template designed to match the look and feel of your app content, rather than in a fixed banner or full-screen format. Like `EzoicBannerView`, `EzoicNativeAdView` is a React component: render it where the ad should appear, sized through `style`.

```tsx
import { EzoicNativeAdView } from '@ezoic/react-native-sdk';

export function ArticleScreen() {
    return (
        <EzoicNativeAdView
            adUnitIdentifier="12345"
            style={{ width: '100%', height: 320 }}
            onLoad={() => console.log('Ezoic native ad loaded')}
            onError={(error) => console.warn('Ezoic native ad failed', error)}
            onImpression={() => console.log('Ezoic native ad impression')}
            onClick={() => console.log('Ezoic native ad clicked')}
            onOpen={() => console.log('Ezoic native ad opened an overlay')}
            onClose={() => console.log('Ezoic native ad overlay closed')}
        />
    );
}
```

Replace `12345` with your Ezoic ad unit identifier. The native SDKs render the ad in a Google-built native ad template (`NativeAdView`) that lays out the headline, icon, media, body, and call-to-action for you; unlike `EzoicBannerView`, `EzoicNativeAdView` has no `size` prop, so the template lays out its assets inside the bounds you give it through `style`.

`EzoicNativeAdView` supports these event props:

- `onLoad`: the native ad received an ad
- `onError`: the native ad failed to load; receives an error object
- `onImpression`: an impression was recorded
- `onClick`: the user tapped the ad
- `onOpen`: the ad opened a full-screen overlay
- `onClose`: the full-screen overlay was dismissed


Unlike `EzoicBannerView`, `EzoicNativeAdView` accepts the Ezoic ad unit identifier as either a string or a number, for example `"12345"` or `12345`.


## Add a Rewarded Ad

Rewarded ads are full-screen ads that grant an in-app reward when the user finishes watching. Unlike banners, they are not React components: load one imperatively ahead of time (for example, at the start of a level), then present it at a natural break. `show()` resolves with the earned reward, or `null` if the user dismissed the ad early.

```tsx
import { EzoicRewardedAd } from '@ezoic/react-native-sdk';

async function runRewardedAd() {
    try {
        const ad = await EzoicRewardedAd.load('12345');

        // Optional: observe lifecycle events
        ad.setListeners({
            onDismissed: () => console.log('Rewarded ad closed'),
            onFailedToShow: (error) => console.warn('Show failed', error.message),
        });

        const reward = await ad.show();
        if (reward) {
            console.log(`Earned ${reward.amount} ${reward.type}`);
            grantReward(reward.amount);
        }

        // Rewarded ads are single-use — release the handle when done.
        ad.destroy();
    } catch (error) {
        console.warn('Rewarded ad failed to load', error);
    }
}
```

Replace `12345` with your Ezoic ad unit identifier (passed as a string). Load and `show` are separate steps; calling `show()` before the ad has loaded rejects with an error. Load a new `EzoicRewardedAd` for each reward opportunity.

The reward `type` and `amount` come from the reward configured on the Google Ad Manager rewarded ad unit. `setListeners` accepts `onShown`, `onFailedToShow`, `onImpression`, `onClicked`, `onUserEarnedReward`, and `onDismissed` — all optional.

## Add an Interstitial Ad

Interstitial ads are full-screen ads shown at natural transition points (for example, between levels or screens). Unlike rewarded ads, they grant no reward. Like rewarded ads, they are not React components: load one imperatively ahead of time, then present it at a natural break. `show()` resolves when the ad is dismissed, or rejects if it fails to present.

```tsx
import { EzoicInterstitialAd } from '@ezoic/react-native-sdk';

async function runInterstitialAd() {
    try {
        const ad = await EzoicInterstitialAd.load('12345');

        // Optional: observe lifecycle events
        ad.setListeners({
            onShown: () => console.log('Interstitial ad shown'),
            onFailedToShow: (error) => console.warn('Show failed', error.message),
        });

        await ad.show();
        console.log('Interstitial ad closed');
    } catch (error) {
        console.warn('Interstitial ad failed to load', error);
    }
}
```

Replace `12345` with your Ezoic ad unit identifier (passed as a string). Load and `show` are separate steps; calling `show()` before the ad has loaded rejects with an error. Interstitial ads are single-use and auto-destroy once dismissed — load a new `EzoicInterstitialAd` for each opportunity. Call `ad.destroy()` yourself only if you loaded an ad and never showed it.

`setListeners` accepts `onShown`, `onFailedToShow`, `onImpression`, `onClicked`, and `onDismissed` — all optional.

## Add an Outstream Video Ad

Render `EzoicOutstreamAdView` where the video should appear. Like `EzoicNativeAdView`, it has no `size` prop — size it with `style` and the native view lays the player out inside those bounds. It is view-managed: mounting the component loads the ad, unmounting destroys it.

```tsx
import { EzoicOutstreamAdView } from '@ezoic/react-native-sdk';

export function ArticleScreen() {
    return (
        <EzoicOutstreamAdView
            adUnitIdentifier="12345"
            style={{ width: '100%', height: 250 }}
            onLoad={() => console.log('Ezoic outstream ad loaded')}
            onError={(error) => console.warn('Ezoic outstream ad failed', error)}
            onImpression={() => console.log('Ezoic outstream ad impression')}
            onClick={() => console.log('Ezoic outstream ad clicked')}
            onOpen={() => console.log('Ezoic outstream ad opened an overlay')}
            onClose={() => console.log('Ezoic outstream ad overlay closed')}
        />
    );
}
```

Replace `12345` with your Ezoic ad unit identifier. The native SDKs render the ad inline through Google Ad Manager at the size configured on the server.

`EzoicOutstreamAdView` supports these event props:

- `onLoad`: the outstream ad received an ad
- `onError`: the outstream ad failed to load; receives an error object
- `onImpression`: an impression was recorded
- `onClick`: the user tapped the ad
- `onOpen`: the ad opened a full-screen overlay
- `onClose`: the full-screen overlay was dismissed


Like `EzoicNativeAdView`, `EzoicOutstreamAdView` accepts the Ezoic ad unit identifier as either a string or a number, for example `"12345"` or `12345`.


## Add an Instream Video Ad

`EzoicInstreamAd` is a view-less controller for instream (pre/mid/post-roll) video. Unlike the banner, native, and outstream components, it renders nothing: your app owns the video player and the Google IMA SDK, and its sole deliverable is a Google Ad Manager VAST ad-tag URL string you feed to your own IMA `AdsRequest`. Unlike rewarded and interstitial ads, a controller is multi-use — it is not auto-destroyed, so you `load()` it repeatedly and `destroy()` it yourself.

```tsx
import { EzoicInstreamAd } from '@ezoic/react-native-sdk';

async function runInstreamAd() {
    const instream = new EzoicInstreamAd('12345');

    try {
        const adTagUrl = await instream.load({ contentUrl: playingVideoUrl });
        adsLoader.requestAds({ adTagUrl });

        // On an IMA ad error, walk down the floor waterfall to the next tag.
        const next = await instream.getNextAdTagUrl(); // null once exhausted
        if (next) adsLoader.requestAds({ adTagUrl: next });

        // On the IMA STARTED event, fire the Ezoic impression pixel.
        await instream.reportImpression({ revenueUsd: 0.42 });
    } catch (error) {
        console.warn('Instream ad failed to load', error);
    } finally {
        await instream.destroy();
    }
}
```

Replace `12345` with your Ezoic ad unit identifier (passed as a string). `load({ contentUrl })` resolves with the tag URL, or rejects on no fill, an uninitialized SDK, or an overlapping load already in flight for this id; `contentUrl` is optional and, when supplied, is added to the tag for contextual targeting. `getNextAdTagUrl()` resolves to `null` once the waterfall is exhausted. `reportImpression({ revenueUsd })` records the Ezoic impression on the IMA `STARTED` event; `revenueUsd` is optional. Call `destroy()` when the ad unit is no longer needed — the controller otherwise stays alive and reusable across loads.

## Privacy and Consent

The native SDKs automatically read standard IAB consent signals from platform storage when a consent management platform sets them — `UserDefaults` on iOS and `SharedPreferences` on Android:

- TCF v2 consent from `IABTCF_*` keys
- GPP consent from `IABGPP_*` keys
- US Privacy consent from the standard IAB US Privacy key

If you manage consent yourself, set it from React Native before ads load:

```ts
await EzoicAds.setGDPRConsent(true, 'TCF_CONSENT_STRING');
await EzoicAds.setGPPConsent('GPP_STRING', '7');
await EzoicAds.setSubjectToCOPPA(false);
```

- `setGDPRConsent(applies, consentString)`: whether GDPR applies and the TCF consent string
- `setGPPConsent(gppString, sectionIds)`: the GPP string and applicable section IDs
- `setSubjectToCOPPA(subject)`: whether the user is subject to COPPA

Manual values take precedence over automatically read signals.

## Pageview Tracking

After initialization, the native SDKs automatically track platform navigation: view controller transitions on iOS, and Activity, Fragment, and view-hosted Navigation on Android.

Because React Native apps drive screens from JavaScript, the native navigation signals do not see your in-app routes. Track a pageview manually whenever the active route changes so ad pacing and reporting stay accurate:

```ts
await EzoicAds.trackPageview();
```

If you use React Navigation, call it from a navigation state listener:

```tsx
import { NavigationContainer } from '@react-navigation/native';
import { EzoicAds } from '@ezoic/react-native-sdk';

export function Root() {
    return (
        <NavigationContainer
            onStateChange={() => {
                EzoicAds.trackPageview();
            }}
        >
            {/* navigators */}
        </NavigationContainer>
    );
}
```

## Troubleshooting

### SDK Not Initializing

1. Confirm the configured `domain` matches your Ezoic dashboard.
2. Confirm the device or simulator has network access.
3. Enable `debugEnabled: true` and review native logs: Logcat for `EzoicAds` on Android, the Xcode console on iOS.
4. On iOS, confirm `pod install` ran after installing the package and that the build uses the generated workspace.

### Ads Not Loading

1. Make sure `EzoicAds.initialize` runs and resolves before `EzoicBannerView` or `EzoicNativeAdView` mounts.
2. Confirm the Ezoic ad unit identifier is configured in Ezoic and passed as a string.
3. Confirm the Google Mobile Ads application ID is present in `AndroidManifest.xml` (Android) and `Info.plist` (iOS).
4. Give the banner explicit `style` dimensions large enough for the requested size.
5. Check consent configuration if your traffic is subject to privacy regulations.

### Build Failures

1. Android: confirm `google()` and `mavenCentral()` are available to your app's Gradle repositories.
2. iOS: delete `ios/Pods` and `ios/Podfile.lock`, then run `pod install` again.
3. Confirm your React Native version meets the minimum requirement and that autolinking is enabled.

