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

# Native Ads

> Learn how to implement native ads using CDN.

## Implementation Methods

Native ads allow you to display ads with custom UI that matches your app's design.

| Method           | Description               | Recommended                         |
| ---------------- | ------------------------- | ----------------------------------- |
| Default Template | Use SDK-provided template | Quick implementation                |
| Custom UI        | Build your own UI         | When design customization is needed |

<Note>
  Use the test unit ID in development: `PUBLIC_TEST_UNIT_ID_NATIVE`
</Note>

***

## Default Template

You can use the default template in the same way as banner ads. Images and text are automatically rendered in the SDK-provided template.

```html theme={null}
<div data-adrop-unit="YOUR_NATIVE_UNIT_ID"></div>
```

<Note>
  The default template does not support advertiser profile sections. Use custom UI to display advertiser profiles.
</Note>

***

## Custom UI

### Data Attributes Method

Add the `data-adrop-render="custom"` attribute and bind fields using `data-adrop-native` attributes on inner elements.

```html theme={null}
<div
  data-adrop-unit="YOUR_NATIVE_UNIT_ID"
  data-adrop-render="custom"
  data-adrop-entire-click="true"
  data-adrop-custom-click="true"
  class="native-ad">

  <!-- Advertiser Profile -->
  <div class="ad-profile">
    <img data-adrop-native="profile.displayLogo" alt="Advertiser">
    <span data-adrop-native="profile.displayName"></span>
  </div>

  <!-- Ad Content -->
  <h3 data-adrop-native="headline"></h3>
  <img data-adrop-native="asset" alt="Ad">
  <p data-adrop-native="body"></p>

  <!-- Extra text items -->
  <span data-adrop-native="extra.price"></span>

  <!-- CTA Button -->
  <button data-adrop-native="callToAction"></button>
</div>
```

#### Data Attributes

<ParamField body="data-adrop-unit" type="string" required>
  Unit ID created in Ad Control Console
</ParamField>

<ParamField body="data-adrop-render" type="string" required>
  Set to `custom` for custom UI
</ParamField>

<ParamField body="data-adrop-context-id" type="string">
  Context ID for contextual targeting
</ParamField>

<ParamField body="data-adrop-theme" type="string" default="light">
  Theme setting (`light` or `dark`)
</ParamField>

<ParamField body="data-adrop-entire-click" type="boolean" default={false}>
  Enable entire area click

  * `false`: Only text/images are clickable, clicking advertiser profile goes to profile link
  * `true`: Entire container is clickable, all clicks go to ad destination
</ParamField>

<ParamField body="data-adrop-custom-click" type="boolean" default={false}>
  Enable custom click handling - When `true`, SDK will not automatically navigate to the destination URL on click, only emit `adClicked` event. Allows developers to implement custom click behavior.
</ParamField>

<ParamField body="data-adrop-ad-id" type="string">
  Advertising identifier — required for the **View on Device** feature to preview a draft creative on a registered test device. Do not hard-code in production.
</ParamField>

### renderAd Method

Use this when you want direct control over ad loading timing.

```html theme={null}
<div id="native-ad-container" class="native-ad">
  <div class="ad-profile">
    <img data-adrop-native="profile.displayLogo" alt="Advertiser">
    <span data-adrop-native="profile.displayName"></span>
  </div>
  <h3 data-adrop-native="headline"></h3>
  <img data-adrop-native="asset" alt="Ad">
  <p data-adrop-native="body"></p>
  <button data-adrop-native="callToAction"></button>
</div>

<script>
  const container = document.getElementById('native-ad-container');
  const adrop = Adrop.instance();

  adrop.renderAd(container, {
    unit: 'YOUR_NATIVE_UNIT_ID',
    contextId: 'YOUR_CONTEXT_ID',
    theme: 'light',
    trackMode: 1,        // Required for custom UI
    isEntireClick: true, // Enable entire area click
    useCustomClick: true // Enable custom click handling
  });
</script>
```

#### renderAd Options

<ParamField body="unit" type="string" required>
  Unit ID created in Ad Control Console
</ParamField>

<ParamField body="uid" type="string">
  User identifier (used to override SDK-level setting for individual placements)
</ParamField>

<ParamField body="contextId" type="string">
  Context ID for contextual targeting
</ParamField>

<ParamField body="trackMode" type="number" required>
  Set to `1` for custom UI
</ParamField>

<ParamField body="isEntireClick" type="boolean" default={false}>
  Enable entire area click
</ParamField>

<ParamField body="theme" type="string" default="light">
  Theme setting (`light` or `dark`)
</ParamField>

<ParamField body="useCustomClick" type="boolean" default={false}>
  Enable custom click handling - When `true`, SDK will not automatically navigate to the destination URL on click, only emit `adClicked` event with destination URL. Allows developers to implement custom click behavior.
</ParamField>

<ParamField body="adId" type="string">
  Advertising identifier — required for the **View on Device** feature to preview a draft creative on a registered test device. Do not hard-code in production.
</ParamField>

***

## Field Binding

Bind ad data to UI elements using the `data-adrop-native` attribute.

| Field                 | Description         | Element Type |
| --------------------- | ------------------- | ------------ |
| `profile.displayLogo` | Advertiser logo URL | `<img>`      |
| `profile.displayName` | Advertiser name     | Text         |
| `headline`            | Ad title            | Text         |
| `body`                | Ad description      | Text         |
| `asset`               | Main image URL      | `<img>`      |
| `callToAction`        | CTA button text     | Text         |
| `extra.{key}`         | Extra text items    | Text         |

<Note>
  `extra.{key}` is the ID of extra text items set in Ad Control Console. It may be empty if not set as required.
</Note>

<Note>
  To display advertiser profile (`profile.displayLogo`, `profile.displayName`), you must enable <strong>Show Advertiser Profile</strong> for that ad unit in Ad Control Console.
</Note>

***

## Ad Size

Custom UI size can be set freely.

| Type         | Size Setting                            | Alignment                  |
| ------------ | --------------------------------------- | -------------------------- |
| Direct Ads   | Responsive support                      | Horizontal/Vertical center |
| Backfill Ads | Initial width matching, height required | Horizontal center          |

<Note>
  Backfill ads request creatives matching the container size. Specify an appropriate size.
</Note>

***

## Fetching Data Only with requestAd

If you want complete control over the UI, you can fetch only the ad data using `requestAd`.

```html theme={null}
<div id="native-ad-container"></div>

<script>
  async function loadNativeAd() {
    const adrop = Adrop.instance();

    const response = await adrop.requestAd({
      unit: 'YOUR_NATIVE_UNIT_ID',
      trackMode: 1
    });

    if (response.code === 0 && response.result) {
      const ad = response.result;
      const container = document.getElementById('native-ad-container');

      container.innerHTML =
        '<div class="native-ad">' +
          '<div class="ad-header">' +
            '<img src="' + (ad.profile?.displayLogo || '') + '" alt="Logo">' +
            '<span>' + (ad.profile?.displayName || '') + '</span>' +
          '</div>' +
          '<h3>' + (ad.headline || '') + '</h3>' +
          '<img src="' + (ad.asset || '') + '" alt="Ad">' +
          '<p>' + (ad.body || '') + '</p>' +
          '<a href="' + ad.destinationURL + '" target="_blank">' + ad.callToAction + '</a>' +
        '</div>';
    }
  }

  loadNativeAd();
</script>
```

<Warning>
  When using `requestAd`, you must implement impression/click tracking yourself. Also, backfill ads are not supported with this method. We recommend using `renderAd` unless there's a special case.
</Warning>

### AdropAdResponse

Return value of `requestAd()`.

| Field    | Type     | Description                                  |
| -------- | -------- | -------------------------------------------- |
| `code`   | `number` | Response code (0: success, 4000-4003: error) |
| `msg`    | `string` | Response message                             |
| `result` | `AdData` | Ad data (only present on success)            |

### AdData

Ad data object. Event handlers also receive the same structure. See [Reference > AdData](/sdk/web/reference#addata) for the complete interface definition.

| Field                 | Type                     | Description                                  |
| --------------------- | ------------------------ | -------------------------------------------- |
| `format`              | `string`                 | Ad format (`banner`, `nativeAd`, `backfill`) |
| `unit`                | `string`                 | Unit ID                                      |
| `headline`            | `string`                 | Ad title                                     |
| `body`                | `string`                 | Ad description                               |
| `callToAction`        | `string`                 | CTA button text                              |
| `asset`               | `string`                 | Main image URL                               |
| `destinationURL`      | `string`                 | Click destination URL                        |
| `profile.displayLogo` | `string`                 | Advertiser logo URL                          |
| `profile.displayName` | `string`                 | Advertiser name                              |
| `profile.link`        | `string`                 | Advertiser profile link                      |
| `extra`               | `Record<string, string>` | Extra text items                             |

***

## Event Handling

```html theme={null}
<script>
  const adrop = Adrop.instance();
  const filter = { unit: 'YOUR_NATIVE_UNIT_ID' };

  function handleReceived(unit, adData) {
    console.log('Ad received:', adData);
  }

  function handleNoFill(unit) {
    console.warn('No ad available:', unit);
  }

  function handleFailed(unit) {
    console.error('Ad failed:', unit);
  }

  function handleImpression(unit, adData) {
    console.log('Ad impression:', unit);
  }

  function handleClicked(unit, adData) {
    console.log('Ad clicked:', unit);
  }

  // Video playback started
  function handleVideoStart(unit, adData) {
    console.log('Video started:', unit);
  }

  // Video playback ended
  function handleVideoEnd(unit, adData) {
    console.log('Video ended:', unit);
  }

  adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
  adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
  adrop.on(Adrop.Events.AD_FAILED, handleFailed, filter);
  adrop.on(Adrop.Events.AD_IMPRESSION, handleImpression, filter);
  adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);
  adrop.on(Adrop.Events.AD_VIDEO_START, handleVideoStart, filter);
  adrop.on(Adrop.Events.AD_VIDEO_END, handleVideoEnd, filter);
</script>
```

### Supported Events

| Event          | Constant              | Description               |
| -------------- | --------------------- | ------------------------- |
| Ad Received    | `AD_RECEIVED`         | Ad request successful     |
| No Ad          | `AD_NO_FILL`          | No direct ads available   |
| Request Failed | `AD_FAILED`           | Ad request failed         |
| Impression     | `AD_IMPRESSION`       | Ad impression recorded    |
| Click          | `AD_CLICKED`          | User clicked the ad       |
| No Backfill    | `AD_BACKFILL_NO_FILL` | No backfill ad available  |
| Video Start    | `AD_VIDEO_START`      | Video ad playback started |
| Video End      | `AD_VIDEO_END`        | Video ad playback ended   |

***

## Custom Click Handling

When `useCustomClick` is enabled, the SDK will not automatically navigate to the destination URL. Instead, you can handle the click event and implement custom behavior.

```html theme={null}
<script>
  const adrop = Adrop.instance();
  
  // Handle ad click with custom behavior
  function handleCustomClick(unit, adData) {
    console.log('Ad clicked:', unit);
    console.log('Destination URL:', adData.destinationURL);
    
    // Implement custom click behavior
    // For example: navigate within SPA, show modal, track analytics, etc.
    if (adData.destinationURL) {
      // Custom navigation logic
      window.location.href = adData.destinationURL;
    }
  }
  
  // Register click handler
  const filter = { unit: 'YOUR_NATIVE_UNIT_ID' };
  adrop.on(Adrop.Events.AD_CLICKED, handleCustomClick, filter);
  
  // Render ad with custom click enabled
  const container = document.getElementById('native-ad-container');
  adrop.renderAd(container, {
    unit: 'YOUR_NATIVE_UNIT_ID',
    trackMode: 1,
    isEntireClick: true,
    useCustomClick: true
  });
</script>
```

<Note>
  With custom click handling enabled, you have full control over what happens when users click the ad. The `destinationURL` is provided in the `adClicked` event data.
</Note>
