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

# ネイティブ広告

> Reactでネイティブ広告を実装する方法をご案内します。

## 実装方法

ネイティブ広告は、アプリのデザインに合わせてカスタムUIで広告を表示できます。

| 方式       | 説明            | 推奨               |
| -------- | ------------- | ---------------- |
| 基本テンプレート | SDK提供テンプレート使用 | 迅速な実装            |
| カスタムUI   | 直接UI構成        | デザインカスタマイズが必要な場合 |

<Note>
  開発環境ではテストユニットIDを使用してください：`PUBLIC_TEST_UNIT_ID_NATIVE`
</Note>

***

## 基本テンプレート

バナー広告と同じ方式で基本テンプレートを使用できます。SDKが提供するテンプレートに画像、テキストが自動的にレンダリングされます。

```tsx theme={null}
function NativeAd() {
  return <div data-adrop-unit="YOUR_NATIVE_UNIT_ID" />;
}
```

<Note>
  基本テンプレートは広告主プロフィールセクションをサポートしていません。広告主プロフィールを表示するには、カスタムUIを使用してください。
</Note>

***

## カスタムUI

### 1. Data Attributes方式

`data-adrop-render="custom"`属性を追加し、内部要素に`data-adrop-native`属性でフィールドをバインディングします。

```tsx theme={null}
function CustomNativeAd() {
  return (
    <div
      data-adrop-unit="YOUR_NATIVE_UNIT_ID"
      data-adrop-render="custom"
      data-adrop-entire-click="true"
      data-adrop-custom-click="true"  // カスタムクリック処理の有効化
      className="native-ad"
    >
      {/* 広告主プロフィール */}
      <div className="ad-profile">
        <img data-adrop-native="profile.displayLogo" alt="広告主" />
        <span data-adrop-native="profile.displayName"></span>
      </div>

      {/* 広告コンテンツ */}
      <h3 data-adrop-native="headline"></h3>
      <img data-adrop-native="asset" alt="広告" />
      <p data-adrop-native="body"></p>

      {/* 追加テキスト項目 */}
      <span data-adrop-native="extra.price"></span>

      {/* CTAボタン */}
      <button data-adrop-native="callToAction"></button>
    </div>
  );
}
```

#### Data Attributes

<ParamField body="data-adrop-unit" type="string" required>
  Ad Controlコンソールで作成したユニットID
</ParamField>

<ParamField body="data-adrop-render" type="string" required>
  カスタムUI使用時は`custom`に設定
</ParamField>

<ParamField body="data-adrop-context-id" type="string">
  コンテキストターゲティング用Context ID
</ParamField>

<ParamField body="data-adrop-theme" type="string" default="light">
  テーマ設定（`light`または`dark`）
</ParamField>

<ParamField body="data-adrop-entire-click" type="boolean" default={false}>
  全体領域クリックを有効化

  * `false`：テキスト/画像のみクリック可能、広告主プロフィールクリック時はプロフィールリンクに移動
  * `true`：コンテナ全体クリック可能、すべてのクリックが広告先に移動
</ParamField>

<ParamField body="data-adrop-custom-click" type="boolean" default={false}>
  カスタムクリック処理の有効化 - `true`に設定するとSDKが自動で目的地URLに移動せず、`adClicked`イベントのみ発生させます。開発者がクリック動作を直接実装できます。
</ParamField>

<ParamField body="data-adrop-ad-id" type="string">
  広告識別子 — **デバイスで表示**機能で登録済みテストデバイスからドラフトクリエイティブをプレビューするときに必要です。本番環境にハードコードしないでください。
</ParamField>

### 2. renderAd方式

広告読み込みタイミングを直接制御したい場合に使用します。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function CustomNativeAd() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: 'YOUR_NATIVE_UNIT_ID',
        contextId: 'YOUR_CONTEXT_ID',
        theme: 'light',
        trackMode: 1,        // カスタムUI使用時必須
        isEntireClick: true, // 全体領域クリックを有効化
        useCustomClick: true // カスタムクリック処理の有効化
      });
    }

    return () => {
    };
  }, []);

  return (
    <div ref={containerRef} className="native-ad">
      <div className="ad-profile">
        <img data-adrop-native="profile.displayLogo" alt="広告主" />
        <span data-adrop-native="profile.displayName"></span>
      </div>
      <h3 data-adrop-native="headline"></h3>
      <img data-adrop-native="asset" alt="広告" />
      <p data-adrop-native="body"></p>
      <button data-adrop-native="callToAction"></button>
    </div>
  );
}
```

#### renderAdオプション

<ParamField body="unit" type="string" required>
  Ad Controlコンソールで作成したユニットID
</ParamField>

<ParamField body="uid" type="string">
  ユーザー識別子（SDK設定値を個別の広告枠で上書きする場合に使用）
</ParamField>

<ParamField body="contextId" type="string">
  コンテキストターゲティング用Context ID
</ParamField>

<ParamField body="trackMode" type="number" required>
  カスタムUI使用時は`1`に設定
</ParamField>

<ParamField body="isEntireClick" type="boolean" default={false}>
  全体領域クリックを有効化
</ParamField>

<ParamField body="theme" type="string" default="light">
  テーマ設定（`light`または`dark`）
</ParamField>

<ParamField body="useCustomClick" type="boolean" default={false}>
  カスタムクリック処理の有効化 - `true`に設定するとSDKが自動で目的地URLに移動せず、`adClicked`イベントのみ発生させます。開発者がクリック動作を直接実装できます。
</ParamField>

<ParamField body="adId" type="string">
  広告識別子 — **デバイスで表示**機能で登録済みテストデバイスからドラフトクリエイティブをプレビューするときに必要です。本番環境にハードコードしないでください。
</ParamField>

***

## フィールドバインディング

`data-adrop-native`属性で広告データをUI要素にバインディングします。

| フィールド                 | 説明         | 要素タイプ   |
| --------------------- | ---------- | ------- |
| `profile.displayLogo` | 広告主ロゴURL   | `<img>` |
| `profile.displayName` | 広告主名       | テキスト    |
| `headline`            | 広告タイトル     | テキスト    |
| `body`                | 広告説明       | テキスト    |
| `asset`               | メイン画像URL   | `<img>` |
| `callToAction`        | CTAボタンテキスト | テキスト    |
| `extra.{key}`         | 追加テキスト項目   | テキスト    |

<Note>
  `extra.{key}`はAd Controlコンソールで設定した追加テキスト項目のIDです。必須設定していない場合は空の可能性があります。
</Note>

<Note>
  広告主プロフィール（`profile.displayLogo`、`profile.displayName`）を表示するには、Ad Controlコンソールで該当広告ユニットの<strong>広告主プロフィール表示</strong>を有効化する必要があります。
</Note>

***

## 広告サイズ

カスタムUIのサイズは自由に設定できます。

| 区分       | サイズ設定       | 配置      |
| -------- | ----------- | ------- |
| ダイレクト広告  | レスポンシブ対応    | 水平/垂直中央 |
| バックフィル広告 | 初期幅合わせ、高さ必須 | 水平中央    |

<Note>
  バックフィル広告はコンテナサイズに合う素材をリクエストします。適切なサイズを指定してください。
</Note>

***

## requestAdでデータのみ取得

UIを完全に直接制御したい場合は、`requestAd`で広告データのみを取得できます。

```tsx theme={null}
import { useState, useEffect } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function NativeAd() {
  const [adData, setAdData] = useState<AdData | null>(null);

  useEffect(() => {
    async function loadAd() {
      const adrop = Adrop.instance();

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

      if (response.code === 0 && response.result) {
        setAdData(response.result);
      }
    }

    loadAd();
  }, []);

  if (!adData) return null;

  return (
    <div className="native-ad">
      <div className="ad-header">
        {adData.profile?.displayLogo && (
          <img src={adData.profile.displayLogo} alt="広告主" />
        )}
        <span>{adData.profile?.displayName}</span>
      </div>
      <h3>{adData.headline}</h3>
      {adData.asset && <img src={adData.asset} alt="広告" />}
      <p>{adData.body}</p>
      <a href={adData.destinationURL} target="_blank" rel="noopener noreferrer">
        {adData.callToAction}
      </a>
    </div>
  );
}
```

<Warning>
  `requestAd`使用時はインプレッション/クリック追跡を直接実装する必要があります。また、この方式ではバックフィル広告はサポートされていません。特別な場合でなければ`renderAd`を推奨します。
</Warning>

### AdropAdResponse

`requestAd()`の戻り値です。

| フィールド    | タイプ      | 説明                           |
| -------- | -------- | ---------------------------- |
| `code`   | `number` | レスポンスコード（0：成功、4000-4003：エラー） |
| `msg`    | `string` | レスポンスメッセージ                   |
| `result` | `AdData` | 広告データ（成功時のみ存在）               |

### AdData

広告データオブジェクトです。イベントハンドラーでも同じ構造で渡されます。詳細は[リファレンス > AdData](/ja/sdk/web/reference#addata)を参照してください。

| フィールド                 | タイプ                      | 説明                                       |
| --------------------- | ------------------------ | ---------------------------------------- |
| `format`              | `string`                 | 広告フォーマット（`banner`、`nativeAd`、`backfill`） |
| `unit`                | `string`                 | ユニットID                                   |
| `headline`            | `string`                 | 広告タイトル                                   |
| `body`                | `string`                 | 広告説明                                     |
| `callToAction`        | `string`                 | CTAボタンテキスト                               |
| `asset`               | `string`                 | メイン画像URL                                 |
| `destinationURL`      | `string`                 | クリック時の移動先URL                             |
| `profile.displayLogo` | `string`                 | 広告主ロゴURL                                 |
| `profile.displayName` | `string`                 | 広告主名                                     |
| `profile.link`        | `string`                 | 広告主プロフィールリンク                             |
| `extra`               | `Record<string, string>` | 追加テキスト項目                                 |

***

## カスタムクリック処理

`useCustomClick`が有効化されるとSDKが自動で目的地URLに移動しません。代わりにクリックイベントを処理してカスタム動作を実装できます。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function CustomClickNativeAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    // カスタム動作で広告クリック処理
    const handleClicked = (unit: string, adData: any) => {
      console.log('広告クリック:', unit);
      console.log('目的地URL:', adData.destinationURL);
      
      // カスタムクリック動作実装
      // 例：SPA内ナビゲーション、モーダル表示、分析追跡など
      if (adData.destinationURL) {
        // カスタムナビゲーションロジック
        window.location.href = adData.destinationURL;
      }
    };

    adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: unitId,
        trackMode: 1,
        isEntireClick: true,
        useCustomClick: true
      });
    }

    return () => {
      adrop.off(Adrop.Events.AD_CLICKED, handleClicked);
    };
  }, [unitId]);

  return (
    <div ref={containerRef} className="native-ad">
      <div className="ad-profile">
        <img data-adrop-native="profile.displayLogo" alt="広告主" />
        <span data-adrop-native="profile.displayName"></span>
      </div>
      <h3 data-adrop-native="headline"></h3>
      <img data-adrop-native="asset" alt="広告" />
      <p data-adrop-native="body"></p>
      <button data-adrop-native="callToAction"></button>
    </div>
  );
}
```

<Note>
  カスタムクリック処理が有効化されると、ユーザーが広告をクリックしたときの動作を完全に制御できます。`destinationURL`は`adClicked`イベントデータに含まれて提供されます。
</Note>

***

## イベント処理

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function NativeAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    const handleReceived = (unit: string, adData: any) => {
      console.log('広告受信:', adData);
    };

    const handleNoFill = (unit: string) => {
      console.warn('広告なし:', unit);
    };

    const handleFailed = (unit: string) => {
      console.error('広告失敗:', unit);
    };

    const handleImpression = (unit: string, adData: any) => {
      console.log('広告表示:', unit);
    };

    const handleClicked = (unit: string, adData: any) => {
      console.log('広告クリック:', unit);
    };

    // 動画再生開始
    const handleVideoStart = (unit: string, adData: any) => {
      console.log('動画開始:', unit);
    };

    // 動画再生完了
    const handleVideoEnd = (unit: string, adData: any) => {
      console.log('動画完了:', 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);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: unitId,
        trackMode: 1,
        isEntireClick: true
      });
    }

    return () => {
      adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
      adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
      adrop.off(Adrop.Events.AD_FAILED, handleFailed);
      adrop.off(Adrop.Events.AD_IMPRESSION, handleImpression);
      adrop.off(Adrop.Events.AD_CLICKED, handleClicked);
      adrop.off(Adrop.Events.AD_VIDEO_START, handleVideoStart);
      adrop.off(Adrop.Events.AD_VIDEO_END, handleVideoEnd);
    };
  }, [unitId]);

  return (
    <div ref={containerRef} className="native-ad">
      <div className="ad-profile">
        <img data-adrop-native="profile.displayLogo" alt="広告主" />
        <span data-adrop-native="profile.displayName"></span>
      </div>
      <h3 data-adrop-native="headline"></h3>
      <img data-adrop-native="asset" alt="広告" />
      <p data-adrop-native="body"></p>
      <button data-adrop-native="callToAction"></button>
    </div>
  );
}
```

### サポートするイベント

| イベント     | 定数                    | 説明             |
| -------- | --------------------- | -------------- |
| 広告受信     | `AD_RECEIVED`         | 広告リクエスト成功      |
| 広告なし     | `AD_NO_FILL`          | 配信可能なダイレクト広告なし |
| リクエスト失敗  | `AD_FAILED`           | 広告リクエスト失敗      |
| インプレッション | `AD_IMPRESSION`       | 広告インプレッション記録   |
| クリック     | `AD_CLICKED`          | ユーザーが広告をクリック   |
| バックフィルなし | `AD_BACKFILL_NO_FILL` | バックフィル広告なし     |
| 動画開始     | `AD_VIDEO_START`      | 動画広告の再生開始      |
| 動画完了     | `AD_VIDEO_END`        | 動画広告の再生完了      |

***

## バックフィル広告

バックフィル広告が有効な場合、直接広告がないときに自動的にバックフィル広告がリクエストされます。`adData.format`で広告タイプを区別できます。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function NativeAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    // 広告受信（直接広告またはバックフィル）
    const handleReceived = (unit: string, adData: any) => {
      if (adData.format === 'backfill') {
        console.log('バックフィル広告がロードされました');
      } else {
        console.log('直接広告がロードされました'); // 'nativeAd'
      }
    };

    // 直接広告なし（バックフィルリクエスト開始）
    const handleNoFill = (unit: string) => {
      console.log('直接広告なし、バックフィル広告をリクエスト中...');
    };

    // バックフィル広告もなし
    const handleBackfillNoFill = (unit: string) => {
      console.warn('バックフィル広告もありません');
      // 広告エリアを非表示にするなどの処理
    };

    adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
    adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
    adrop.on(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, { unit: unitId });
    }

    return () => {
      adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
      adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
      adrop.off(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill);
    };
  }, [unitId]);

  return (
    <div ref={containerRef}>
      <h3 data-adrop-native="headline"></h3>
      <img data-adrop-native="asset" alt="広告" />
      <p data-adrop-native="body"></p>
      <button data-adrop-native="callToAction"></button>
    </div>
  );
}
```

<Note>
  **開発環境テスト**: アプリに連携された広告ユニットのうち少なくとも1つが**収益化中**であれば、localhostからでもバックフィル広告のリクエストが可能です。承認されていないドメインでは `AD_BACKFILL_NO_FILL` イベントが発生します。
</Note>
