> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rewarded Ads

> Learn how to implement rewarded ads in your React Native app.

## Overview

Rewarded ads are full-screen video ads that provide users with in-game currency, extra lives, hints, or other rewards when they watch the video to completion.

### Key Features

* Full-screen video ads
* Rewards only provided when user fully watches the ad
* User chooses to watch the ad (e.g., "Watch video to get a life" button)
* Configurable reward type and amount

<Note>
  Use test unit IDs in development environments.
</Note>

***

## Implementation Methods

Rewarded ads can be implemented in two ways:

1. **Class Method** - Using `AdropRewardedAd` class directly
2. **Hook Method** - Using `useAdropRewardedAd` Hook (recommended)

***

## Hook Method Implementation (Recommended)

Use React Hooks for a more concise and React-like implementation.

### Basic Example

```tsx theme={null}
import React, { useCallback } from 'react';
import { Button, View, Text, StyleSheet } from 'react-native';
import { useAdropRewardedAd } from 'adrop-ads-react-native';

const RewardedAdScreen = () => {
  const unitId = 'YOUR_UNIT_ID'; // or test unit ID

  const {
    load,
    show,
    reset,
    isLoaded,
    isOpened,
    isClosed,
    isEarnRewarded,
    reward,
    errorCode,
    isReady
  } = useAdropRewardedAd(unitId);

  // Load ad on component mount
  React.useEffect(() => {
    if (isReady) {
      load();
    }
  }, [isReady, load]);

  // Load next ad after ad closes
  React.useEffect(() => {
    if (isClosed) {
      console.log('Ad closed');
      // Preload next ad
      reset();
      load();
    }
  }, [isClosed, reset, load]);

  // Handle reward
  React.useEffect(() => {
    if (isEarnRewarded && reward) {
      console.log(`Reward earned - Type: ${reward.type}, Amount: ${reward.amount}`);
      grantReward(reward.type, reward.amount);
    }
  }, [isEarnRewarded, reward]);

  const handleShowAd = useCallback(() => {
    if (isLoaded) {
      show();
    } else {
      console.log('Ad not loaded yet');
    }
  }, [isLoaded, show]);

  const grantReward = (type: number, amount: number) => {
    // Grant reward to user
    console.log(`Granting reward: type=${type}, amount=${amount}`);
    // Implement actual reward logic
  };

  return (
    <View style={styles.container}>
      <Button
        title="Load Ad"
        onPress={load}
        disabled={!isReady}
      />
      <Button
        title="Watch Ad"
        onPress={handleShowAd}
        disabled={!isLoaded}
      />
      {errorCode && (
        <Text style={styles.error}>Error: {errorCode}</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
  },
  error: {
    color: 'red',
  },
});

export default RewardedAdScreen;
```

### useAdropRewardedAd Hook

The Hook automatically manages ad state.

#### Parameters

<ParamField path="unitId" type="string | null">
  Ad unit ID from the Ad Control console. Pass `null` to skip ad instance creation.
</ParamField>

#### Return Values

<ParamField path="load" type="() => void">
  Requests an ad.
</ParamField>

<ParamField path="show" type="() => void">
  Shows the ad.
</ParamField>

<ParamField path="reset" type="() => void">
  Resets ad state and creates a new ad instance.
</ParamField>

<ParamField path="isLoaded" type="boolean">
  Whether the ad is loaded and ready to show.
</ParamField>

<ParamField path="isOpened" type="boolean">
  Whether the ad is displayed on screen.
</ParamField>

<ParamField path="isClosed" type="boolean">
  Whether the ad has been closed.
</ParamField>

<ParamField path="isEarnRewarded" type="boolean">
  Whether the user has earned a reward.
</ParamField>

<ParamField path="reward" type="{ type: number, amount: number } | undefined">
  Reward information (type and amount).
</ParamField>

<ParamField path="errorCode" type="string | undefined">
  Error code (only present on error).
</ParamField>

<ParamField path="isReady" type="boolean">
  Whether the ad instance is ready for use.
</ParamField>

<ParamField path="isClicked" type="boolean">
  Whether the ad has been clicked.
</ParamField>

<ParamField path="isBackPressed" type="boolean">
  Whether the back button was pressed while the ad is displayed. **Android only.**
</ParamField>

<ParamField path="browserTarget" type="BrowserTarget | undefined">
  Browser target setting of the loaded ad (`BrowserTarget.EXTERNAL` or `BrowserTarget.INTERNAL`).
</ParamField>

***

## Class Method Implementation

You can implement ads using the `AdropRewardedAd` class directly.

### Basic Example

```tsx theme={null}
import React, { useEffect, useState, useCallback } from 'react';
import { Button, View, Text, StyleSheet } from 'react-native';
import { AdropRewardedAd, AdropListener } from 'adrop-ads-react-native';

const RewardedAdScreen = () => {
  const [rewardedAd, setRewardedAd] = useState<AdropRewardedAd | null>(null);
  const [isLoaded, setIsLoaded] = useState(false);

  useEffect(() => {
    // 1. Create AdropRewardedAd instance
    const ad = new AdropRewardedAd('YOUR_UNIT_ID');

    // 2. Set up listener
    const listener: AdropListener = {
      onAdReceived: (ad) => {
        console.log('Ad received:', ad.unitId);
        setIsLoaded(true);
      },
      onAdFailedToReceive: (ad, errorCode) => {
        console.log('Ad failed to receive:', errorCode);
        setIsLoaded(false);
      },
      onAdDidPresentFullScreen: (ad) => {
        console.log('Ad presented:', ad.unitId);
      },
      onAdDidDismissFullScreen: (ad) => {
        console.log('Ad dismissed:', ad.unitId);
        setIsLoaded(false);
        // Preload next ad
        ad.load();
      },
      onAdEarnRewardHandler: (ad, type, amount) => {
        console.log(`Reward earned - Type: ${type}, Amount: ${amount}`);
        grantReward(type, amount);
      },
      onAdClicked: (ad) => {
        console.log('Ad clicked:', ad.unitId);
      },
      onAdImpression: (ad) => {
        console.log('Ad impression:', ad.unitId);
      },
      onAdFailedToShowFullScreen: (ad, errorCode) => {
        console.log('Ad failed to show:', errorCode);
      },
    };

    ad.listener = listener;
    setRewardedAd(ad);

    // 3. Load ad
    ad.load();

    // Cleanup on unmount
    return () => {
      ad.destroy();
    };
  }, []);

  const handleShowAd = useCallback(() => {
    if (rewardedAd && isLoaded) {
      rewardedAd.show();
    } else {
      console.log('Ad not loaded yet');
    }
  }, [rewardedAd, isLoaded]);

  const grantReward = (type: number, amount: number) => {
    // Grant reward to user
    console.log(`Granting reward: type=${type}, amount=${amount}`);
    // Implement actual reward logic
  };

  return (
    <View style={styles.container}>
      <Button
        title="Load Ad"
        onPress={() => rewardedAd?.load()}
      />
      <Button
        title="Watch Ad"
        onPress={handleShowAd}
        disabled={!isLoaded}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
  },
});

export default RewardedAdScreen;
```

### AdropRewardedAd Class

#### Constructor

```typescript theme={null}
new AdropRewardedAd(unitId: string)
```

<ParamField path="unitId" type="string">
  Ad unit ID from the Ad Control console.
</ParamField>

#### Properties

<ParamField path="unitId" type="string">
  Ad unit ID (read-only).
</ParamField>

<ParamField path="isLoaded" type="boolean">
  Whether the ad is loaded and ready to show (read-only).
</ParamField>

<ParamField path="creativeId" type="string">
  Creative ID of the loaded ad (read-only).
</ParamField>

<ParamField path="txId" type="string">
  Transaction ID (read-only).
</ParamField>

<ParamField path="campaignId" type="string">
  Campaign ID of the loaded ad (read-only).
</ParamField>

<ParamField path="destinationURL" type="string">
  Destination URL of the loaded ad (read-only).
</ParamField>

<ParamField path="browserTarget" type="BrowserTarget">
  Browser target setting of the loaded ad (`BrowserTarget.EXTERNAL` or `BrowserTarget.INTERNAL`) (read-only).
</ParamField>

<ParamField path="listener" type="AdropListener | undefined">
  Listener for receiving ad events.
</ParamField>

#### Methods

<ParamField path="load()" type="void">
  Requests an ad. Results are delivered via `onAdReceived` or `onAdFailedToReceive` listener callbacks.
</ParamField>

<ParamField path="show()" type="void">
  Shows the ad.
</ParamField>

<ParamField path="destroy()" type="void">
  Releases ad resources. Should be called on component unmount.
</ParamField>

***

## AdropListener Interface

All callbacks are optional. Set only the ones you need.

### Callbacks

<ParamField path="onAdReceived(ad: AdropAd)" type="void">
  Called when ad is received successfully. You can call `show()` from this point.
</ParamField>

<ParamField path="onAdFailedToReceive(ad: AdropAd, errorCode?: any)" type="void">
  Called when ad fails to receive. Check error code for failure reason.
</ParamField>

<ParamField path="onAdImpression(ad: AdropAd)" type="void">
  Called when ad impression is recorded.
</ParamField>

<ParamField path="onAdClicked(ad: AdropAd)" type="void">
  Called when user clicks the ad.
</ParamField>

<ParamField path="onAdWillPresentFullScreen(ad: AdropAd)" type="void">
  Called just before the ad screen is presented.
</ParamField>

<ParamField path="onAdDidPresentFullScreen(ad: AdropAd)" type="void">
  Called after the ad screen is fully presented.
</ParamField>

<ParamField path="onAdWillDismissFullScreen(ad: AdropAd)" type="void">
  Called just before the ad screen is dismissed.
</ParamField>

<ParamField path="onAdDidDismissFullScreen(ad: AdropAd)" type="void">
  Called after the ad screen is fully dismissed. Good time to preload next ad.
</ParamField>

<ParamField path="onAdFailedToShowFullScreen(ad: AdropAd, errorCode?: any)" type="void">
  Called when ad fails to show. Check error code for failure reason.
</ParamField>

<ParamField path="onAdBackButtonPressed(ad: AdropAd)" type="void">
  Called when the user presses the back button while the ad is displayed. **Android only.**
</ParamField>

### Reward-specific Callback

<ParamField path="onAdEarnRewardHandler(ad: AdropAd, type: number, amount: number)" type="void">
  Called when user has watched the ad to completion and earned a reward.

  * `type`: Reward type set in the Ad Control console (integer)
  * `amount`: Reward amount set in the Ad Control console (integer)
</ParamField>

***

## Reward Handling

### Hook Method Reward Handling

```tsx theme={null}
const RewardedAdScreen = () => {
  const { isEarnRewarded, reward } = useAdropRewardedAd('YOUR_UNIT_ID');

  useEffect(() => {
    if (isEarnRewarded && reward) {
      // Process reward
      console.log(`Reward earned - Type: ${reward.type}, Amount: ${reward.amount}`);
      grantReward(reward.type, reward.amount);
    }
  }, [isEarnRewarded, reward]);

  const grantReward = (type: number, amount: number) => {
    // Grant reward to user
    // e.g., add coins, restore life, etc.
  };

  // ...
};
```

### Class Method Reward Handling

```tsx theme={null}
const listener: AdropListener = {
  onAdEarnRewardHandler: (ad, type, amount) => {
    console.log(`Reward earned - Type: ${type}, Amount: ${amount}`);
    grantReward(type, amount);
  },
  // other callbacks...
};

const grantReward = (type: number, amount: number) => {
  // Grant reward to user
  // e.g., add coins, restore life, etc.
};
```

## Server-Side Verification

You can verify reward grants on your server to prevent fraud. Use `setServerSideVerificationOptions()` to pass user and custom data that will be included in server-side verification callbacks.

<Note>
  To receive SSV callbacks on your server, register a callback URL in the console: **\[Management] > \[Integrations] > Reward Ad SSV**. The `userId` and `customData` set here are included in the encrypted payload sent to that URL. See the [Reward Ad SSV guide](/integrations/ssv) for payload decryption and setup.
</Note>

### Setup

```tsx theme={null}
import { AdropRewardedAd } from 'adrop-ads-react-native'

const rewardedAd = new AdropRewardedAd('YOUR_UNIT_ID')

// Set server-side verification options before loading the ad
rewardedAd.setServerSideVerificationOptions({
  userId: 'user_12345',
  customData: 'extra_info',
})

rewardedAd.listener = {
  onAdReceived: (ad) => {
    ad.show()
  },
  onAdEarnRewardHandler: (ad, type, amount) => {
    // Client-side callback (optional)
    // Server-side verification callback will also be sent
    console.log(`Reward earned: type=${type}, amount=${amount}`)
  },
}

rewardedAd.load()
```

### ServerSideVerificationOptions

```typescript theme={null}
type ServerSideVerificationOptions = {
  userId?: string
  customData?: string
}
```

**Properties:**

* `userId` (string, optional): User identifier sent in the server callback
* `customData` (string, optional): Custom data sent in the server callback

<Note>
  `setServerSideVerificationOptions()` should be called before `load()`. The options are sent to the server when the user earns a reward.
</Note>

***

## Testing

### Test Unit IDs

Always use test unit IDs during development. Testing with real unit IDs may result in invalid traffic and account suspension.

```tsx theme={null}
// Hook method
const unitId = __DEV__ ? 'PUBLIC_TEST_UNIT_ID_REWARDED' : 'YOUR_PRODUCTION_UNIT_ID';
const rewardedAd = useAdropRewardedAd(unitId);

// Class method
const unitId = __DEV__ ? 'PUBLIC_TEST_UNIT_ID_REWARDED' : 'YOUR_PRODUCTION_UNIT_ID';
const ad = new AdropRewardedAd(unitId);
```

***

## Error Handling

### Hook Method Error Handling

```tsx theme={null}
const RewardedAdScreen = () => {
  const { load, errorCode, reset } = useAdropRewardedAd('YOUR_UNIT_ID');

  useEffect(() => {
    if (errorCode) {
      console.log('Ad error:', errorCode);
      // Handle by error type
      if (errorCode === AdropErrorCode.network) {
        // Network error: retry
        setTimeout(() => {
          reset();
          load();
        }, 3000);
      }
    }
  }, [errorCode, reset, load]);

  // ...
};
```

### Class Method Error Handling

```tsx theme={null}
const listener: AdropListener = {
  onAdFailedToReceive: (ad, errorCode) => {
    console.log('Ad receive failed:', errorCode);
    if (errorCode === AdropErrorCode.network) {
      // Network error: retry after 3 seconds
      setTimeout(() => {
        ad.load();
      }, 3000);
    }
  },
  onAdFailedToShowFullScreen: (ad, errorCode) => {
    console.log('Ad show failed:', errorCode);
    Alert.alert('Notice', 'Unable to show ad. Please try again later.');
  },
  // other callbacks...
};
```

***

## Best Practices

### 1. Preload Ads

Preload ads for better user experience.

```tsx theme={null}
// Hook method
const RewardedAdScreen = () => {
  const { load, isClosed, reset, isReady } = useAdropRewardedAd('YOUR_UNIT_ID');

  // Load ad on component mount
  useEffect(() => {
    if (isReady) {
      load();
    }
  }, [isReady, load]);

  // Preload next ad after ad closes
  useEffect(() => {
    if (isClosed) {
      reset();
      load();
    }
  }, [isClosed, reset, load]);

  // ...
};
```

### 2. Check Ad Ready State

Check if ad is loaded and update UI accordingly.

```tsx theme={null}
const RewardedAdScreen = () => {
  const { isLoaded, show } = useAdropRewardedAd('YOUR_UNIT_ID');

  return (
    <View>
      <Button
        title={isLoaded ? "Watch video to get a life" : "Loading ad..."}
        onPress={show}
        disabled={!isLoaded}
      />
    </View>
  );
};
```

### 3. Memory Management

Clean up ad resources on component unmount.

```tsx theme={null}
// Hook method automatically cleans up
const { ... } = useAdropRewardedAd('YOUR_UNIT_ID');

// Class method requires manual cleanup
useEffect(() => {
  const ad = new AdropRewardedAd('YOUR_UNIT_ID');
  // ...

  return () => {
    ad.destroy();
  };
}, []);
```

### 4. Error Handling

Improve user experience with proper error handling.

```tsx theme={null}
const RewardedAdScreen = () => {
  const { errorCode, reset, load } = useAdropRewardedAd('YOUR_UNIT_ID');

  useEffect(() => {
    if (errorCode) {
      // Notify user of error
      Alert.alert('Notice', 'Unable to load ad.');

      // Retry on network error
      if (errorCode === AdropErrorCode.network) {
        setTimeout(() => {
          reset();
          load();
        }, 3000);
      }
    }
  }, [errorCode, reset, load]);

  // ...
};
```

***

## Complete Example

### Hook Method Complete Example

```tsx theme={null}
import React, { useEffect, useCallback } from 'react';
import {
  Button,
  View,
  Text,
  StyleSheet,
  Alert,
  ActivityIndicator
} from 'react-native';
import { useAdropRewardedAd } from 'adrop-ads-react-native';

const RewardedAdScreen = () => {
  const unitId = __DEV__ ? 'PUBLIC_TEST_UNIT_ID_REWARDED' : 'YOUR_PRODUCTION_UNIT_ID';

  const {
    load,
    show,
    reset,
    isLoaded,
    isOpened,
    isClosed,
    isEarnRewarded,
    reward,
    errorCode,
    isReady
  } = useAdropRewardedAd(unitId);

  // Load ad on component mount
  useEffect(() => {
    if (isReady) {
      console.log('Ad instance ready, starting ad load');
      load();
    }
  }, [isReady, load]);

  // When ad is displayed
  useEffect(() => {
    if (isOpened) {
      console.log('Ad is displayed');
      // Pause background music, etc.
    }
  }, [isOpened]);

  // Preload next ad after ad closes
  useEffect(() => {
    if (isClosed) {
      console.log('Ad closed');
      // Resume background music, etc.

      // Preload next ad
      reset();
      load();
    }
  }, [isClosed, reset, load]);

  // Handle reward
  useEffect(() => {
    if (isEarnRewarded && reward) {
      console.log(`Reward earned - Type: ${reward.type}, Amount: ${reward.amount}`);
      grantReward(reward.type, reward.amount);
    }
  }, [isEarnRewarded, reward]);

  // Handle errors
  useEffect(() => {
    if (errorCode) {
      console.log('Ad error:', errorCode);

      // Retry on network error
      if (errorCode === AdropErrorCode.network) {
        Alert.alert(
          'Network Error',
          'Unable to load ad. Retrying in 3 seconds.',
          [{ text: 'OK' }]
        );

        setTimeout(() => {
          reset();
          load();
        }, 3000);
      } else {
        Alert.alert('Error', `Ad error: ${errorCode}`);
      }
    }
  }, [errorCode, reset, load]);

  const handleShowAd = useCallback(() => {
    if (isLoaded) {
      show();
    } else {
      Alert.alert('Notice', 'Ad not loaded yet.');
    }
  }, [isLoaded, show]);

  const grantReward = (type: number, amount: number) => {
    // Grant reward to user
    Alert.alert(
      'Reward Earned!',
      `Type: ${type}, Amount: ${amount}`,
      [{ text: 'OK' }]
    );

    // Implement actual reward logic
    // e.g., add coins, restore life, etc.
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Rewarded Ad</Text>

      {!isReady && (
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#0000ff" />
          <Text style={styles.loadingText}>Initializing ad...</Text>
        </View>
      )}

      <View style={styles.buttonContainer}>
        <Button
          title="Load Ad"
          onPress={load}
          disabled={!isReady}
        />
      </View>

      <View style={styles.buttonContainer}>
        <Button
          title={isLoaded ? "Watch video to get a life" : "Loading ad..."}
          onPress={handleShowAd}
          disabled={!isLoaded}
        />
      </View>

      <View style={styles.statusContainer}>
        <Text style={styles.statusText}>
          Status: {isLoaded ? 'Ready' : 'Loading'}
        </Text>
        {errorCode && (
          <Text style={styles.errorText}>Error: {errorCode}</Text>
        )}
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 30,
  },
  loadingContainer: {
    alignItems: 'center',
    marginBottom: 20,
  },
  loadingText: {
    marginTop: 10,
    color: '#666',
  },
  buttonContainer: {
    width: '100%',
    marginVertical: 8,
  },
  statusContainer: {
    marginTop: 30,
    alignItems: 'center',
  },
  statusText: {
    fontSize: 16,
    color: '#333',
  },
  errorText: {
    fontSize: 14,
    color: 'red',
    marginTop: 8,
  },
});

export default RewardedAdScreen;
```

***

## Backfill Ads

<Info>To use backfill ads, you must have the backfill dependency added to your native platforms (Android/iOS).</Info>

When backfill ads are enabled, the SDK automatically falls back to backfill ads when no direct ad is available. You can handle backfill-specific error codes in the listener.

```tsx theme={null}
rewardedAd.listener = {
  onAdReceived: (ad) => {
    console.log('Ad loaded:', ad.creativeId)
  },
  onAdFailedToReceive: (ad, errorCode) => {
    switch (errorCode) {
      case AdropErrorCode.adNoFill:
        console.log('No direct ad available, requesting backfill...')
        break
      case AdropErrorCode.backfillNoFill:
        console.log('No backfill ad available either')
        break
      default:
        console.log('Ad load failed:', errorCode)
    }
  },
}
```

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Interstitial Ads" href="/sdk/react-native/interstitial" icon="rectangle-ad">
    Interstitial ad implementation guide
  </Card>

  <Card title="Popup Ads" href="/sdk/react-native/popup" icon="window-maximize">
    Popup ad implementation guide
  </Card>

  <Card title="Native Ads" href="/sdk/react-native/native" icon="image">
    Native ad implementation guide
  </Card>

  <Card title="Error Codes" href="/sdk/react-native/reference#error-codes" icon="triangle-exclamation">
    Error code reference
  </Card>
</CardGroup>
