Preroll Ads

Preroll ads are video ads that play before your content. The SDK manages playback automatically using Google IMA — the ad auto-plays with no user-visible controls. Users can skip the ad when the VAST creative allows it.

After the ad completes, is skipped, or fails, your content can start playing automatically. No additional handling is needed.

Each ad format uses a Zone ID to identify the ad placement. Zone IDs are configured in the Empower dashboard.

Note: All ad listeners are optional. The SDK handles ad loading, playback, and fallback automatically. Use listeners only if you need to track ad states for analytics or UI updates.


Platform Differences

Preroll ads use different native player components per platform:

PlatformPlayer ComponentContainer
AndroidPlayerView (Media3/ExoPlayer)androidx.media3.ui.PlayerView
iOSIMA SDKUIView container

Important (iOS): The IMA SDK requires rootViewController to be set for proper ad presentation. The React Native bridge sets this automatically during init() via EMASettings.shared.rootViewController. If you encounter issues with preroll ads not displaying on iOS, ensure SDK initialization completes before loading preroll ads.


Loading a Preroll Ad

Using loadPrerollAd

import {
loadPrerollAd,
addEventListener,
EmpowerAdsEvents,
AdStatus,
} from '@empower-nokta/react-native-mobile-ads';
const ZONE_ID = { android: 'ANDROID_PREROLL_ZONE_ID', ios: 'IOS_PREROLL_ZONE_ID' };
// Load preroll ad with a content video URL
loadPrerollAd({
zoneId: ZONE_ID,
contentUrl: 'https://example.com/your-content-video.mp4',
muted: false, // Optional: mute ad audio
});

Parameters

ParameterTypeRequiredDefaultDescription
zoneIdstring \| { android?: string, ios?: string }YesThe zone ID for the preroll placement
contentUrlstringYesURL of the content video that plays after the ad
mutedbooleanNofalseWhether to mute audio during ad playback

Using the EmpowerPrerollView Component

For inline video ad placement, use the EmpowerPrerollView component:

import { EmpowerPrerollView } from '@empower-nokta/react-native-mobile-ads';
function VideoScreen() {
return (
<EmpowerPrerollView
zoneId="YOUR_PREROLL_ZONE_ID"
contentUrl="https://example.com/your-content-video.mp4"
muted={false}
onPrerollStatusChanged={(event) => {
console.log('Preroll status:', event.nativeEvent.status);
}}
onPrerollAdEvent={(event) => {
console.log('IMA event:', event.nativeEvent.type);
}}
style={{ width: '100%', aspectRatio: 16 / 9 }}
/>
);
}

Props

PropTypeRequiredDescription
zoneIdstring \| { android?: string, ios?: string }YesZone ID for the preroll placement
contentUrlstringYesURL of the content video
mutedbooleanNoMute ad audio (default: false)
onPrerollStatusChanged(event) => voidNoCalled when preroll ad status changes
onPrerollAdEvent(event) => voidNoCalled for IMA ad events (quartile progress, etc.)
styleViewStyleNoContainer style. Recommended: { width: '100%', aspectRatio: 16/9 }

Listening to Preroll Events (Optional)

Status Changes

import { addEventListener, EmpowerAdsEvents, AdStatus } from '@empower-nokta/react-native-mobile-ads';
const unsubStatus = addEventListener(
EmpowerAdsEvents.PREROLL_STATUS,
(event) => {
switch (event.status) {
case AdStatus.READY:
// Ad is loaded and about to play
break;
case AdStatus.ACTIVE:
// Ad is playing
break;
case AdStatus.COMPLETE_PLAYING:
// Ad finished — content video is now playing
break;
case AdStatus.FAILED:
// Ad failed — content video plays automatically
break;
case AdStatus.PAUSED:
// Ad playback paused
break;
}
}
);
// Clean up
unsubStatus();

IMA Ad Events

Track granular ad playback progress:

const unsubAd = addEventListener(
EmpowerAdsEvents.PREROLL_AD,
(event) => {
switch (event.type) {
case 'STARTED':
// Ad playback started
break;
case 'FIRST_QUARTILE':
// 25% of the ad has played
break;
case 'MIDPOINT':
// 50% of the ad has played
break;
case 'THIRD_QUARTILE':
// 75% of the ad has played
break;
case 'COMPLETE':
// Ad playback finished
break;
case 'SKIPPED':
// User skipped the ad
break;
case 'CLICKED':
// User clicked the ad
break;
}
}
);
// Clean up
unsubAd();

Lifecycle Management

The SDK automatically manages the ad lifecycle based on the component's visibility. For special cases like scrolling the video player off-screen in a FlatList, use the control functions:

import { pausePreroll, resumePreroll, destroyPreroll } from '@empower-nokta/react-native-mobile-ads';
const ZONE_ID = 'YOUR_PREROLL_ZONE_ID';
// Pause playback (e.g., view scrolled off-screen)
pausePreroll(ZONE_ID);
// Resume playback (e.g., view scrolled back)
resumePreroll(ZONE_ID);
// Release all resources when done
destroyPreroll(ZONE_ID);
MethodDescription
pausePreroll(zoneId)Pauses ad or content playback
resumePreroll(zoneId)Resumes playback
destroyPreroll(zoneId)Releases player resources

Tip: Call destroyPreroll when the screen unmounts to free native resources.


Complete Example

import React, { useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import {
EmpowerPrerollView,
addEventListener,
EmpowerAdsEvents,
destroyPreroll,
} from '@empower-nokta/react-native-mobile-ads';
const ZONE_ID = { android: 'ANDROID_PREROLL_ZONE_ID', ios: 'IOS_PREROLL_ZONE_ID' };
export default function VideoScreen() {
useEffect(() => {
const unsubStatus = addEventListener(
EmpowerAdsEvents.PREROLL_STATUS,
(event) => {
console.log('Preroll status:', event.status);
}
);
const unsubAd = addEventListener(
EmpowerAdsEvents.PREROLL_AD,
(event) => {
console.log('IMA event:', event.type);
}
);
return () => {
unsubStatus();
unsubAd();
destroyPreroll(ZONE_ID);
};
}, []);
return (
<View style={styles.container}>
<EmpowerPrerollView
zoneId={ZONE_ID}
contentUrl="https://example.com/content-video.mp4"
style={styles.player}
/>
<Text style={styles.title}>Video Title</Text>
<Text style={styles.description}>Video description goes here...</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
player: { width: '100%', aspectRatio: 16 / 9 },
title: { color: '#fff', fontSize: 18, fontWeight: 'bold', padding: 16 },
description: { color: '#ccc', fontSize: 14, paddingHorizontal: 16 },
});

Best Practices

  • Set explicit aspect ratio — Use aspectRatio: 16/9 on the container for standard video proportions
  • Mute when appropriate — Set muted={true} if the video auto-plays in a feed or silent context
  • Destroy on unmount — Always call destroyPreroll in the cleanup function of useEffect to release native player resources
  • Frequency capping — The SDK respects server-configured session frequency caps
  • Content URL required — Always provide a valid contentUrl. The ad plays first, then transitions to your content video automatically

iOS: rootViewController

The IMA SDK on iOS requires a rootViewController reference for proper ad presentation. The bridge sets this automatically during SDK initialization:

// Set automatically inside init()
EMASettings.shared.rootViewController = rootViewController

If preroll ads fail to display on iOS, verify that:

  1. SDK initialization (init()) has completed before loading preroll ads
  2. The app has a visible root view controller at the time of initialization
  3. EMASettings.shared.rootViewController is set — the bridge does this automatically, but if you override initialization, ensure it's included

Ad Status Reference

StatusDescription
READYAd is loaded and about to play
ACTIVEAd is playing
COMPLETE_PLAYINGAd finished playing, content video is now playing
SKIPPEDUser skipped the ad, content video is now playing
FAILEDAd failed, content video plays automatically
PAUSEDAd playback paused

Troubleshooting

Preroll Not Playing on iOS

  1. Check rootViewController is set:
// Enable debug logs to verify
setLogLevel('all');
  1. Ensure SDK is initialized before loading preroll

  2. Check zone ID is correct and active in the Empower dashboard

Preroll Not Playing on Android

  1. Ensure Media3 (ExoPlayer) dependency is available — the SDK includes it transitively, but verify no version conflicts exist

  2. Check the content URL is accessible — the SDK needs a valid video URL to transition to after the ad

Video Playback Issues

  • Black screen: Verify container dimensions are set correctly (non-zero width and height)
  • Audio issues: Check the muted prop and device volume settings
  • Memory leaks: Always call destroyPreroll when navigating away from the video screen