> ## 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.

# Popup Ads

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

## Overview

Popup ads are an ad format that appears on screen at specific moments. They can be displayed at app launch, content load completion, specific events, etc. Users can dismiss by tapping the close button or selecting "Don't show today".

### Features

* Popup format displayed at center or bottom of screen
* Image and video ad support
* Close, dim (background) click, and "Don't show today" options
* Customizable background color, text color, etc.
* Non-intrusive yet effective ad experience

<Note>
  Use test unit IDs in development. See the [Test Unit IDs](#test-unit-ids) section.
</Note>

***

## Implementation Steps

Popup ads are implemented in 4 steps:

1. **Initialize** - Create AdropPopupAd instance
2. **Set Listener** - Set listener for receiving ad events
3. **Load Ad** - Request and receive ad
4. **Show Ad** - Display ad on screen

***

## Basic Implementation

### AdropPopupAd Class

`AdropPopupAd` is the main class for managing popup ads.

```typescript theme={null}
import { AdropPopupAd, type AdropPopupAdColors } from 'adrop-ads-react-native';

const popupAd = new AdropPopupAd(
  unitId: string,
  colors?: AdropPopupAdColors,
  useCustomClick?: boolean
);
```

#### Constructor Parameters

<ParamField path="unitId" type="string" required>
  Popup ad unit ID. Use the unit ID created in the Ad Control console.
</ParamField>

<ParamField path="colors" type="AdropPopupAdColors">
  Options for customizing popup ad colors.

  * `closeTextColor`: Close button text color
  * `hideForTodayTextColor`: "Don't show today" text color
  * `backgroundColor`: Popup background (dim) color
</ParamField>

<ParamField path="useCustomClick" type="boolean" default="false">
  Whether to use custom click handling. When set to `true`, only the `onAdClicked` callback is called instead of opening the default browser on ad click.
</ParamField>

### Basic Usage

```typescript theme={null}
import React, { useEffect, useState, useMemo } from 'react';
import { Button, View } from 'react-native';
import { AdropPopupAd, type AdropListener } from 'adrop-ads-react-native';

const App: React.FC = () => {
  const [popupAd, setPopupAd] = useState<AdropPopupAd>();
  const [isLoaded, setIsLoaded] = useState(false);

  const listener: AdropListener = useMemo(() => ({
    onAdReceived: (ad: AdropPopupAd) => {
      console.log('Popup ad received');
      setIsLoaded(true);
    },
    onAdFailedToReceive: (_: AdropPopupAd, errorCode: any) => {
      console.log('Popup ad failed to receive:', errorCode);
    },
    onAdClicked: (ad: AdropPopupAd) => {
      console.log('Popup ad clicked');
      // Close popup on click
      ad.close();
    },
  }), []);

  useEffect(() => {
    // 1. Create popup ad
    const ad = new AdropPopupAd('YOUR_POPUP_UNIT_ID');
    ad.listener = listener;
    setPopupAd(ad);

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

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

  // 3. Show ad
  const showAd = () => {
    if (popupAd && isLoaded) {
      popupAd.show();
    }
  };

  return (
    <View>
      <Button
        title="Show Popup Ad"
        onPress={showAd}
        disabled={!isLoaded}
      />
    </View>
  );
};

export default App;
```

***

## AdropListener Interface

Listener interface for receiving popup ad events.

### Recommended Callbacks

<ParamField path="onAdReceived" type="(ad: AdropPopupAd) => void">
  Called on successful ad reception. You can call `show()` at this point.
</ParamField>

<ParamField path="onAdFailedToReceive" type="(ad: AdropPopupAd, errorCode?: any) => void">
  Called on ad reception failure. Check error code for failure reason.
</ParamField>

### Optional Callbacks

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

<ParamField path="onAdClicked" type="(ad: AdropPopupAd) => void">
  Called when user clicks the ad. You can call `ad.close()` in this callback to dismiss the popup.
</ParamField>

<ParamField path="onAdWillPresentFullScreen" type="(ad: AdropPopupAd) => void">
  Called just before popup ad is displayed.
</ParamField>

<ParamField path="onAdDidPresentFullScreen" type="(ad: AdropPopupAd) => void">
  Called immediately after popup ad is displayed.
</ParamField>

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

<ParamField path="onAdDidDismissFullScreen" type="(ad: AdropPopupAd) => void">
  Called immediately after popup ad is dismissed. Good time to preload next ad.
</ParamField>

<ParamField path="onAdFailedToShowFullScreen" type="(ad: AdropPopupAd, errorCode?: any) => void">
  Called on ad display failure. Check error code for failure reason.
</ParamField>

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

<ParamField path="onAdVideoStart" type="(ad: AdropPopupAd) => void">
  Called when a video ad starts playing.
</ParamField>

<ParamField path="onAdVideoEnd" type="(ad: AdropPopupAd) => void">
  Called when a video ad finishes playing.
</ParamField>

### Listener Implementation Example

```typescript theme={null}
const listener: AdropListener = useMemo(() => ({
  // Ad received successfully
  onAdReceived: (ad: AdropPopupAd) => {
    console.log('Popup ad received');
    console.log('Creative ID:', ad.creativeId);
    console.log('Campaign ID:', ad.campaignId);
    // Auto-show when ad is ready
    ad.show();
  },

  // Ad reception failed
  onAdFailedToReceive: (ad: AdropPopupAd, errorCode?: any) => {
    console.log('Popup ad failed to receive:', errorCode);
  },

  // Ad impression
  onAdImpression: (ad: AdropPopupAd) => {
    console.log('Popup ad impression');
    console.log('TX ID:', ad.txId);
    console.log('Destination URL:', ad.destinationURL);
  },

  // Ad clicked
  onAdClicked: (ad: AdropPopupAd) => {
    console.log('Popup ad clicked:', ad.destinationURL);
    // Close popup on click
    ad.close();
  },

  // Just before popup is displayed
  onAdWillPresentFullScreen: (ad: AdropPopupAd) => {
    console.log('Popup ad about to display');
  },

  // Popup displayed
  onAdDidPresentFullScreen: (ad: AdropPopupAd) => {
    console.log('Popup ad displayed');
  },

  // Just before popup is dismissed
  onAdWillDismissFullScreen: (ad: AdropPopupAd) => {
    console.log('Popup ad about to dismiss');
  },

  // Popup dismissed
  onAdDidDismissFullScreen: (ad: AdropPopupAd) => {
    console.log('Popup ad dismissed');
    // Preload next ad
    loadNextAd();
  },

  // Popup display failed
  onAdFailedToShowFullScreen: (ad: AdropPopupAd, errorCode?: any) => {
    console.log('Popup ad failed to show:', errorCode);
  },

  // Video ad started
  onAdVideoStart: (ad: AdropPopupAd) => {
    console.log('Video ad started playing:', ad.creativeId);
  },

  // Video ad ended
  onAdVideoEnd: (ad: AdropPopupAd) => {
    console.log('Video ad finished playing:', ad.creativeId);
  },
}), []);
```

***

## Methods

### load()

Requests and loads an ad.

```typescript theme={null}
popupAd.load();
```

### show()

Displays the loaded ad. Can only be called after `onAdReceived` callback is fired.

```typescript theme={null}
popupAd.show();
```

<Warning>
  Only call `show()` when the ad is loaded (`isLoaded === true`).
</Warning>

### close()

Closes the currently displayed popup ad. Primarily used in the `onAdClicked` callback.

```typescript theme={null}
popupAd.close();
```

### destroy()

Cleans up the ad instance and releases resources. Must be called on component unmount.

```typescript theme={null}
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

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

***

## Ad Properties

The following properties are available on the popup ad object:

<ParamField path="unitId" type="string">
  Ad unit ID
</ParamField>

<ParamField path="isLoaded" type="boolean">
  Whether the ad is loaded
</ParamField>

<ParamField path="creativeId" type="string">
  Creative ID of the currently displayed ad
</ParamField>

<ParamField path="destinationURL" type="string">
  URL to navigate to on ad click
</ParamField>

<ParamField path="txId" type="string">
  Transaction ID (for ad impression tracking)
</ParamField>

<ParamField path="campaignId" type="string">
  Campaign ID
</ParamField>

<ParamField path="browserTarget" type="BrowserTarget">
  Browser target for ad click. `BrowserTarget.EXTERNAL` (0) opens the system browser, `BrowserTarget.INTERNAL` (1) opens an in-app browser.
</ParamField>

***

## Customization

### Color Settings

Use `AdropPopupAdColors` type to customize popup ad colors.

```typescript theme={null}
import { AdropPopupAd, type AdropPopupAdColors } from 'adrop-ads-react-native';

// Define color options
const customColors: AdropPopupAdColors = {
  closeTextColor: '#FFFFFF',                    // Close button color
  hideForTodayTextColor: '#456789',             // "Don't show today" color
  backgroundColor: 'rgba(53, 255, 63, 0.3)',    // Background (dim) color
};

// Apply colors when creating popup ad
const popupAd = new AdropPopupAd(
  'YOUR_POPUP_UNIT_ID',
  customColors
);
```

#### AdropPopupAdColors Type

<ParamField path="closeTextColor" type="string">
  Close button text color. Supports HEX color codes or RGBA format.
</ParamField>

<ParamField path="hideForTodayTextColor" type="string">
  "Don't show today" text color. Supports HEX color codes or RGBA format.
</ParamField>

<ParamField path="backgroundColor" type="string">
  Popup background (dim) color. Supports HEX color codes or RGBA format. Transparency can be adjusted.
</ParamField>

### Custom Click Handling

To use custom handling instead of opening the default browser on ad click, use the `useCustomClick` parameter.

```typescript theme={null}
const listener: AdropListener = useMemo(() => ({
  onAdReceived: (ad: AdropPopupAd) => {
    ad.show();
  },
  onAdFailedToReceive: (_: AdropPopupAd, errorCode: any) => {
    console.log('Ad failed to receive:', errorCode);
  },
  onAdClicked: (ad: AdropPopupAd) => {
    // Custom click handling
    console.log('Ad clicked:', ad.destinationURL);

    // Handle URL as desired
    // e.g., Open in in-app browser
    openInAppBrowser(ad.destinationURL);

    // Close popup
    ad.close();
  },
}), []);

// Set useCustomClick to true
const popupAd = new AdropPopupAd(
  'YOUR_POPUP_UNIT_ID',
  undefined,  // colors
  true        // useCustomClick
);
popupAd.listener = listener;
```

***

## Test Unit IDs

Use the following test unit IDs during development and testing.

| Ad Type                   | Test Unit ID                                  |
| ------------------------- | --------------------------------------------- |
| Popup (Bottom Image)      | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM`            |
| Popup (Center Image)      | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER`            |
| Popup Video (Bottom 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_16_9` |
| Popup Video (Bottom 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM_VIDEO_9_16` |
| Popup Video (Center 16:9) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_16_9` |
| Popup Video (Center 9:16) | `PUBLIC_TEST_UNIT_ID_POPUP_CENTER_VIDEO_9_16` |

### Test Ad Usage Example

```typescript theme={null}
// Separate development/production environments
const POPUP_UNIT_ID = __DEV__
  ? 'PUBLIC_TEST_UNIT_ID_POPUP_BOTTOM'  // Test unit ID
  : 'YOUR_PRODUCTION_UNIT_ID';           // Production unit ID

const popupAd = new AdropPopupAd(POPUP_UNIT_ID);
```

<Warning>
  Make sure to use the actual unit ID created in the Ad Control console for production releases.
</Warning>

***

## Error Handling

Handle errors appropriately by checking error codes on ad load or display failure.

```typescript theme={null}
const listener: AdropListener = {
  onAdFailedToReceive: (ad: AdropPopupAd, errorCode?: any) => {
    console.error('Ad reception failed:', errorCode);

    switch (errorCode) {
      case AdropErrorCode.network:
        // Handle network error
        console.log('Please check your network connection');
        break;
      case AdropErrorCode.adNoFill:
        // Insufficient ad inventory
        console.log('No ads available to display');
        break;
      case AdropErrorCode.invalidUnit:
        // Invalid unit ID
        console.log('Please check your ad unit ID');
        break;
      default:
        console.log('Unable to load ad');
    }
  },

  onAdFailedToShowFullScreen: (ad: AdropPopupAd, errorCode?: any) => {
    console.error('Ad display failed:', errorCode);

    // Retry later
    setTimeout(() => {
      ad.load();
    }, 30000); // Retry after 30 seconds
  },
};
```

***

## Best Practices

### 1. Appropriate Display Timing

Popup ads are most effective at these times:

```typescript theme={null}
// Good: App launch
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  ad.listener = {
    onAdReceived: (ad) => ad.show(),
    onAdFailedToReceive: (_, error) => console.log(error),
  };
  ad.load();

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

// Good: Content load completion
const onContentLoaded = () => {
  if (shouldShowPopupAd()) {
    popupAd?.show();
  }
};

// Good: Specific event completion
const onAchievementUnlocked = () => {
  popupAd?.show();
};

// Bad: While user is working
const onUserTyping = () => {
  popupAd?.show(); // Harms user experience
};
```

### 2. Frequency Limiting

Don't show popup ads too frequently.

```typescript theme={null}
import AsyncStorage from '@react-native-async-storage/async-storage';

const LAST_SHOWN_KEY = 'popup_ad_last_shown';
const MINIMUM_INTERVAL = 3600000; // 1 hour (milliseconds)

// Check if ad can be shown
const canShowAd = async (): Promise<boolean> => {
  try {
    const lastShown = await AsyncStorage.getItem(LAST_SHOWN_KEY);
    if (!lastShown) return true;

    const currentTime = Date.now();
    const lastShownTime = parseInt(lastShown, 10);

    return currentTime - lastShownTime >= MINIMUM_INTERVAL;
  } catch (error) {
    return true;
  }
};

// Record ad shown
const recordAdShown = async () => {
  try {
    await AsyncStorage.setItem(LAST_SHOWN_KEY, Date.now().toString());
  } catch (error) {
    console.error('Error recording ad shown:', error);
  }
};

// Usage
const showAdIfAllowed = async () => {
  if (await canShowAd()) {
    popupAd?.show();
    await recordAdShown();
  }
};
```

### 3. Preload Ads

Preload ads for better user experience.

```typescript theme={null}
const [isAdReady, setIsAdReady] = useState(false);

useEffect(() => {
  // Preload at app launch
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  ad.listener = {
    onAdReceived: () => setIsAdReady(true),
    onAdFailedToReceive: (_, error) => console.log(error),
  };
  ad.load();

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

// Show immediately at desired time
const showPopupNow = () => {
  if (isAdReady) {
    popupAd?.show();
  }
};
```

### 4. Memory Management

Always clean up ads on component unmount.

```typescript theme={null}
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

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

### 5. Close Popup on Click

Close popup on ad click for better user experience.

```typescript theme={null}
const listener: AdropListener = {
  onAdClicked: (ad: AdropPopupAd) => {
    console.log('Ad clicked:', ad.destinationURL);
    // Auto-close popup on click
    ad.close();
  },
};
```

***

## Troubleshooting

### Ad Not Displaying

<AccordionGroup>
  <Accordion title="onAdReceived not called">
    * Verify SDK is initialized
    * Check if unit ID is correct
    * Check network connection
    * Use test unit ID in test environment
  </Accordion>

  <Accordion title="onAdFailedToReceive is called">
    * Check error code to identify cause
    * Retry later if ad inventory is insufficient
    * Verify native SDK is properly integrated
  </Accordion>

  <Accordion title="Nothing happens after show() is called">
    * Verify `show()` is called after `onAdReceived` callback
    * Check `isLoaded` property to confirm ad is loaded
    * Verify native module is properly connected
  </Accordion>
</AccordionGroup>

### Memory Leak

```typescript theme={null}
// Good: Using cleanup function
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);

  return () => {
    ad.destroy();  // Must call
  };
}, []);

// Bad: Not cleaning up
useEffect(() => {
  const ad = new AdropPopupAd('YOUR_UNIT_ID');
  setPopupAd(ad);
  // No destroy() call - memory leak!
}, []);
```

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Getting Started" href="/sdk/react-native">
    SDK installation and initialization
  </Card>

  <Card title="Interstitial Ads" href="/sdk/react-native/interstitial">
    Implementing interstitial ads
  </Card>

  <Card title="Rewarded Ads" href="/sdk/react-native/rewarded">
    Implementing rewarded ads
  </Card>

  <Card title="Banner Ads" href="/sdk/react-native/banner">
    Implementing banner ads
  </Card>
</CardGroup>
