> For the complete documentation index, see [llms.txt](https://adpopcornssp.gitbook.io/ssp-sdk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://adpopcornssp.gitbook.io/ssp-sdk/sdk/web-sdk-1.md).

# Web SDK

이 문서는 애드팝콘 SSP Web SDK를 사용하여 광고를 노출하고 이벤트를 처리하는 방법에 대한 연동 가이드입니다.

### 1. SDK 라이브러리 로드

연동이 필요한 페이지에 아래 SDK 스크립트를 추가합니다.

```html
<head>
   <script
      async
      src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
    ></script>
</head>
```

***

### 2. SDK 초기화 및 설정

SDK를 초기화하고 config를 설정해야 합니다. `init` 함수를 호출하여 `app_key`와 `placement_id`를 설정하고, `setConfig` 함수를 사용하여 Android 또는 iOS 플랫폼에 따라 해당 운영 체제에 맞는 config를 구성합니다.

#### 2-1. init 함수 전달용 객체 속성 정의

| 파라미터          | 타입      | 필수 | 설명                                          | 기본값   |
| ------------- | ------- | -- | ------------------------------------------- | ----- |
| app\_key      | string  | Y  | 매체용으로 발급된 광고 앱 키                            | -     |
| placement\_id | string  | Y  | 매체용으로 발급된 광고 지면 아이디                         | -     |
| log\_enabled  | boolean | N  | SDK 세부 로그 출력 여부 (설정하지 않을 경우, 에러 레벨의 로그만 출력) | false |

#### 2-2. setConfig 함수 전달용 객체 속성 정의

{% hint style="warning" %}
**안내사항**

* 광고 물량은 전달 가능한 파라미터 범위에 따라 달라질 수 있습니다. 가능한 범위 내 최대한 전달 부탁드립니다.
* 플랫폼 기준 공통으로 적용하는 항목 외에는 각 OS에 맞게 전달해 주시기 바랍니다.
  {% endhint %}

<table><thead><tr><th width="109" align="center">플랫폼</th><th width="135">속성</th><th width="99">Type</th><th width="78" align="center">필수</th><th width="217">설명</th><th>default</th></tr></thead><tbody><tr><td align="center">Android</td><td>adid</td><td>string</td><td align="center"><mark style="color:red;">Y</mark></td><td>Android 광고 식별자</td><td></td></tr><tr><td align="center">iOS</td><td>idfa</td><td>string</td><td align="center"><mark style="color:red;">Y</mark></td><td>iOS 광고 식별자</td><td></td></tr><tr><td align="center">iOS</td><td>idfv</td><td>string</td><td align="center">N(<mark style="color:red;">Y</mark>)</td><td>벤더 식별자 (단, 광고 추적 미동의로 idfa를 전달할 수 없는 경우, idfv 값을 필수로 전달)</td><td></td></tr><tr><td align="center">공통</td><td>network</td><td>string</td><td align="center">N</td><td>네트워크(wifi or mobile)</td><td>""</td></tr><tr><td align="center">공통</td><td>carrier</td><td>string</td><td align="center">N</td><td>통신사</td><td>""</td></tr><tr><td align="center">공통</td><td>model</td><td>string</td><td align="center">N</td><td>모델명</td><td>""</td></tr><tr><td align="center">공통</td><td>manufacturer</td><td>string</td><td align="center">N</td><td>제조사</td><td>""</td></tr><tr><td align="center">공통</td><td>os_version</td><td>string</td><td align="center">N</td><td>플랫폼 OS 버전</td><td>"0"</td></tr><tr><td align="center">공통</td><td>tag_for_child</td><td>0 | 1</td><td align="center">N</td><td>만 14세 미만 연령 제한 플래그 (기본값: 비활성화, 활성화 시 광고 미송출)</td><td>0</td></tr></tbody></table>

```html
<head>
  <script>
    window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };
    AdPopcornSSPWebSDK.cmd.push(() => {
      AdPopcornSSPWebSDK.init({
        app_key: "...",
        placement_id: "...",
        ...optional,
      });
      
      // android용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        adid: "...",
        ...optional,
      });

      // iOS용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        idfa: "...",
        ...optional,
      });
    });
  </script>
</head>
```

***

### 3. 광고 연동

연동할 광고 타입을 선택하세요.

{% hint style="info" %}
**광고 타입별 연동 방식**

* **배너 / 전면 / 전면비디오 / 리워드비디오**: `display()` 함수로 광고 노출. SDK가 직접 렌더링
* **네이티브**: `loadAd()` 함수로 광고 데이터 수신. 매체사가 직접 마크업 구성
  {% endhint %}

{% tabs %}
{% tab title="배너" %}
배너 광고를 노출할 `<div>` 요소를 HTML에 추가한 뒤, `display()` 함수를 호출하여 광고를 노출합니다.

**인스턴스 생성 함수 정의**

{% hint style="info" %}
앱키, 지면 아이디를 인스턴스에 전달하면 SDK init 설정과 별개로 인스턴스 개별 설정을 사용할 수 있습니다.
{% endhint %}

<table><thead><tr><th width="230">함수</th><th>설명</th></tr></thead><tbody><tr><td>createBannerSize300x250</td><td>배너 광고 인스턴스 생성용(사이즈: 320x250)</td></tr><tr><td>createBannerSize320x50</td><td>배너 광고 인스턴스 생성용(사이즈: 320x50)</td></tr><tr><td>createBannerSize320x100</td><td>배너 광고 인스턴스 생성용(사이즈: 320x100)</td></tr></tbody></table>

**인스턴스 생성 함수(create-) 전달용 객체 속성 정의**

<table><thead><tr><th width="207">속성명</th><th width="118">타입</th><th width="74">필수</th><th>설명</th></tr></thead><tbody><tr><td>app_key</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 앱 키</td></tr><tr><td>placement_id</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 지면 아이디</td></tr></tbody></table>

**인스턴스 함수 정의**

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>광고 요소를 화면에 표시</td></tr></tbody></table>

**인스턴스 함수 전달용 파라미터 속성 정의**

<table><thead><tr><th width="115">함수</th><th width="90">속성명</th><th width="84">Type</th><th width="73">필수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리를 구성할 요소의 id 속성명</td></tr></tbody></table>

```html
<body>
  <!-- 전면 배너 광고를 표시할 요소 -->
  <div id="banner-300-250-ad-inventory-frame"></div>
  <div id="banner-320-50-ad-inventory-frame"></div>
  <div id="banner-320-100-ad-inventory-frame"></div>
  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 배너 광고 인스터스 생성
      const banner300x250 = AdPopcornSSPWebSDK.createBannerSize300x250();
      const banner320x50 = AdPopcornSSPWebSDK.createBannerSize320x50();
      const banner320x100 = AdPopcornSSPWebSDK.createBannerSize320x100();      
      
      // 개별 설정 사용시, 배너 광고 인스턴스 생성
      const banner300x250 = AdPopcornSSPWebSDK.createBannerSize300x250({
        app_key: "...",
        placement_id: "..."
      });
      const banner320x50 = AdPopcornSSPWebSDK.createBannerSize320x50({
        app_key: "...",
        placement_id: "..."
      });
      const banner320x100 = AdPopcornSSPWebSDK.createBannerSize320x100({
        app_key: "...",
        placement_id: "..."
      });        

      // 배너 광고 노출
      banner300x250.display("banner-300-250-ad-inventory-frame");
      banner320x50.display("banner-320-50-ad-inventory-frame");
      banner320x100.display("banner-320-100-ad-inventory-frame");
    });
  </script>
</body>
```

{% endtab %}

{% tab title="전면" %}
전면 광고를 `<div>` 노출할 요소를 추가한 뒤 `display()` 함수를 호출합니다.

**인스턴스 생성 함수 정의**

{% hint style="info" %}
앱키, 지면 아이디를 인스턴스에 전달하면 SDK init 설정과 별개로 인스턴스 개별 설정을 사용할 수 있습니다.
{% endhint %}

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>createInterstitial</td><td>전면 광고 인스턴스 생성용</td></tr></tbody></table>

**인스턴스 생성 함수(create-) 전달용 객체 속성 정의**

<table><thead><tr><th width="207">속성명</th><th width="118">타입</th><th width="74">필수</th><th>설명</th></tr></thead><tbody><tr><td>app_key</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 앱 키</td></tr><tr><td>placement_id</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 지면 아이디</td></tr></tbody></table>

**인스턴스 함수 정의**

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>광고 요소를 화면에 표시</td></tr></tbody></table>

**인스턴스 함수 전달용 파라미터 속성 정의**

<table><thead><tr><th width="115">함수</th><th width="90">속성명</th><th width="84">Type</th><th width="73">필수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리를 구성할 요소의 id 속성명</td></tr></tbody></table>

```html
<body>
  <!-- 전면 광고를 표시할 요소 -->
  <div id="interstitial-ad-inventory-frame"></div>
  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 전면 광고 인스터스 생성
      const interstitial = AdPopcornSSPWebSDK.createInterstitial();      
      
      // 개별 설정 사용시, 전면 광고 인스턴스 생성
      const interstitial = AdPopcornSSPWebSDK.createInterstitial({
        app_key: "...",
        placement_id: "..."
      });

      // 전면 광고 노출
      interstitial.display("interstitial-ad-inventory-frame");
    });
  </script>
</body>
```

{% endtab %}

{% tab title="전면 비디오" %}
전면 비디오 광고를 노출할 `<div>` 요소를 추가한 뒤 `display()` 함수를 호출합니다.

{% hint style="warning" %}
**iOS 전체 화면 노출 방지**

iOS에서 전면 비디오 사용 시 전체 화면 노출을 방지하려면 아래 조건을 만족해야 합니다.

* Web SDK v1.11.0 이상 적용
* 앱 내 코드 추가: `configuration.allowsInlineMediaPlayback = true`&#x20;
  {% endhint %}

**인스턴스 생성 함수 정의**

{% hint style="info" %}
앱키, 지면 아이디를 인스턴스에 전달하면 SDK init 설정과 별개로 인스턴스 개별 설정을 사용할 수 있습니다.
{% endhint %}

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>createInterstitialVideo</td><td>전면 비디오 광고 인스턴스 생성용</td></tr></tbody></table>

**인스턴스 생성 함수(create-) 전달용 객체 속성 정의**

<table><thead><tr><th width="207">속성명</th><th width="118">타입</th><th width="74">필수</th><th>설명</th></tr></thead><tbody><tr><td>app_key</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 앱 키</td></tr><tr><td>placement_id</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 지면 아이디</td></tr><tr><td>user_landing_enabled</td><td>boolean</td><td>N</td><td>광고 클릭 시, 랜딩 페이지로 이동 허용 여부</td></tr></tbody></table>

**인스턴스 함수 정의**

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>광고 요소를 화면에 표시</td></tr><tr><td>terminateAd</td><td>구성된 광고 요소의 재생 중단 및 즉시 종료</td></tr></tbody></table>

**인스턴스 함수 전달용 파라미터 속성 정의**

<table><thead><tr><th width="123">함수</th><th width="87">속성명</th><th width="92">Type</th><th width="80">필수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리를 구성할 요소의 id 속성명</td></tr><tr><td>terminateAd</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리가 구성 요소의 id 속성명</td></tr></tbody></table>

```html
<body>
  <!-- 전면 비디오 광고를 표시할 요소 -->
  <div id="interstitial-video-ad-inventory-frame"></div>
  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 전면 광고 인스터스 생성
      const interstitialVideo = AdPopcornSSPWebSDK.createInterstitialVideo();      
      
      // 개별 설정 사용시, 전면 광고 인스턴스 생성
      const interstitialVideo = AdPopcornSSPWebSDK.createInterstitialVideo({
        app_key: "...",
        placement_id: "...",
        user_landing_enabled: "..."
      });

      // 전면 비디오 광고 노출
      interstitial.display("interstitial-video-ad-inventory-frame");
      
      // 전면 비디오 광고 강제 제거 필요시 실행
      interstitial.terminateAd("interstitial-video-ad-inventory-frame");
    });
  </script>
</body>
```

{% endtab %}

{% tab title="리워드 비디오" %}
리워드 비디오 광고를 노출할 `<div>` 요소를 추가한 뒤 `display()` 함수를 호출합니다.

{% hint style="warning" %}
**iOS 전체 화면 노출 방지**

iOS에서 전면 비디오 사용 시 전체 화면 노출을 방지하려면 아래 조건을 만족해야 합니다.

* Web SDK v1.11.0 이상 적용
* 앱 내 코드 추가: `configuration.allowsInlineMediaPlayback = true`&#x20;
  {% endhint %}

**인스턴스 생성 함수 정의**

{% hint style="info" %}
앱키, 지면 아이디를 인스턴스에 전달하면 SDK init 설정과 별개로 인스턴스 개별 설정을 사용할 수 있습니다.
{% endhint %}

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>createRewardVideo</td><td>리워드 비디오 광고 인스턴스 생성용</td></tr></tbody></table>

**인스턴스 생성 함수(create-) 전달용 객체 속성 정의**

<table><thead><tr><th width="207">속성명</th><th width="118">타입</th><th width="74">필수</th><th>설명</th></tr></thead><tbody><tr><td>app_key</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 앱 키</td></tr><tr><td>placement_id</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 지면 아이디</td></tr><tr><td>user_landing_enabled</td><td>boolean</td><td>N</td><td>광고 클릭 시, 랜딩 페이지로 이동 허용 여부</td></tr></tbody></table>

**인스턴스 함수 정의**

<table><thead><tr><th width="207">함수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>광고 요소를 화면에 표시</td></tr><tr><td>terminateAd</td><td>구성된 광고 요소의 재생 중단 및 즉시 종료</td></tr></tbody></table>

**인스턴스 함수 전달용 파라미터 속성 정의**

<table><thead><tr><th width="123">함수</th><th width="87">속성명</th><th width="92">Type</th><th width="80">필수</th><th>설명</th></tr></thead><tbody><tr><td>display</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리를 구성할 요소의 id 속성명</td></tr><tr><td>terminateAd</td><td>id</td><td>string</td><td>Y</td><td>광고 인벤토리가 구성 요소의 id 속성명</td></tr></tbody></table>

**\[ setUserId 함수 전달용 파라미터 속성 정의 ]**

{% hint style="warning" %}
**주의사항**

1. 1명의 유저는 1개의 고유한 유저식별값을 가져야하며, 가변적인 값을 사용해서는 안됩니다.
2. 개인정보(이메일, 이름, 전화번호, 식별가능한 유저아이디 등)이 포함되어서는 안됩니다.
3. 비디오 광고 노출 함수 실행 전에 설정되어야 합니다.
   {% endhint %}

{% hint style="info" %}
CS 처리 기능을 위해 유저식별값(userId)을 필수로 설정해주세요.
{% endhint %}

<table><thead><tr><th width="110">속성명</th><th width="90">Type</th><th width="70">필수</th><th></th></tr></thead><tbody><tr><td>userId</td><td>string</td><td><mark style="color:red;">Y</mark></td><td>리워드 비디오 시청 완료 시 완료 유저를 식별하기 위해 사용되는 값</td></tr></tbody></table>

{% code title="HTML" %}

```html
<body>
  <!-- 전면 배너 광고를 표시할 요소 -->
  <div id="reward-video-ad-inventory-frame"></div>
  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 리워드 비디오 광고 인스터스 생성
      const rewardVideo = AdPopcornSSPWebSDK.createRewardVideo();
      
      // 개별 설정 사용시, 리워드 비디오 광고 인스턴스 생성
      const rewardVideo = AdPopcornSSPWebSDK.createRewardVideo({
        app_key: "...",
        placement_id: "...",
        user_landing_enabled: "..."
      });
      
      // 리워드 비디오 CS 처리 기능을 위한 유저 식별값 필수 설정
      rewardVideo.setUserId("...")     

      // 리워드 비디오 광고 노출
      rewardVideo.display("reward-video-ad-inventory-frame");
      
      // 리워드 비디오 광고 강제 제거 필요시 실행
      rewardVideo.terminateAd("reward-video-ad-inventory-frame");
    });
  </script>
</body>
```

{% endcode %}
{% endtab %}

{% tab title="네이티브" %}
광고 데이터를 수신하여 매체사가 직접 UI를 구성하는 방식입니다. `loadAd()` 함수로 광고를 호출하고, `adLoadCompleted` 이벤트에서 광고 데이터를 수신합니다.

{% hint style="warning" %}
**주의사항**

loadAd() 호출 결과 광고 수신에 실패한 경우, loadAd()를 재호출하면 안 됩니다. 과도한 광고 호출 요청은 Block 사유가 됩니다.
{% endhint %}

**인스턴스 생성 함수 정의**

<table><thead><tr><th width="211">함수</th><th>설명</th></tr></thead><tbody><tr><td>createNative</td><td>네이티브 광고 인스턴스 생성용</td></tr><tr><td>createNativeTemplate</td><td>네이티브 템플릿 광고 인스턴스 생성용</td></tr></tbody></table>

**인스턴스 생성 함수 전달용 객체 속성 정의**

<table><thead><tr><th width="131">속성명</th><th width="95">Type</th><th width="92">필수</th><th>설명</th></tr></thead><tbody><tr><td>app_key</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 앱 키</td></tr><tr><td>placement_id</td><td>string</td><td>N</td><td>매체용으로 발급된 광고 지면 아이디</td></tr></tbody></table>

**네이티브 인스턴스 함수 정의**

{% hint style="warning" %}
**주의사항**

네이티브 광고 로딩 성공 후 리포트 수집을 위해 아래 함수를 필수로 호출해야 합니다.\
단, 네이티브 템플릿은 \[ 1) 광고 호출 ] 의 reportImpression, reportClick을 내장하고 있어 별도 호출이 필요하지 않습니다.
{% endhint %}

<table><thead><tr><th width="207">함수명</th><th>설명</th></tr></thead><tbody><tr><td>reportImpression</td><td>광고 로딩에 성공 후, 광고 데이터를 화면에 노출한 경우에 광고 노출 측정</td></tr><tr><td>reportClick</td><td>구성한 네이티브 광고를 클릭한 경우에 클릭 측정</td></tr></tbody></table>

1. **네이티브**

```html
<body>
  <!-- 광고 게재 위치 -->
  <div id="native-ad-inventory-frame"></div>

  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNative();
      
      // 개별 설정 사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNative({
        app_key: '[APP_KEY]',
        placement_id: '[PLACEMENT_ID]',
      });

      native.addEventListener('sdkError', (event) => {
        // 에러 케이스 대응
      });
    
      native.addEventListener('adLoadCompleted', (data) => {
        const { isNoAd, adData } = data; 
        
        if (isNoAd) {
          // no ad 케이스 대응
        }
                    
        // 마크업 작성 후 광고 요소(native-ad-inventory-frame)에 추가
      });
    
      native.loadAd();
      
      // ❗️광고 호출 결과 광고가 있는 경우, 아래 함수를 시점에 맞춰 필수 호출
      // 광고 호출 결과 수신용 adLoadCompleted 이벤트 리스너 사용법은 연동 가이드의 4. 광고 이벤트 처리 참조
      const reportNativeAdImpression = () => {
        // 네이티브 광고 노출 시점에 호출
        native.reportImpression();
      };
      
      const reportNativeAdClick = () => {
        // 네이티브 광고 클릭 시점에 호출
        native.reportClick();
      }
    });
  </script>
</body>
```

2. **템플릿 (createNativeTemplate)**

```html
<body>
  <!-- 광고 게재 위치 -->
  <div id="native-ad-360x80"></div>

  <!-- 광고 실행 코드(body 최하단 삽입 권장) -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNativeTemplate();
      
      // 개별 설정 사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNativeTemplate({
        app_key: '[APP_KEY]',
        placement_id: '[PLACEMENT_ID]',
      });

      native.addEventListener('sdkError', (event) => {
        // 에러 케이스 대응
      });
      
      native.addEventListener('adLoadCompleted', (data) => {
        const { isNoAd, adElement } = data;
        
        if (isNoAd) {
           // no ad 케이스 대응
        }
        
        //❗️아래 기능은 필요한 경우 템플릿에 적용
        // 1. 인포마크 제거
        adElement.dataset.noPrivacy = 'true';

        // 2. 테두리 제거
        adElement.dataset.noBorder = 'true';
  
        // 3. 배경색 변경
        adElement.style.backgroundColor = '#F6F6F6';

        // 4. 라운드 처리
        adElement.style.borderRadius = '10px';
        
        // 광고 게재 위치에 템플릿 등록             
        native.displayTemplate(adElement, 'native-ad-360x80');
      });

      // 광고 호출
      native.loadAd();
    });
  </script>
</body>

```

{% endtab %}
{% endtabs %}

***

### 3-1. \[선택] 패스백

{% tabs %}
{% tab title="배너" %}
**1. 애드팝콘 > 타 네트워크사**&#x20;

* 애드팝콘 `adInventoryRendered` 이벤트에서 `isNoAd`가 `true`일 때 모비위드 패스백 광고를 호출합니다.

{% code expandable="true" %}

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AP > MobWith passback sample</title>

    <!--  스크립트 삽입-->
    <script async src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"></script>

    <!-- 초기화 -->
    <script>
      window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };
    </script>
  </head>

  <body>
    <!-- 광고 개제 위치 -->
    <div id="adpopcorn-banner-ad-inventory-frame"></div>

    <!-- 애드팝콘 광고 연동 -->
    <script>
      let banner300x250;

      AdPopcornSSPWebSDK.cmd.push(() => {
        AdPopcornSSPWebSDK.init({
          app_key: "[APP_KEY]",
          placement_id: "[PLACEMENT_ID]",
          log_enabled: true,
          log_level: 0,
        });

        // ❗️option 1. android용 config 설정
        AdPopcornSSPWebSDK.setConfig({
          adid: "[ADID]",
        });

        // ❗️option 2. ios용 config 설정
        AdPopcornSSPWebSDK.setConfig({
          idfa: "[IDFA]",
        });
      });

      AdPopcornSSPWebSDK.cmd.push(() => {
        const bannerAdInventoryFrameId = "adpopcorn-banner-ad-inventory-frame";

        banner300x250 = AdPopcornSSPWebSDK.createBannerSize300x250();

        banner300x250.addEventListener("sdkError", (e) => {
          console.log("banner300x250 sdkError event:", e);
        });

        banner300x250.addEventListener("adInventoryRendered", (e) => {
          // ❗️adpopcorn 광고 no ad 시 mobwith 패스백 적용
          if (e.isNoAd) {
            const passbackBannerAdId = "reward-banner-ad-inventory-frame";
            setPassbackBannerAd(bannerAdInventoryFrameId, passbackBannerAdId);
          }
        });

        banner300x250.addEventListener("adClicked", (e) => {
          // ❗adpopcorn 광고 클릭 이벤트 처리 위치
          console.log("[adpopcorn banner clicked]");
        });

        banner300x250.display(bannerAdInventoryFrameId);
      });
    </script>

    <!-- 패스백 및 클릭 이벤트 적용 -->
    <script>
      const setPassbackBannerAd = (bannerAdInventoryFrameId, bannerAdId) => {
        // passback 광고를 표시할 요소 정의
        const bannerInventoryFrame = document.getElementById(
          bannerAdInventoryFrameId
        );

        // passback 광고 컨텐츠용 요소 정의
        const bannerAd = document.createElement("iframe");
        bannerAd.id = bannerAdId;

        // passback 광고 클릭 중복 발생 방지용 dataset 설정
        bannerAd.dataset.clicked = "false";

        // passback 광고 노출 위치 기본 스타일 설정
        Object.assign(bannerAd.style, {
          border: "none",
          width: "300px",
          height: "250px",
        });

        // ❗️mobwith api 적용
        // ❗ENV는 환경에 따라 적용 필요 (모바일 웹: 'web', 웹뷰: 'app')
        // ❗adid 항목에 os별 식별자 삽입
        bannerAd.src = "https://www.mobwithad.com/api/banner/{ENV}/adpopcorn/v2/adpopcorn?zone=&w=300&h=250&adid={ADID or IDFA}";

        bannerInventoryFrame.appendChild(bannerAd);

        const bannerAdDocument =
          bannerAd.contentDocument || bannerAd.contentWindow?.document;

        if (bannerAdDocument) {
          bannerAd.addEventListener("load", () => {
            bannerAdDocument.body.style.margin = "0";

            window.addEventListener("blur", () =>
              iframeClickEventHandler(bannerAd)
            );

            // 광고 로드 완료 시점에 iframe focus를 초기화
            window.focus();
          });
        }
      };

      const iframeClickEventHandler = (adElement) => {
        // 포커스된 요소가 iframe인지 확인
        if (
          !document.activeElement ||
          document.activeElement.tagName !== "IFRAME"
        )
          return;

        // 이미 클릭된 광고인지 확인
        if (adElement.dataset.clicked === "true") return;

        const activeIframeId = document.activeElement.id;
        const adElementId = adElement.id;

        // 포커스된 iframe 요소가 광고 요소의 id와 일치하는지 확인
        if (activeIframeId === adElementId) {
          // 광고 클릭 중복 발생 방지용 dataset 설정
          adElement.dataset.clicked = "true";

          // ❗️패스백 배너 클릭 이벤트 처리 위치
          console.log("[passback ad clicked]");
        }

        // 광고 요소 클릭으로 창이 이동되었을 때 window 포커스 초기화
        window.addEventListener("visibilitychange", () => {
          window.focus();
        });
      };
    </script>
  </body>
</html>
```

{% endcode %}

* 애드팝콘 `adInventoryRendered` 이벤트에서 `isNoAd`가 `true`일 때 트레이딩웍스(TW) 패스백 광고를 호출하고, TW 광고도 없을 경우 모비위드 패스백 광고를 호출합니다.

{% code expandable="true" %}

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AP > TW > MobWith passback sample</title>

    <!--  스크립트 삽입-->
    <script async src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"></script>

    <!-- 초기화 -->
    <script>
      window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };
    </script>
</head>

<body>
<!-- 광고 개제 위치 -->
<div id="adpopcorn-banner-ad-inventory-frame"></div>

<!-- 애드팝콘 광고 연동 -->
<script>
  let banner300x250;

  // ❗️애드팝콘 SSP app key, placement id 입력
  AdPopcornSSPWebSDK.cmd.push(() => {
    AdPopcornSSPWebSDK.init({
      app_key: "[APP_KEY]",
      placement_id: "[PLACEMENT_ID]",
      log_enabled: true,
      log_level: 0,
    });

    // ❗️option 1. android용 config 설정
    AdPopcornSSPWebSDK.setConfig({
      adid: "[ADID]",
    });

    // ❗️option 2. ios용 config 설정
    AdPopcornSSPWebSDK.setConfig({
      idfa: "[IDFA]",
    });
  });

  AdPopcornSSPWebSDK.cmd.push(() => {
    const bannerAdInventoryFrameId = "adpopcorn-banner-ad-inventory-frame";

    banner300x250 = AdPopcornSSPWebSDK.createBannerSize300x250();

    banner300x250.addEventListener("sdkError", (e) => {
      console.log("banner300x250 sdkError event:", e);
    });

    banner300x250.addEventListener("adInventoryRendered", (e) => {
      // ❗️adpopcorn 광고 no ad 시 TW 패스백 적용
      if (e.isNoAd) {
        setTWPassBackAd(bannerAdInventoryFrameId);
      }
    });

    banner300x250.addEventListener("adClicked", (e) => {
      // ❗adpopcorn 광고 클릭 이벤트 처리 위치
      console.log("[adpopcorn banner clicked]");
    });

    banner300x250.display(bannerAdInventoryFrameId);
  });
</script>

<!-- TW 패스백 광고 연동 -->
<script>
  const TW_AD_CONFIG = {
    endpoint: "https://ad-proxy.rtb.tw.igaw.io/ad",
    bundle: "[APP_BUNDLE]", // ❗패키지명
    tagid: "[PLACEMENT_ID]", // ❗애드팝콘 SSP placement id
    appId: "[APP_KEY]", // ❗애드팝콘 SSP app key
    adid: "[ADID]", // ❗Android GAID (앱에서 전달받아 세팅)
    idfa: "[IDFA]", // ❗iOS IDFA (앱에서 전달받아 세팅)
    timeout: 1000,
  };

  // TW 광고 요청
  const requestTWAd = async (config) => {
    const ifa = config.adid || config.idfa || "";

    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), config.timeout);

    try {
      const response = await fetch(config.endpoint, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          w: config.width,
          h: config.height,
          bundle: config.bundle,
          tagid: config.tagid,
          app_id: config.appId,
          ifa: ifa,
        }),
        signal: controller.signal,
      });

      clearTimeout(timer);

      if (response.status === 204 || !response.ok) {
        return null;
      }

      const markup = await response.text();
      return markup || null;
    } catch (err) {
      clearTimeout(timer);
      return null;
    }
  };

  // TW 패스백 광고 요청. no ad 시 MobWith 패스백 적용
  const setTWPassBackAd = async (bannerAdInventoryFrameId) => {
    const adMarkup = await requestTWAd(TW_AD_CONFIG);

    if (adMarkup) {
      createAdIframe({
        containerId: bannerAdInventoryFrameId,
        frameId: "tw-ad-frame",
        width: 300,
        height: 250,
        markup: adMarkup,
      });
      return;
    }

    // ❗️TW 광고 no ad 시 MobWith 패스백 적용
    setMobWithPassBackAd(bannerAdInventoryFrameId);
  };
</script>

<!-- MobWith 패스백 광고 연동 -->
<script>
  const setMobWithPassBackAd = (bannerAdInventoryFrameId) => {
    createAdIframe({
      containerId: bannerAdInventoryFrameId,
      frameId: "mobwith-ad-frame",
      width: 300,
      height: 250,
      // ❗adid 항목에 os별 식별자 삽입
      src: "https://www.mobwithad.com/api/banner/web/adpopcorn/v2/adpopcorn?zone=&w=300&h=250&adid=[ADID or IDFA]",
    });
  };
</script>

<!-- 패스백 iframe 생성 -->
<script>
  // 패스백 광고 iframe을 생성하고 컨테이너에 삽입
  const createAdIframe = ({ containerId, frameId, width, height, markup, src }) => {
    const container = document.getElementById(containerId);
    if (!container) return;

    container.style.display = "block";

    const iframe = document.createElement("iframe");
    iframe.id = frameId;
    iframe.dataset.clicked = "false";
    iframe.setAttribute("scrolling", "no");

    Object.assign(iframe.style, {
      border: "none",
      width: `${width}px`,
      height: `${height}px`,
      overflow: "hidden",
    });

    if (src) {
      iframe.src = src;
    }

    container.appendChild(iframe);

    const doc = iframe.contentDocument || iframe.contentWindow?.document;

    if (markup) {
      if (doc) {
        doc.open();
        doc.write(`<body style="margin:0;padding:0;overflow:hidden;">${markup}</body>`);
        doc.close();
      }
    }

    iframe.addEventListener("load", () => {
      // src 방식은 body margin 직접 제거
      if (src) {
        if (doc) doc.body.style.margin = "0";
      }

      window.addEventListener("blur", () => iframeClickEventHandler(iframe));
      window.focus();
    });
  };
</script>

<!-- 클릭 이벤트 적용 -->
<script>
  // iframe 내부 광고 클릭 감지
  const iframeClickEventHandler = (adElement) => {
    // 포커스된 요소가 iframe인지 확인
    if (
      !document.activeElement ||
      document.activeElement.tagName !== "IFRAME"
    )
      return;

    // 이미 클릭된 광고인지 확인
    if (adElement.dataset.clicked === "true") return;

    const activeIframeId = document.activeElement.id;
    const adElementId = adElement.id;

    // 포커스된 iframe 요소가 광고 요소의 id와 일치하는지 확인
    if (activeIframeId === adElementId) {
      // 광고 클릭 중복 발생 방지용 dataset 설정
      adElement.dataset.clicked = "true";

      // ❗️패스백 배너 클릭 이벤트 처리 위치
      console.log("[passback ad clicked]");
    }

    // 광고 요소 클릭으로 창이 이동되었을 때 window 포커스 초기화
    window.addEventListener("visibilitychange", () => {
      window.focus();
    });
  };
</script>
</body>
</html>

```

{% endcode %}

**2. 타 네트워크사 > 애드팝콘**&#x20;

구글 `slotRenderEnded` 이벤트에서`isEmpty`가 `true`일 때 애드팝콘 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <script
    async
    src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
  ></script>
  <script
    async
    src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
  ></script>
  <!-- 스크립트 초기화 및 설정 -->
  <script>
    window.googletag = window.googletag || { cmd: [] };
    window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };

    AdPopcornSSPWebSDK.cmd.push(() => {
      AdPopcornSSPWebSDK.init({
        app_key: "...",
        placement_id: "...",
        ...optional,
      });

      // android용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        adid: "...",
        ...optional,
      });

      // iOS용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        idfa: "...",
        ...optional,
      });
    });
  </script>
</head>
<body>
  <!-- 구글 배너 광고를 표시할 요소  -->
  <div id="google-banner-ad-inventory-frame"></div>
  <!-- 애드팝콘 광고를 표시할 요소  -->
  <div id="adpopcorn-ad-inventory-frame"></div>
  <script>
    // 구글 스크립트 연동
    
    googletag.cmd.push(() => {
      // 광고 슬롯 정의 및 서비스 추가
      const googleSlotElementId = 'google-banner-ad-inventory-frame';
      googletag.defineSlot(
        "...",
        [300,250],
        googleSlotElementId
      )
      .addService(googletag.pubads());
      
      // 이벤트 리스너 추가
      googletag.pubads().addEventListener("slotRenderEnded", (event) => {
        // 구글 스크립트 실행 결과, 광고가 없을 경우 애드팝콘 패스백 처리
        if (event.slot.getSlotElementId() === googleSlotElementId && event.isEmpty) {
          // 애드팝콘 스크립트 연동
          AdPopcornSSPWebSDK.cmd.push(() => {
            // 연동 가이드의 3.광고 연동 > 1)광고 노출, 4. 광고 이벤트 처리 참조
            // [필수] 1.광고 인스턴스 생성
            // [옵션] 2 [리워드비디오] 유저 식별값 설정
            // [옵션] 3.광고 이벤트 처리
            // [필수] 4.광고 노출
          });
        }
      });
      
      // 광고 서비스 설정 및 활성화
      googletag.pubads().enableSingleRequest();
      googletag.pubads().set("page_url", "...");
      googletag.enableServices();
      
      // 광고 노출
      googletag.display("google-banner-ad-inventory-frame");
    });
  </script>
</body>
```

{% endcode %}
{% endtab %}

{% tab title="전면" %}

1. **타 네트워크사 > 애드팝콘**&#x20;

구글 `slotRenderEnded` 이벤트에서 `isEmpty`가 `true`일 때 애드팝콘 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <script
    async
    src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
  ></script>
  <script
    async
    src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
  ></script>
  <!-- 스크립트 초기화 및 설정 -->
  <script>
    window.googletag = window.googletag || { cmd: [] };
    window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };

    AdPopcornSSPWebSDK.cmd.push(() => {
      AdPopcornSSPWebSDK.init({
        app_key: "...",
        placement_id: "...",
        ...optional,
      });

      // android용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        adid: "...",
        ...optional,
      });

      // iOS용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        idfa: "...",
        ...optional,
      });
    });
  </script>
</head>
<body>
  <!-- 애드팝콘 광고를 표시할 요소  -->
  <div id="adpopcorn-ad-inventory-frame"></div>
  <script>
    // 구글 스크립트 연동
    googletag.cmd.push(() => {
      // 광고 슬롯 정의 및 서비스 추가
      const interstitialSlot = googletag.defineOutOfPageSlot(
        "...",
        googletag.enums.OutOfPageFormat.INTERSTITIAL
      );

      if (interstitialSlot) {
        interstitialSlot.addService(googletag.pubads()).setConfig({
          interstitial: {
            triggers: {
              unhideWindow: true,
            },
          },
        });
      }
      
      // 이벤트 리스너 추가
      googletag.pubads().addEventListener("slotRenderEnded", (event) => {
        // 구글 스크립트 실행 결과, 광고가 없을 경우 애드팝콘 패스백 처리
        if (event.isEmpty) {
          // 애드팝콘 스크립트 연동
          AdPopcornSSPWebSDK.cmd.push(() => {
            // 3.광고 연동 > 1)광고 노출, 4. 광고 이벤트 처리 연동 가이드 참조
            // [필수] 1.광고 인스턴스 생성
            // [옵션] 2 [리워드비디오] 유저 식별값 설정
            // [옵션] 3.광고 이벤트 처리
            // [필수] 4.광고 노출
          });
        }
      });
      
      // 광고 서비스 설정 및 활성화
      googletag.pubads().enableSingleRequest();
      googletag.pubads().set("page_url", "...");
      googletag.enableServices();
      
      // 광고 노출
      googletag.display(interstitialSlot);
    });
  </script>
</body>

```

{% endcode %}
{% endtab %}

{% tab title="전면 비디오" %}

1. **타 네트워크사 > 애드팝콘**&#x20;

구글 `slotRenderEnded` 이벤트에서 `isEmpty`가 `true`일 때 애드팝콘 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <script
    async
    src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
  ></script>
  <script
    async
    src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
  ></script>
  <!-- 스크립트 초기화 및 설정 -->
  <script>
    window.googletag = window.googletag || { cmd: [] };
    window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };

    AdPopcornSSPWebSDK.cmd.push(() => {
      AdPopcornSSPWebSDK.init({
        app_key: "...",
        placement_id: "...",
        ...optional,
      });

      // android용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        adid: "...",
        ...optional,
      });

      // iOS용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        idfa: "...",
        ...optional,
      });
    });
  </script>
</head>
<body>
  <!-- 애드팝콘 광고를 표시할 요소  -->
  <div id="adpopcorn-ad-inventory-frame"></div>
  <script>
    // 구글 스크립트 연동
    googletag.cmd.push(() => {
      // 광고 슬롯 정의 및 서비스 추가
      const interstitialVieoSlot = googletag.defineOutOfPageSlot(
        "...",
        googletag.enums.OutOfPageFormat.REWARDED
      );

      if (interstitialVieoSlot) {
        interstitialVieoSlot.addService(googletag.pubads());
      }
      
      // 이벤트 리스너 추가
      googletag.pubads().addEventListener("slotRenderEnded", (event) => {
        // 구글 스크립트 실행 결과, 광고가 없을 경우 애드팝콘 패스백 처리
        if (event.isEmpty) {
          // 애드팝콘 스크립트 연동
          AdPopcornSSPWebSDK.cmd.push(() => {
            // 3.광고 연동 > 1)광고 노출, 4. 광고 이벤트 처리 연동 가이드 참조
            // [필수] 1.광고 인스턴스 생성
            // [옵션] 2 [리워드비디오] 유저 식별값 설정
            // [옵션] 3.광고 이벤트 처리
            // [필수] 4.광고 노출
          });
        }
      });
      
      googletag.pubads().addEventListener("rewardedSlotReady", (e) => {
        // 광고가 준비되었을 때, 광고 슬롯의 visible 속성 변경
        e.makeRewardedVisible();
      });
      googletag.pubads().addEventListener("rewardedSlotClosed", () => {
        // 광고 닫기 이벤트가 감지되었을 때, 광고 슬롯 제거
        googletag.destroySlots([interstitialVideoSlot]);
      });
      
      // 광고 서비스 설정 및 활성화
      googletag.pubads().enableSingleRequest();
      googletag.pubads().set("page_url", "...");
      googletag.enableServices();
      
      // 광고 노출
      googletag.display(interstitialVieoSlot);
    });
  </script>
</body>

```

{% endcode %}
{% endtab %}

{% tab title="리워드 비디오" %}

1. **타 네트워크사 > 애드팝콘**&#x20;

구글 `slotRenderEnded` 이벤트에서 `isEmpty`가 `true`일 때 애드팝콘 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <script
    async
    src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
  ></script>
  <script
    async
    src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
  ></script>
  <!-- 스크립트 초기화 및 설정 -->
  <script>
    window.googletag = window.googletag || { cmd: [] };
    window.AdPopcornSSPWebSDK = window.AdPopcornSSPWebSDK || { cmd: [] };

    AdPopcornSSPWebSDK.cmd.push(() => {
      AdPopcornSSPWebSDK.init({
        app_key: "...",
        placement_id: "...",
        ...optional,
      });

      // android용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        adid: "...",
        ...optional,
      });

      // iOS용 config 설정
      AdPopcornSSPWebSDK.setConfig({
        idfa: "...",
        ...optional,
      });
    });
  </script>
</head>
<body>
  <!-- 애드팝콘 광고를 표시할 요소  -->
  <div id="adpopcorn-ad-inventory-frame"></div>
  <script>
    // 구글 스크립트 연동
    googletag.cmd.push(() => {
      // 광고 슬롯 정의 및 서비스 추가
      const rewardVideoSlot = googletag.defineOutOfPageSlot(
        "...",
        googletag.enums.OutOfPageFormat.REWARDED
      );

      if (rewardVideoSlot) {
        rewardVideoSlot.addService(googletag.pubads());
      }
      
      // 이벤트 리스너 추가
      googletag.pubads().addEventListener("slotRenderEnded", (event) => {
        // 구글 스크립트 실행 결과, 광고가 없을 경우 애드팝콘 패스백 처리
        if (event.isEmpty) {
          // 애드팝콘 스크립트 연동
          AdPopcornSSPWebSDK.cmd.push(() => {
            // 3.광고 연동 > 1)광고 노출, 4. 광고 이벤트 처리 연동 가이드 참조
            // [필수] 1.광고 인스턴스 생성
            // [옵션] 2 [리워드비디오] 유저 식별값 설정
            // [옵션] 3.광고 이벤트 처리
            // [필수] 4.광고 노출
          });
        }
      });
      
      googletag.pubads().addEventListener("rewardedSlotReady", (e) => {
        // 광고가 준비되었을 때, 광고 슬롯의 visible 속성 변경
        e.makeRewardedVisible();
      });
      googletag.pubads().addEventListener("rewardedSlotClosed", () => {
        // 광고 닫기 이벤트가 감지되었을 때, 광고 슬롯 제거
        googletag.destroySlots([rewardVideoSlot]);
      });
      googletag.pubads().addEventListener('rewardedSlotGranted', (e) => {
        // 리워드 지급 조건에 부합했을 때, 리워드 정보 감지
        const reward = event.payload
      });
      
      // 광고 서비스 설정 및 활성화
      googletag.pubads().enableSingleRequest();
      googletag.pubads().set("page_url", "...");
      googletag.enableServices();
      
      // 광고 노출
      googletag.display(rewardVideoSlot);
    });
  </script>
</body>

```

{% endcode %}
{% endtab %}

{% tab title="네이티브" %}

1. **애드팝콘 > 타 네트워크**

`adLoadCompleted` 이벤트에서 `isNoAd`가 `true`일 때 NAM 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <!-- Web SDK -->
  <script
      async
      src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
    ></script>
  <!-- NAM -->
  <script async src="https://ssl.pstatic.net/tveta/libs/glad/prod/gfp-core.js"></script>
</head>
<body>
  <!-- 광고 게재 위치 -->
  <div id="native-ad-inventory-frame"></div>
    
  <!-- Web SDK -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const native = AdPopcornSSPWebSDK.createNative({
        app_key: '[APP_KEY]',
        placement_id: '[PLACEMENT_ID]',
      });
    
      native.addEventListener('sdkError', (event) => {
        // 에러 케이스 대응
      });
    
      native.addEventListener('adLoadCompleted', (data) => {
        const { isNoAd, adData } = data; 
        
        if (isNoAd) {
            // ❗️ Web SDK 광고 응답이 없을 경우 NAM 호출
            loadNAMAd();
            return;
        }
                    
        // 마크업 작성 후 광고 요소(native-ad-inventory-frame)에 추가
      });
    
      native.loadAd();
    });
  </script>
  
  <!-- NAM -->
  <script>
    const loadNAMAd = () => {
      const namDiv = document.getElementById('native-ad-inventory-frame');

      namDiv.style.display = 'block';

      window.gladsdk = window.gladsdk || { cmd: [] };
      window.gladsdk.cmd.push(() => {
        const adSlotInfo = {
          adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId
          adSlotElementId: 'native-ad-inventory-frame', // 배너 광고를 표시할 요소
        };

        // Case 1. 기본 적용
        window.gladsdk.defineAdSlot(adSlotInfo);
        window.gladsdk.displayAd('native-ad-inventory-frame');
        
        -----------------------------
        
        // Case 2. 커스텀 핸들러 적용
        // ref. https://naver.github.io/nam-sdk-guide/web/advanced/click_handler/
        const adSlot = window.gladsdk.defineAdSlot(adSlotInfo);
        
        adSlot.setClickHandler(function (curl, furl, extra) {
          console.debug('curl', curl, 'furl', furl, 'ext', ext, 'type', ext.type);
        });
        
        window.gladsdk.displayAd('native-ad-inventory-frame');
        });
    };
  </script>
</body>
```

{% endcode %}
{% endtab %}

{% tab title="네이티브 템플릿" %}

1. **애드팝콘 > 타 네트워크**

`adLoadCompleted` 이벤트에서 `isNoAd`가 `true`일 때 NAM 광고를 호출합니다.

{% code expandable="true" %}

```html
<head>
  <!-- 스크립트 추가 -->
  <!-- Web SDK -->
  <script
      async
      src="https://webapi.adpopcorn.com/ssp/web-sdk/ap-ssp-web-sdk-1.14.1.min.js"
    ></script>
  <!-- NAM -->
  <script async src="https://ssl.pstatic.net/tveta/libs/glad/prod/gfp-core.js"></script>
</head>
<body>
  <!-- 광고 게재 위치 -->
  <div id="native-ad-360x80"></div>

  <!-- Web SDK -->
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      // 개별 설정 미사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNativeTemplate();
      
      // 개별 설정 사용시, 네이티브 광고 인스턴스 생성
      const native = AdPopcornSSPWebSDK.createNativeTemplate({
         app_key: '[APP_KEY]',
         placement_id: '[PLACEMENT_ID]',
      });

      native.addEventListener('sdkError', (event) => {
        // 에러 케이스 대응
      });
      
      native.addEventListener('adLoadCompleted', (data) => {
        const { isNoAd, adElement } = data;
        
        if (isNoAd) {
           // ❗️ Web SDK 광고 응답이 없을 경우 NAM 호출
           loadNAMAd();
           return;
        }
                    
        // 광고 게재 위치에 템플릿 등록             
        native.displayTemplate(adElement, 'native-ad-360x80');
      });

      // 광고 호출
      native.loadAd();
    });
  </script>
  
  <!-- NAM -->
  <script>
    const loadNAMAd = () => {
      const namDiv = document.getElementById('native-ad-360x80');

      namDiv.style.display = 'block';

      window.gladsdk = window.gladsdk || { cmd: [] };
      window.gladsdk.cmd.push(() => {
        const adSlotInfo = {
          adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId
          adSlotElementId: 'native-ad-360x80', // 배너 광고를 표시할 요소
        };

        window.gladsdk.defineAdSlot(adSlotInfo);
        window.gladsdk.displayAd('native-ad-360x80');
      });
    };
  </script>
</body>
```

{% endcode %}
{% endtab %}
{% endtabs %}

<details>

<summary>NAM 광고 중복 제어 적용하기</summary>

페이지에 여러 개의 광고 슬롯이 있을 때 각각의 광고는 독립적으로 요청되기 때문에 동일한 광고가 노출될 수 있습니다. 동일한 광고를 제공하고 싶지 않을 때 중복 제어를 적용하여 중복된 광고를 제공하지 않을 수 있습니다.\
\
**참고 문서**\
[NAM SDK > 광고 중복 제어](https://naver.github.io/nam-sdk-guide/web/advanced/deduplication/)

```html
// e.g.노출하고자 하는 NAM 광고 영역이 4개일 때

<body>
    <!-- 광고 영역 -->
    <div id="division_1"></div>
    <div id="division_2"></div>
    <div id="division_3"></div>
    <div id="division_4"></div>
    
    <script>
      const loadWebSDKAd = () => {
        AdPopcornSSPWebSDK.cmd.push(() => {
          const native = AdPopcornSSPWebSDK.createNative({
            app_key: '[APP_KEY]',
            placement_id: '[PLACEMENT_ID]',
          });
  
          native.addEventListener('sdkError', (e) => {
            console.log('native sdkError event:', e);
          });
  
          native.addEventListener('adLoadCompleted', (e) => {
            console.log('native adLoadCompleted event:', e);
  
            if (e.isNoAd) {
              // Web SDK 광고 응답이 없을 경우 NAM 호출
              loadNAMAd();
            }
  
            // no ad가 아닌 경우 각 광고 영역 (division 1~4)에 해당하는 마크업 제작 후 추가
          });
  
          native.loadAd();
        });
      };
    </script>

    <script>
      const loadNAMAd = () => {
        const dedupReqId = 'deduplicationRequestId';
        const maxDedupReqCount = 3;
  
        window.gladsdk = window.gladsdk || { cmd: [] };
  
        window.gladsdk.cmd.push(() => {
          const adSlotInfo1 = {
            adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId 1
            adSlotElementId: 'division_1',
          };
  
          const adSlotInfo2 = {
            adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId 2 
            adSlotElementId: 'division_2',
          };
  
          const adSlotInfo3 = {
            adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId 3
            adSlotElementId: 'division_3',
          };
  
          const adSlotInfo4 = {
            adUnitId: '[AD_UNIT_ID]', // NAM에서 발급받은 adUnitId 4
            adSlotElementId: 'division_4',
          };
  
          const adSlot1 = window.gladsdk.defineAdSlot(adSlotInfo1);
          const adSlot2 = window.gladsdk.defineAdSlot(adSlotInfo2);
          const adSlot3 = window.gladsdk.defineAdSlot(adSlotInfo3);
          const adSlot4 = window.gladsdk.defineAdSlot(adSlotInfo4);
  
          const adDedupManager = window.gladsdk.setAdDeduplication(dedupReqId, maxDedupReqCount);
  
          adDedupManager.displayAds([adSlot1, adSlot2, adSlot3, adSlot4]);
        });
      }
    </script>
</body>
```

</details>

***

### 4. SDK 이벤트 처리

광고 노출 함수(display) / 광고 호출 함수(loadAd) 실행 전, 광고 인스턴스의 <mark style="color:red;">`addEventListener`</mark>함수를 등록하여 광고 이벤트를 감지하고 필요한 작업을 수행할 수 있습니다.

#### &#x20;이벤트 정의&#x20;

<table><thead><tr><th width="150">광고타입</th><th width="191">이벤트 타입</th><th width="230">이벤트 설명</th><th>이벤트 객체(e) 유,무</th></tr></thead><tbody><tr><td>공통</td><td>sdkError</td><td>SDK 연동 실패 시 발생</td><td>O</td></tr><tr><td>전면/전면비디오/배너/리워드 비디오</td><td>adInventoryRendered</td><td>SDK 연동이 성공한 상황에서 광고 인벤토리 렌더링 실행 후 발생</td><td>O</td></tr><tr><td>전면/전면 비디오/ 리워드 비디오</td><td>adClosed</td><td>광고 인벤토리 닫기 클릭시 발생</td><td>X</td></tr><tr><td>전면/배너</td><td>adClicked</td><td>광고 인벤토리의 광고 클릭시 최초 1회 발생</td><td>X</td></tr><tr><td>전면 비디오/ 리워드 비디오</td><td>adClickthrough</td><td>user_landing_enabled가 false인 환경에서 광고 인벤토리 클릭시 발생</td><td>O</td></tr><tr><td>리워드 비디오</td><td>adPlaybackCompleted</td><td>리워드 비디오 광고 재생 완료시 발생</td><td>X</td></tr><tr><td>네이티브</td><td>adLoadCompleted</td><td>SDK 연동이 성공한 상황에서 네이티브 광고 API 호출 후 발생</td><td>O</td></tr></tbody></table>

#### 이벤트 객체  속성 정의

<table><thead><tr><th width="180">속성 명</th><th width="92">Type</th><th width="74">필수</th><th width="435">설명</th><th data-hidden>default</th></tr></thead><tbody><tr><td>code</td><td>string</td><td>Y</td><td>이벤트 코드</td><td></td></tr><tr><td>message</td><td>string</td><td>Y</td><td>이벤트 코드 설명</td><td></td></tr><tr><td>isNoAd</td><td>boolean</td><td>Y</td><td>광고 요청 결과에 따른 광고 유,무</td><td></td></tr><tr><td>adData</td><td>string</td><td>N</td><td>네이티브 광고 호출 성공 시 전달되는 광고 데이터</td><td></td></tr><tr><td>adElement</td><td>Element</td><td>N</td><td>네이티브 템플릿 광고 호출 성공 시 전달되는 광고 엘리먼트</td><td></td></tr><tr><td>clickthroughURL</td><td>string</td><td>N</td><td>user_landing_enabled가 false인 환경에서 비디오형(전면 비디오/리워드 비디오) 광고 클릭 시, 랜딩될 주소</td><td></td></tr></tbody></table>

#### 광고 데이터(adData) 객체 속성 정의

<table><thead><tr><th width="233">속성 명</th><th width="92">Type</th><th width="74">필수</th><th width="435">설명</th><th data-hidden>default</th></tr></thead><tbody><tr><td>ctaText</td><td>string</td><td>Y</td><td>광고 CTA(call to action) 버튼 텍스트</td><td></td></tr><tr><td>desc</td><td>string</td><td>Y</td><td>광고 설명</td><td></td></tr><tr><td>iconImageURL</td><td>string</td><td>Y</td><td>광고 아이콘 이미지</td><td></td></tr><tr><td>landingURL</td><td>string</td><td>Y</td><td>광고 클릭시, 랜딩될 주소</td><td></td></tr><tr><td>mainImageURL</td><td>string</td><td>Y</td><td>광고 메인 이미지(기본 사이즈: 1200x628)</td><td></td></tr><tr><td>privacyPolicyImageURL</td><td>string</td><td>Y</td><td>개인 정보 아이콘 이미지 다운로드 주소</td><td></td></tr><tr><td>privacyPolicyURL</td><td>string</td><td>Y</td><td>개인정보 아이콘 클릭시 랜딩될 주소</td><td></td></tr><tr><td>title</td><td>string</td><td>Y</td><td>광고 타이틀</td><td></td></tr></tbody></table>

#### 광고 데이터(adData) 예시

```javascript
{
  ctaText: "Click",
  desc: "Adpopcorn SSP description sample",
  iconImageURL: "https://ap-ssp-be-static.s3.ap-northeast-1.amazonaws.com/test_campaign/80x80_icon.jpg",
  landingURL: "https://www.adpopcorn.com/",
  mainImageURL: "https://ap-ssp-be-static.s3.ap-northeast-1.amazonaws.com/test_campaign/1200x627.jpg",
  privacyPolicyImageURL: "https://ap-ssp-be-static.s3.ap-northeast-1.amazonaws.com/default_image/info-ico.png",
  privacyPolicyURL: "https://www.adpopcorn.com/policy/privacy",
  title: "Title sample"
};
```

{% tabs %}
{% tab title="전면" %}
{% code title="HTML" %}

```html
<body>
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const interstitial = AdPopcornSSPWebSDK.createInterstitial();

      // SDK 연동 실패
      interstitial.addEventListener("sdkError", (e) => {
        // SDK 연동 실패시, 이벤트 처리
      });

      // 광고 렌더링 결과
      interstitial.addEventListener("adInventoryRendered", (e) => {
        // 광고 렌더링 결과에 따른 이벤트 처리
      });

      // 광고 클릭
      interstitial.addEventListener("adClicked", () => {
        // 광고 클릭시, 이벤트 처리        
      });
      
      // 광고 닫기 클릭
      interstitial.addEventListener("adClosed", () => {
        // 광고 닫기 클릭시, 이벤트 처리        
      });
      
      interstitial.display("...");
    });
  </script>
</body>
```

{% endcode %}
{% endtab %}

{% tab title="전면 비디오" %}

<pre class="language-html" data-title="HTML"><code class="lang-html">&#x3C;body>
  &#x3C;script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const interstitialVideo = AdPopcornSSPWebSDK.createInterstitialVideo();

      // SDK 연동 실패
      interstitialVideo.addEventListener("sdkError", (e) => {
        // SDK 연동 실패시, 이벤트 처리
      });

      // 광고 렌더링 결과
      interstitialVideo.addEventListener("adInventoryRendered", (e) => {
        // 광고 렌더링 결과에 따른 이벤트 처리
      });
      
      // user_landing_enabled가 false인 환경에서 광고 클릭
      interstitialVideo.addEventListener("adClickthrough", (e) => {
        // 광고 클릭 후, 이벤트 처리
<strong>      });
</strong>      
      // 광고 닫기 클릭
      interstitialVideo.addEventListener("adClosed", () => {
        // 광고 닫기 클릭시, 이벤트 처리        
      });
      
      interstitialVideo.display("...");
    });
  &#x3C;/script>
&#x3C;/body>
</code></pre>

{% endtab %}

{% tab title="배너" %}

```html
<body>
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const banner = AdPopcornSSPWebSDK.createBanner000x000();

      // SDK 연동 실패
      banner.addEventListener("sdkError", (e) => {
        // SDK 연동 실패시, 이벤트 처리
      });

      // 광고 렌더링 결과
      banner.addEventListener("adInventoryRendered", (e) => {
        // 광고 렌더링 결과에 따른 이벤트 처리
      });

      // 광고 클릭
      banner.addEventListener("adClicked", () => {
        // 광고 클릭시, 이벤트 처리        
      });
            
      banner.display("...");
    });
  </script>
</body>
```

{% endtab %}

{% tab title="리워드 비디오" %}

```html
<body>
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const rewardVideo = AdPopcornSSPWebSDK.createRewardVideo();

      // SDK 연동 실패
      rewardVideo.addEventListener("sdkError", (e) => {
        // SDK 연동 실패시, 이벤트 처리
      });

      // 광고 렌더링 결과
      rewardVideo.addEventListener("adInventoryRendered", (e) => {
        // 광고 렌더링 결과에 따른 이벤트 처리
      });

      // 광고 재생 완료
      rewardVideo.addEventListener("adPlaybackCompleted", () => {
        // 광고 재생 완료시, 이벤트 처리        
      });
      
      // user_landing_enabled가 false인 환경에서 광고 클릭
      rewardVideo.addEventListener("adClickthrough", (e) => {
        // 광고 클릭 후, 이벤트 처리
      });
      
      // 광고 닫기 클릭
      rewardVideo.addEventListener("adClosed", () => {
        // 광고 닫기 클릭시, 이벤트 처리        
      });
      
      rewardVideo.display('...');
    });
  </script>
</body>
```

{% endtab %}

{% tab title="네이티브" %}

```html
<body>
  <script>
    AdPopcornSSPWebSDK.cmd.push(() => {
      const native = AdPopcornSSPWebSDK.createNative();

      // SDK 연동 실패
      native.addEventListener("sdkError", (e) => {
        // SDK 연동 실패시, 이벤트 처리
      });

      
      // 광고 호출 결과
      native.addEventListener("adLoadCompleted", (e) => {
        // 광고 호출 결과에 따른 이벤트 처리
        if (e.isNoAd) {
          // 광고 응답이 없을 경우
        }
         
        // 이벤트 객체 내 adData로 네이티브 배너 구성
      });
      
      native.loadAd();
    });
  </script>
</body>
```

{% endtab %}
{% endtabs %}
