Skip to main content

Integrating Rewarded Video Ads

This article will demonstrate the methods used to integrate Rewarded video ads into your app.

Rewarded video ad unit requirements

  • Do not place Rewarded Ad Units inside active in-game windows.
  • Ensure compliance–clearly disclose to users that they are engaging with an ad.
  • Do not promote or implement misleading or fraudulent rewards (e.g., free Robux, cash, or similar incentives) to drive video completion.
  • Rewards must be accurate, transparent, and fully honored.
  • Rewarded Ad Units must remain fully optional and cannot be required for accessing features, advancing in the app, or continuing core functionality.

Setup the Rewarded video ad container

  • The rewarded ad container must be hidden by default.
  • Use the visibility property only to control its display state. Do not use opacity, off-screen positioning, or other visual workarounds to hide the container.
  • The window hosting the rewarded video ad must be opened in transparent mode to ensure proper rendering and user experience.
Example CSS
#rewarded_container {
visibility: hidden;
width: 640px;
height: 480px;
}

You have full control over how and where the window containing the video player appears.

Example UX patterns:

  • Modal window.
  • Centered popup.
  • Overlay screen.
  • Dedicated reward screen.

You define the:

  • Width / height
    • The recommended Size for the ad container is 640x480 for best fill rates. A minimum size of 400x300 is enforced on the sdk level).
  • Styling.
  • Messaging.
  • Surrounding UI.

Initialize rewarded video ads on session start

Initialize rewarded ads once

const containerElement = document.getElementById('rewarded_container');

const rewardedAdInstance = new OwAd(containerElement, {
rewarded: true,
volume: 1,
containerId: "Test Me"
});

This immediately starts background ad requests for the entire session.

Accepting the reward offer

When the user chooses to watch an ad in order to receive a reward the app should open the reward UI (modal / window / screen) and then make the rewarded ad container visible.

function onUserAcceptReward() {
openRewardWindow();
containerElement.style.visibility = 'visible';
}

Use the the SDK to make sure:

  • If an ad is ready, then playback starts immediately, and the impression event fires.
  • If no ad is ready, then the error event is emitted.

Closing or canceling the reward flow

Your reward UI should allow users to exit the reward flow after accepting the offer (e.g., through a Close button or X icon). This allows the user to cancel the attempt if they change their mind before or during playback.

This action needs to originate from your app UI and not from the OW Ad player so make sure your app notifies the OwAd instance that the user canceled the attempt.

If an ad is already playing, the SDK will treat this as a skip event.

When a user quits the reward flow, your app should:

  • Notify the OwAd instance that the video should be skipped.
  • Hide the rewarded ad container (visibility: hidden)
  • Close or reset your reward UI (modal / window / screen).
function onUserQuitReward() {
rewardedAdInstance.skipVideo();
containerElement.style.visibility = 'hidden';
closeRewardWindow();
}

The SDK behavior should emit the video_ad_skipped event and then, continue the background ad fetching if additional ads aren't already available in the queue.

Event handling logic

Ad readiness (video_ad_ready)

The SDK emits video_ad_ready whenever an ad becomes available for playback. This occurs multiple times during a session as the SDK continues fetching ads in the background.

Each time the event is emitted, the number of available ads in the queue increases.

The event payload includes the readyAds property which contains the current total number of rewarded ads ready to play in the SDK queue.

This event signals availability only when:

  • It doesn't start playback.
  • It doesn’t show the ad container.
  • On playback start only when the rewarded container is set to visible.

How to use it

To use ad readiness:

  1. Track readiness as a count (not a boolean). This way more than one ad can be ready at the same time. Also, video_ad_ready may be emitted repeatedly with updated totals so its important to keep a local counter that mirrors the SDK queue size.
let readyAdsCount = 0;

rewardedAdInstance.addEventListener('video_ad_ready', (event) => {
// event.readyAds represents the current total ready in the queue
readyAdsCount = event.readyAds ?? 1;
updateRewardOfferState(readyAdsCount > 0);
});
  1. Decrement when an ad starts playing. When playback starts, treat it as consuming one ready ad from the queue.
rewardedAdInstance.addEventListener('impression', () => {
readyAdsCount = Math.max(0, readyAdsCount - 1);
updateRewardOfferState(readyAdsCount > 0);
});

Using readyAdsCount in your UX

  • If readyAdsCount > 0, at least one ad is ready. Enable “Watch Ad” / “Claim Reward” and offer the user another reward attempt.
  • If readyAdsCount === 0, disable the reward offer until the next video_ad_ready.
One ad per One user interaction

You should only play a single video ad per one user interaction. On each attempt outcome (completed, skipped, user closed the window, timeout/error), your app should:

  • Hide the rewarded container (visibility: hidden).
  • Close/reset your reward UI.
  • If readyAdsCount > 0, you may offer the user to watch another ad for another reward.
  • Start the next ad only after explicit user action by making the container visible again.
  • readyAdsCount > 0 means “an ad is ready,” not “an ad will auto-play.”

Handling non-ready states

When implemented correctly, rewarded ads should typically start playing immediately after the user accepts the reward offer, since ads are fetched continuously in the background.

However, short delays may still occur in rare cases due to factors such as:

  • Network latency.
  • Ad expiration between readiness and playback.
  • Temporary fill fluctuations.

To ensure a smooth user experience:

  • Only enable the reward action (e.g., “Watch Ad”) after receiving the video_ad_ready event.
  • If the user opens the reward UI, display a loading indicator until playback begins (until the impression event fires).
  • Avoid leaving users in an ambiguous state where the container is visible but no feedback is shown.
  • If playback does not begin within a reasonable timeframe, rely on the SDK error events (video_no_ready_ads, video_no_impression_timeout) to gracefully close the flow.

Start playing ads (Impression)

rewardedAdInstance.addEventListener('impression', () => {
console.log('Rewarded ad is playing');
});
  • Video playback begins automatically.
  • Reward flow is now locked until completion or failure.

Ad completed (Reward Granted)

rewardedAdInstance.addEventListener('complete', () => {
containerElement.style.visibility = 'hidden';
closeRewardWindow();
grantUserReward();
});

This event is critical. Use it to:

  • Close the reward UI.
  • Continue the user flow.
  • Mark reward as successfully completed in your backend.

This is the only event that should trigger reward delivery.

No ad available (Rare Case)

In rare cases you will encounter a situation where no ad is available. Ensure that even in these cases the rewarded ad container should only be made visible after receiving the video_ad_ready event, which indicates that an ad is ready to play.

However, in rare cases (for example, an ad expiring between readiness and playback), the SDK may still emit a video_no_ready_ads error.

rewardedAdInstance.addEventListener('error', (e) => {
if (e.info === 'video_no_ready_ads') {
containerElement.style.visibility = 'hidden';
closeRewardWindow();
}
});

In this case your app should:

  • Close the reward UI.
  • Not grant the reward.

Once the container is hidden again, you app should continue fetching ads in the background.

Ad Skipped (Rare Case)

Rewarded ads are set to non-skippable by Overwolf. It is recommended to track this event, and act accordingly in cases where some programmatic buyers may not respect these settings and still include a skip button on the ad itself.

rewardedAdInstance.addEventListener('video_ad_skipped', () => {
containerElement.style.visibility = 'hidden';
closeRewardWindow();
});

In these cases your app should:

  • Close the reward UI.
  • Not grant the reward.

Once the container is hidden again, your app should continue fetching ads in the background.

Ad didn't start

In rare cases where playback didn't start for any reason, use the timeout even. When this event fires, close the reward UI and set the container visibility back to the default hidden state.

rewardedAdInstance.addEventListener('video_no_impression_timeout', () => {
containerElement.style.visibility = 'hidden';
closeRewardWindow();
});

Once the container is hidden again, your app should continue fetching ads in the background.

Reward completion rules

A reward is considered successfully completed only if the complete event fires.

A reward must not be granted if:

  • The video_ad_skipped event is fired.
  • The video_no_ready_ads event is fired.
  • The video_no_impression_timeout event is fired.

For higher-value rewards (e.g., premium unlocks, meaningful currency grants), backend validation is strongly recommended.

Client-side events can be:

  • Manipulated in modified environments.
  • Interrupted mid-flow.
  • Triggered without backend awareness.

Relying solely on client logic increases fraud risk for high-value rewards.

In your app it is recommended (optional) to implement additional safeguards such as:

  • Enforcing daily / session reward caps server-side.
  • Logging acceptance, impression, and completion funnel.
  • Rate-limit repeated reward attempts.
  • Flag abnormal completion frequency patterns.

Key considerations should include:

  • The complete event signals successful ad playback.
  • You app's backend should be the final authority on reward eligibility and delivery for high-value implementations.

Flow summary

Shutdown (Optional)

Call shutdown() is optional and not always needed.

Call shutdown() only if you want to permanently disable rewarded ads for the remainder of the user session (e.g.,when the user has reached the maximum reward limit based on your internal logic).

rewardedAdInstance.shutdown();

Once shutdown is called, Rewarded ads stop being requested and playing. The reward flow cannot be used again in this session until a you initialize a new owAd.