Lightweight, JS-only fallback ad components for React Native & Expo — no native modules, no native linking required.
When your primary ad SDK fails to load — network errors, no fill, SDK initialisation issues, ad blockers — react-native-fallback-ads lets you drop in a polished, self-contained ad unit in seconds. All components are written in pure JavaScript/TypeScript with zero native dependencies.
- Features
- Installation
- Components
- Utilities
- Link Resolution
- Theme Support
- TypeScript
- Requirements
- Support Us
- Advertise Our Apps
- ✅ Zero native code — pure JS/TS, works with Expo Go and managed workflow
- 🎨 Light / dark / auto theme support on every component
- 🔁 Multi-image cycling with smooth animations (
flip,3d-flip,fade,none) - 🖼 Fullscreen interstitial with configurable close-button delay and countdown badge
- 🎁 Rewarded video ad support with custom watch-to-end or close-delay modes
- ♿ Accessible — every component ships with proper
accessibilityRoleandaccessibilityLabel - 🔧 Fully typed — complete TypeScript definitions included
npm install react-native-fallback-ads
# or
yarn add react-native-fallback-adsNo pod install, no expo prebuild, no npx react-native link needed.
A smart banner that accepts an array of mixed text/image ad configs and randomly selects one to display. Exposes a ref with a refresh() method to pick a new random ad on demand.
import { useRef } from 'react';
import { FallbackBannerAd, FallbackBannerAdRef } from 'react-native-fallback-ads';
const bannerRef = useRef<FallbackBannerAdRef>(null);
<FallbackBannerAd
ref={bannerRef}
theme="auto"
data={[
{
type: 'text',
icon: require('./assets/app-icon.png'),
title: 'My Awesome App',
subtitle: 'Download it free today',
link: 'https://example.com/app',
},
{
type: 'image',
image: require('./assets/banner.png'),
link: 'https://example.com/promo',
},
]}
/>
// Refresh the displayed ad at any time:
bannerRef.current?.refresh();| Prop | Type | Default | Description |
|---|---|---|---|
data |
BannerAdItem[] |
required | Array of text or image ad configs |
style |
ViewStyle |
— | Override container styles |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Color scheme |
mode |
'manual' | 'auto' |
'manual' |
Refresh mode. If 'auto', the ad will automatically refresh every refreshInterval ms |
refreshInterval |
number |
5000 |
Refresh interval in milliseconds (applicable when mode is 'auto') |
testID |
string |
— | Test identifier |
| Method | Description |
|---|---|
refresh() |
Randomly selects a new ad from data |
A compact 300 × 50 banner with an icon, title, and subtitle row. Best used as a house-ad or cross-promotion unit.
import { FallbackTextBannerAd } from 'react-native-fallback-ads';
<FallbackTextBannerAd
icon={require('./assets/icon.png')}
title="Try Our Pro Plan"
subtitle="Unlock all features — starting at $2.99"
link="https://example.com/pro"
onPress={(url) => console.log('Opened:', url)}
onError={(err) => console.warn('Ad error:', err)}
theme="auto"
/>| Prop | Type | Default | Description |
|---|---|---|---|
icon |
ImageSourcePropType |
required | App icon or logo displayed on the left |
title |
string |
required | Primary text (bold) |
subtitle |
string |
required | Secondary text |
link |
string |
— | The destination link to open when the ad is tapped |
onPress |
(url: string) => void |
— | Called after the link is successfully opened |
onError |
(err: AdError) => void |
— | Called when the link cannot be resolved or opened |
style |
ViewStyle |
— | Override container styles |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Color scheme |
testID |
string |
— | Test identifier |
A 320 × 50 image banner that supports a single image or an array of images that cycle automatically with smooth animations.
import { FallbackImageBannerAd } from 'react-native-fallback-ads';
// Single image
<FallbackImageBannerAd
image={require('./assets/banner.png')}
link="https://example.com"
theme="auto"
/>
// Cycling images with 3D flip transition
<FallbackImageBannerAd
images={[
require('./assets/banner1.png'),
require('./assets/banner2.png'),
require('./assets/banner3.png'),
]}
switchInterval={4000}
animationType="3d-flip"
link="https://example.com"
onPress={(url) => console.log('Tapped:', url)}
/>| Prop | Type | Default | Description |
|---|---|---|---|
image |
ImageSourcePropType |
— | Single image to display |
images |
ImageSourcePropType[] |
— | Array of images to cycle (overrides image) |
switchInterval |
number |
5000 |
Milliseconds between image switches |
animationType |
'flip' | '3d-flip' | 'fade' | 'none' |
'flip' |
Transition animation |
link |
string |
— | The destination link to open when the ad is tapped |
onPress |
(url: string) => void |
— | Called after the link is successfully opened |
onError |
(err: AdError) => void |
— | Called on link or image errors |
style |
ViewStyle |
— | Override container styles |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Color scheme |
testID |
string |
— | Test identifier |
A 300 × 250 medium rectangle (MREC) image ad — the industry-standard "box" format. Supports all the same cycling and animation options as FallbackImageBannerAd, plus a horizontal 3D flip variant.
import { FallbackMrecAd } from 'react-native-fallback-ads';
<FallbackMrecAd
images={[
require('./assets/mrec1.png'),
require('./assets/mrec2.png'),
]}
switchInterval={6000}
animationType="3d-flip-horizontal"
link={
Platform.select({
android: 'market://details?id=com.example.app',
ios: 'https://apps.apple.com/app/id123456789',
default: 'https://example.com',
})
}
onPress={(url) => console.log('Opened:', url)}
theme="dark"
/>Same as FallbackImageBannerAd, with one additional animationType option:
| Prop | Type | Default | Description |
|---|---|---|---|
animationType |
'flip' | '3d-flip' | '3d-flip-horizontal' | 'fade' | 'none' |
'flip' |
Transition animation (adds horizontal 3D flip) |
All other props are identical to FallbackImageBannerAd.
A unified, full-screen interstitial ad component rendered inside a React Native Modal. Under the hood, it automatically delegates to either FallbackFullscreenImageAd or FallbackFullscreenVideoAd based on whether video props (portraitVideo or landscapeVideo) are provided.
import { useState } from 'react';
import { FallbackFullscreenAd } from 'react-native-fallback-ads';
const [adVisible, setAdVisible] = useState(false);
// Automatically renders FallbackFullscreenImageAd
<FallbackFullscreenAd
visible={adVisible}
portraitImage={require('./assets/interstitial-portrait.png')}
landscapeImage={require('./assets/interstitial-landscape.png')}
showCloseButton={true}
closeDelay={5}
link="https://example.com/promo"
onDismiss={() => setAdVisible(false)}
/>
// Automatically renders FallbackFullscreenVideoAd
<FallbackFullscreenAd
visible={adVisible}
portraitVideo={require('./assets/video-portrait.mp4')}
landscapeVideo={require('./assets/video-landscape.mp4')}
showCloseButton={true}
closeDelay={5}
link="https://example.com/promo"
onDismiss={() => setAdVisible(false)}
/>Since FallbackFullscreenAd serves as a wrapper, it accepts all props for both image and video fullscreen ads:
| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
true |
Controls modal visibility |
portraitImage |
ImageSourcePropType |
— | Portrait image source. (Used for Image Ads) |
landscapeImage |
ImageSourcePropType |
— | Landscape image source. Falls back to portraitImage. (Used for Image Ads) |
portraitVideo |
any |
— | Portrait video source (require or URI object). (Used for Video Ads) |
landscapeVideo |
any |
— | Landscape video source. Falls back to portraitVideo. (Used for Video Ads) |
onDismiss |
() => void |
— | Called when the close button is pressed or ad is dismissed |
link |
string |
— | Destination URL when the ad is tapped |
onPress |
(resolvedUrl: string) => void |
— | Callback after the link is successfully opened |
onError |
(err: AdError) => void |
— | Callback on link, image, or video loading/playback errors |
showCloseButton |
boolean |
true |
Show/hide the close button |
closeDelay |
number |
5 |
Countdown in seconds before close button is active |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Theme scheme |
testID |
string |
— | Test identifier |
Specifically renders a fullscreen image ad.
import { FallbackFullscreenImageAd } from 'react-native-fallback-ads';
<FallbackFullscreenImageAd
visible={visible}
portraitImage={require('./assets/portrait.png')}
landscapeImage={require('./assets/landscape.png')}
onDismiss={() => setVisible(false)}
/>| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
true |
Controls modal visibility |
portraitImage |
ImageSourcePropType |
— | Portrait image source |
landscapeImage |
ImageSourcePropType |
— | Landscape image source. Falls back to portraitImage |
onDismiss |
() => void |
— | Called when the close button is pressed |
link |
string |
— | Destination URL when the ad is tapped |
onPress |
(resolvedUrl: string) => void |
— | Callback after the link is successfully opened |
onError |
(err: { type: 'NO_LINK' | 'LINK_FAILED' | 'NO_IMAGE'; message?: string }) => void |
— | Callback on link or image load errors |
showCloseButton |
boolean |
true |
Show/hide the close button |
closeDelay |
number |
5 |
Countdown in seconds before close button is active |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Theme scheme |
testID |
string |
— | Test identifier |
Specifically renders a fullscreen video ad.
To keep this library lightweight and avoid native linking conflicts, video players are not bundled directly. Instead, FallbackFullscreenVideoAd dynamically detects and supports the following player libraries if they are installed in the host project:
react-native-videoexpo-video
Important
You must install either react-native-video or expo-video to use the fullscreen video ad component.
- Install a supported video library:
Choose and install one of the supported video players in your host project:
- React Native CLI (or bare Expo):
Note: Ensure the library is properly linked. For modern React Native versions, this is done automatically. If you're on an older version, run
npm install react-native-video # or yarn add react-native-videopod installinside theiosdirectory. - Expo Managed Workflow:
npx expo install expo-video
- React Native CLI (or bare Expo):
- Import the component:
import { FallbackFullscreenVideoAd } from 'react-native-fallback-ads';
- Provide Video Sources:
Pass local requires (e.g.,
require('./assets/ad.mp4')) or remote source objects (e.g.,{ uri: 'https://example.com/ad.mp4' }) toportraitVideoandlandscapeVideoprops. - Orientation Lock Behavior: To prevent visual glitches and layout shifts, the component locks its orientation to whichever mode (portrait or landscape) the device is in when the video begins playing. Rotating the phone during playback scales the video but does not switch the active source or reset playback progress.
import { FallbackFullscreenVideoAd } from 'react-native-fallback-ads';
<FallbackFullscreenVideoAd
visible={visible}
portraitVideo={require('./assets/video-portrait.mp4')}
landscapeVideo={require('./assets/video-landscape.mp4')}
onDismiss={() => setVisible(false)}
closeDelay={5}
/>| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
true |
Controls modal visibility |
portraitVideo |
any |
— | Portrait video source (require or URI object) |
landscapeVideo |
any |
— | Landscape video source. Falls back to portraitVideo |
onDismiss |
() => void |
— | Called when the close button is pressed |
link |
string |
— | Destination URL when the ad is tapped |
onPress |
(resolvedUrl: string) => void |
— | Callback after the link is successfully opened |
onError |
(err: { type: 'NO_LINK' | 'LINK_FAILED' | 'NO_VIDEO'; message?: string }) => void |
— | Callback on link or video loading/playback errors |
showCloseButton |
boolean |
true |
Show/hide the close button |
closeDelay |
number |
5 |
Countdown in seconds before close button is active |
theme |
'light' | 'dark' | 'auto' |
'auto' |
Theme scheme |
forceWatchToEnd |
boolean |
false |
If true, countdown doesn't run and the close button is hidden until the video ends or parent dismisses the ad |
onVideoEnd |
() => void |
— | Callback when the video finishes playing |
onCountdownEnd |
() => void |
— | Callback when the close delay countdown reaches 0 |
closeButtonAccessory |
React.ReactNode |
— | Optional React node to render next to the close button (e.g. badges) |
testID |
string |
— | Test identifier |
A specialized wrapper around FallbackFullscreenVideoAd tailored for rewarded ad placements. It provides reward hooks and supports two modes of interaction.
- Watch to End Mode (Default - no
closeDelayprovided): The user must watch the video until completion to earn the reward. The close button is hidden during playback, and once the video finishes,onRewardis triggered and the ad automatically closes. - Countdown Mode (with
closeDelayprovided, e.g.closeDelay={15}): A countdown is shown. When the countdown completes, a green "Rewarded" badge appears next to the close button, indicating they can now close the ad to claim their reward. The ad remains open until the user taps the close button, at which point theonRewardcallback is triggered.
import { FallbackRewardedVideoAd } from 'react-native-fallback-ads';
<FallbackRewardedVideoAd
visible={visible}
portraitVideo={require('./assets/rewarded-portrait.mp4')}
onReward={() => console.log('User rewarded!')}
onDismiss={() => setVisible(false)}
/>Inherits all props from FallbackFullscreenVideoAdProps except onVideoEnd, onCountdownEnd, forceWatchToEnd, and closeButtonAccessory.
| Prop | Type | Default | Description |
|---|---|---|---|
onReward |
() => void |
— | Callback triggered when the reward condition is met |
onDismiss |
() => void |
— | Callback when the ad is closed (either automatically after completion or manually after countdown) |
closeDelay |
number |
— | If provided, allows closing after this many seconds to get reward. If omitted, forces watching to completion |
A standalone helper that picks the right URL for the current platform. Useful if you want to open the link manually.
import { resolveLink } from 'react-native-fallback-ads';
const url = resolveLink(
'market://details?id=com.example.app', // androidLink
'https://apps.apple.com/app/id123', // iosLink
'https://example.com', // commonLink (fallback)
);
// Returns:
// Android → 'market://details?id=com.example.app'
// iOS → 'https://apps.apple.com/app/id123'
// Other → 'https://example.com'
// No match → nullYou can use React Native's Platform.select directly in the link prop to provide platform-specific URLs, or you can use our included resolveLink helper manually if needed.
All ad components accept an onError callback that receives one of the following error objects:
type AdError =
| { type: 'NO_LINK'; message?: string } // No link provided for this platform
| { type: 'LINK_FAILED'; message?: string } // Linking.openURL failed
| { type: 'NO_IMAGE'; message?: string } // Image failed to load
| { type: 'NO_VIDEO'; message?: string } // Video failed to loadAll components accept a theme prop:
| Value | Behaviour |
|---|---|
'auto' (default) |
Follows the device's system color scheme via useColorScheme() |
'light' |
Forces light theme |
'dark' |
Forces dark theme |
All props interfaces and utility types are exported from the package root:
import type {
// Component props
FallbackBannerAdProps,
FallbackBannerAdRef,
FallbackTextBannerAdProps,
FallbackImageBannerAdProps,
FallbackMrecAdProps,
FallbackFullscreenAdProps,
FallbackFullscreenImageAdProps,
FallbackFullscreenVideoAdProps,
FallbackRewardedVideoAdProps,
// Data types
BannerAdItem,
BannerAdTextData,
BannerAdImageData,
} from 'react-native-fallback-ads';| Dependency | Minimum version |
|---|---|
react |
>= 19.2.0 |
react-native |
>= 0.83.0 |
Works with Expo SDK 52+ (managed & bare workflow) and plain React Native CLI projects.
This library is free and open-source. If it saves you time, please consider supporting the developers by checking out our app:
A simple, privacy-friendly personal finance tracker for Android.
You can show your support in two easy ways:
-
⭐ Try our app & share your feedback — we invite you to try our new app. If you like it, please consider leaving a review or providing us feedback directly from the app. It helps the app reach more people and keeps us motivated to maintain this library.
-
💎 Purchase the Premium Add-on — unlock extra features inside CashBook and directly fund continued development of open-source tools like this one.
👉 Open CashBook on Google Play
Thank you — every download and review genuinely makes a difference! 🙏
MIT © Inocentum Technologies