React Native Integration Guide

Integrate AppSpike into your React Native app and serve your first ad in under 10 minutes.

AppSpike sits on top of your existing ad networks and uses real-time bidding to route every impression to the highest-paying demand source. You keep your current ad network accounts — AppSpike optimizes across all of them.

Prerequisites

Step 1: Install the SDK

Install the AppSpike React Native package:

npm
npm install @appspike/react-native
yarn
yarn add @appspike/react-native

Android Setup

Add the AppSpike Maven repository to your project-level android/build.gradle:

android/build.gradle
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://sdk.appspike.dev/android' }
    }
}

iOS Setup

Install CocoaPods dependencies:

cd ios && pod install && cd ..

Add the NSUserTrackingUsageDescription key to your ios/<YourApp>/Info.plist for App Tracking Transparency compliance:

Info.plist
<key>NSUserTrackingUsageDescription</key>
<string>This allows us to show you more relevant ads.</string>

Step 2: Initialize the SDK

Initialize AppSpike as early as possible, ideally in your root component or entry point. Pass your App ID directly:

App.tsx
import React, { useEffect } from 'react';
import { AppSpike } from '@appspike/react-native';

const App: React.FC = () => {
  useEffect(() => {
    AppSpike.initialize({ appId: "YOUR_APP_ID" })
      .then((result) => {
        console.log(`AppSpike initialized — ${result.adapterCount} adapters loaded`);
      })
      .catch((error) => {
        console.error(`AppSpike init failed: ${error.message}`);
      });
  }, []);

  return (
    // Your app content
  );
};

export default App;

Use the <AppSpikeBanner /> component to render banner ads declaratively:

HomeScreen.tsx
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { AppSpikeBanner, BannerAdSize } from '@appspike/react-native';

const HomeScreen: React.FC = () => {
  return (
    <View style={styles.container}>
      {/* Your screen content */}
      <View style={styles.content}>
        {/* ... */}
      </View>

      {/* Banner pinned to bottom */}
      <AppSpikeBanner
        placementId="YOUR_APPSPIKE_PLACEMENT"
        size={BannerAdSize.BANNER}
        onAdLoaded={() => console.log('Banner loaded')}
        onAdFailedToLoad={(error) => console.error(`Banner failed: ${error.message}`)}
        onAdClicked={() => console.log('Banner clicked')}
        style={styles.banner}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1 },
  content: { flex: 1 },
  banner: { alignSelf: 'center' },
});

export default HomeScreen;

Available BannerAdSize options: BANNER, LARGE_BANNER, MEDIUM_RECTANGLE, FULL_BANNER, LEADERBOARD, ADAPTIVE.

Step 4: Interstitial Ads

Use the useInterstitialAd hook to load and show interstitials at natural break points:

GameScreen.tsx
import React, { useEffect } from 'react';
import { Button, View } from 'react-native';
import { useInterstitialAd } from '@appspike/react-native';

const GameScreen: React.FC = () => {
  const { load, show, isLoaded, isClosed } = useInterstitialAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    load();
  }, [load]);

  // Reload after the ad is dismissed
  useEffect(() => {
    if (isClosed) {
      load();
    }
  }, [isClosed, load]);

  const handleLevelComplete = () => {
    if (isLoaded) {
      show();
    }
    // Continue to next level
    navigateToNextLevel();
  };

  return (
    <View>
      <Button title="Next Level" onPress={handleLevelComplete} />
    </View>
  );
};

export default GameScreen;

Step 5: Rewarded Ads

Use the useRewardedAd hook when the user opts in to watch an ad for a reward:

StoreScreen.tsx
import React, { useEffect, useState } from 'react';
import { Button, Text, View } from 'react-native';
import { useRewardedAd } from '@appspike/react-native';

const StoreScreen: React.FC = () => {
  const [coins, setCoins] = useState(0);
  const { load, show, isLoaded, reward, isClosed } = useRewardedAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    load();
  }, [load]);

  // Reload after dismissal
  useEffect(() => {
    if (isClosed) {
      load();
    }
  }, [isClosed, load]);

  // Grant reward when earned
  useEffect(() => {
    if (reward) {
      console.log(`User earned: ${reward.amount} ${reward.type}`);
      setCoins((prev) => prev + reward.amount);
    }
  }, [reward]);

  return (
    <View>
      <Text>Coins: {coins}</Text>
      <Button
        title="Watch Ad for 50 Coins"
        onPress={() => show()}
        disabled={!isLoaded}
      />
    </View>
  );
};

export default StoreScreen;

Step 6: Native Ads

Use the useNativeAd hook to load native ads and bind them to your own custom layout:

NativeAdComponent.tsx
import React, { useEffect } from 'react';
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
import { useNativeAd, NativeAdView } from '@appspike/react-native';

const NativeAdComponent: React.FC = () => {
  const { load, ad, isLoaded } = useNativeAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    load();
  }, [load]);

  if (!isLoaded || !ad) return null;

  return (
    <NativeAdView ad={ad} style={styles.container}>
      <View style={styles.header}>
        <Image source={{ uri: ad.iconUrl }} style={styles.icon} />
        <View>
          <Text style={styles.headline}>{ad.headline}</Text>
          <Text style={styles.body}>{ad.body}</Text>
        </View>
      </View>
      <TouchableOpacity style={styles.cta}>
        <Text style={styles.ctaText}>{ad.callToAction}</Text>
      </TouchableOpacity>
    </NativeAdView>
  );
};

const styles = StyleSheet.create({
  container: { padding: 16, backgroundColor: '#f9f9f9', borderRadius: 12 },
  header: { flexDirection: 'row', gap: 12, marginBottom: 12 },
  icon: { width: 48, height: 48, borderRadius: 8 },
  headline: { fontSize: 16, fontWeight: '700' },
  body: { fontSize: 14, color: '#666' },
  cta: { backgroundColor: '#4A9EFF', padding: 12, borderRadius: 8, alignItems: 'center' },
  ctaText: { color: '#fff', fontWeight: '600' },
});

export default NativeAdComponent;

Step 7: App Open Ads

App open ads display when users bring your app to the foreground. Use the useAppOpenAd hook with React Native's AppState listener:

AppOpenAdManager.tsx
import React, { useEffect, useRef } from 'react';
import { AppState, AppStateStatus } from 'react-native';
import { useAppOpenAd } from '@appspike/react-native';

const AppOpenAdManager: React.FC = () => {
  const appState = useRef(AppState.currentState);
  const { load, show, isLoaded, isClosed } = useAppOpenAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    load();
  }, [load]);

  // Reload after dismissal
  useEffect(() => {
    if (isClosed) {
      load();
    }
  }, [isClosed, load]);

  useEffect(() => {
    const subscription = AppState.addEventListener('change', (nextState: AppStateStatus) => {
      if (appState.current.match(/inactive|background/) && nextState === 'active') {
        if (isLoaded) {
          show();
        }
      }
      appState.current = nextState;
    });

    return () => subscription.remove();
  }, [isLoaded, show]);

  return null; // This component manages ads, no UI needed
};

export default AppOpenAdManager;

Mount this component at the root of your app:

App.tsx
const App: React.FC = () => {
  return (
    <>
      <AppOpenAdManager />
      <NavigationContainer>
        {/* Your screens */}
      </NavigationContainer>
    </>
  );
};

Step 8: Rewarded Interstitial Ads

Rewarded interstitials combine the full-screen experience of an interstitial with an opt-in reward. Unlike standard rewarded ads, they can be shown without the user explicitly choosing to watch:

LevelTransition.tsx
import React, { useEffect, useState } from 'react';
import { Button, Text, View } from 'react-native';
import { useRewardedInterstitialAd } from '@appspike/react-native';

const LevelTransition: React.FC = () => {
  const [bonusCoins, setBonusCoins] = useState(0);
  const { load, show, isLoaded, reward, isClosed } = useRewardedInterstitialAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    load();
  }, [load]);

  // Reload after dismissal
  useEffect(() => {
    if (isClosed) {
      load();
    }
  }, [isClosed, load]);

  // Grant reward when earned
  useEffect(() => {
    if (reward) {
      console.log(`User earned: ${reward.amount} ${reward.type}`);
      setBonusCoins((prev) => prev + reward.amount);
    }
  }, [reward]);

  const handleContinue = () => {
    if (isLoaded) {
      show();
    }
    navigateToNextLevel();
  };

  return (
    <View>
      <Text>Bonus Coins: {bonusCoins}</Text>
      <Button title="Continue" onPress={handleContinue} />
    </View>
  );
};

export default LevelTransition;

Context / Provider Pattern

For production apps, use an AppSpikeProvider to centralize ad management across your entire app:

AppSpikeProvider.tsx
import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
import type { ReactNode } from 'react';
import { AppSpike, useInterstitialAd, useRewardedAd } from '@appspike/react-native';

interface AdContextType {
  isInitialized: boolean;
  showInterstitial: () => void;
  showRewarded: (onReward: (amount: number) => void) => void;
  isInterstitialReady: boolean;
  isRewardedReady: boolean;
}

const AdContext = createContext<AdContextType | null>(null);

export const useAds = (): AdContextType => {
  const context = useContext(AdContext);
  if (!context) throw new Error('useAds must be used within AppSpikeProvider');
  return context;
};

interface Props {
  appId: string;
  children: ReactNode;
}

export const AppSpikeProvider: React.FC<Props> = ({ appId, children }) => {
  const [isInitialized, setIsInitialized] = useState(false);

  const interstitial = useInterstitialAd("YOUR_APPSPIKE_PLACEMENT");
  const rewarded = useRewardedAd("YOUR_APPSPIKE_PLACEMENT");

  useEffect(() => {
    AppSpike.initialize({ appId })
      .then(() => setIsInitialized(true))
      .catch((err) => console.error(`AppSpike init failed: ${err.message}`));
  }, [appId]);

  // Load ads once initialized
  useEffect(() => {
    if (isInitialized) {
      interstitial.load();
      rewarded.load();
    }
  }, [isInitialized]);

  // Reload after dismissal
  useEffect(() => {
    if (interstitial.isClosed) interstitial.load();
  }, [interstitial.isClosed]);

  useEffect(() => {
    if (rewarded.isClosed) rewarded.load();
  }, [rewarded.isClosed]);

  const showInterstitial = useCallback(() => {
    if (interstitial.isLoaded) interstitial.show();
  }, [interstitial.isLoaded, interstitial.show]);

  const showRewarded = useCallback((onReward: (amount: number) => void) => {
    if (rewarded.isLoaded) {
      rewarded.show();
    }
  }, [rewarded.isLoaded, rewarded.show]);

  return (
    <AdContext.Provider
      value={{
        isInitialized,
        showInterstitial,
        showRewarded,
        isInterstitialReady: interstitial.isLoaded,
        isRewardedReady: rewarded.isLoaded,
      }}
    >
      {children}
    </AdContext.Provider>
  );
};

Wrap your app:

App.tsx
const App: React.FC = () => {
  return (
    <AppSpikeProvider appId="YOUR_APP_ID">
      <NavigationContainer>
        {/* Your screens */}
      </NavigationContainer>
    </AppSpikeProvider>
  );
};

Usage from any component:

LevelCompleteScreen.tsx
import { useAds } from './AppSpikeProvider';

const LevelCompleteScreen: React.FC = () => {
  const { showInterstitial, showRewarded, isRewardedReady } = useAds();

  return (
    <View>
      <Button
        title="Continue"
        onPress={() => {
          showInterstitial();
          navigateToNextLevel();
        }}
      />
      <Button
        title="Watch Ad for Bonus Coins"
        onPress={() => showRewarded((amount) => addCoins(amount))}
        disabled={!isRewardedReady}
      />
    </View>
  );
};

Testing

Enable test mode during development to avoid serving live ads:

AppSpike.initialize({ appId: "YOUR_APP_ID", testMode: true })
  .then(() => {
    // Test ads will always fill and never charge
  });

Use the built-in ad inspector to debug mediation and demand source selection:

AppSpike.openAdInspector();

The ad inspector shows:

Best Practices

Next Steps