> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/common/monetization/iaa/web-banner.md).

# 应用内广告 - 横幅广告（WebView）

服务介绍和控制台设置方法请参考 [应用内广告介绍文档](https://developers-apps-in-toss.toss.im/guide/monetization/in-app-ad)。

这是一个可以在 WebView 中展示横幅广告的广告库。

### 开始使用

横幅广告 API 可在 Toss 应用 5.241.0 及以上版本中使用。

| Toss 应用版本       | 支持情况 | 说明           |
| --------------- | ---- | ------------ |
| **5.241.0 及以上** | 支持   | 可使用横幅广告      |
| **低于 5.241.0**  | 不支持  | 无法使用横幅广告 API |

{% hint style="info" %}
**低于 5.241.0 版本的异常处理**

在 Toss App 5.241.0 以下版本中可能会显示空白页面，因此请务必进行异常处理。请使用获取 Toss App 版本的功能进行异常处理。
{% endhint %}

在开发阶段使用测试用广告 ID。

| 类型          | 测试 ID                         |
| ----------- | ----------------------------- |
| 横幅广告 - 列表型  | `ait-ad-test-banner-id`       |
| 横幅广告 - 信息流型 | `ait-ad-test-native-image-id` |

### API 参考

**概览**

| API                    | 说明                                                                             |
| ---------------------- | ------------------------------------------------------------------------------ |
| `TossAds.initialize`   | 初始化横幅广告 SDK。显示广告之前必须调用一次。                                                      |
| `TossAds.attachBanner` | 将横幅广告附加到特定 DOM 元素上。会应用样式预设（theme、tone、variant），并且返回的对象的 `destroy()` 方法可用于移除横幅。 |
| `TossAds.destroyAll`   | 移除所有已初始化的横幅槽位。                                                                 |

每个 API 都可以通过 `isSupported()` 属性来检查当前环境中是否可使用该功能。

**事件流程**

```
调用 TossAds.initialize
↓
onInitialized 回调（初始化完成）
↓
调用 TossAds.attachBanner
↓
onAdRendered 事件（广告渲染完成）
↓
onAdImpression 事件（广告已展示在屏幕上）
↓
onAdViewable 事件（广告展示已记录）
↓
onAdClicked 事件（可选 - 用户点击时）
```

{% hint style="info" %}
**横幅何时会刷新（refresh）？**

当横幅广告同时满足以下两个条件时，SDK 会自动刷新：

* 广告渲染后已过 10 秒以上
* 屏幕的 visibility 从 false 变为 true 时（例如：点击广告后返回，或应用从后台回到前台时）
  {% endhint %}

**横幅广告 SDK 初始化（`initialize`)**

初始化横幅广告 SDK。初始化过程是异步进行的，完成结果会通过回调传递。使用广告前必须先初始化一次，建议只在应用的顶层组件中调用一次。

**签名**

```tsx
TossAds.initialize(options: TossAdsInitializeOptions): void;
```

**参数**

* **options** · `TossAdsInitializeOptions`

  初始化 SDK 时传入的选项对象。可以设置初始化成功/失败的回调。
* **options.callbacks** · `{ onInitialized?: () => void; onInitializationFailed?: (error: Error) => void; }`

  用于定义 SDK 初始化过程中会被调用的回调对象。

  * **options.callbacks.onInitialized** · `() => void`

    在 SDK 初始化成功完成时调用。
  * **options.callbacks.onInitializationFailed** · `(error: Error) => void`

    在 SDK 初始化失败时调用。失败原因会以 `Error` 对象传递。

**TossAdsInitializeOptions**

```tsx
interface TossAdsInitializeOptions {
  callbacks?: {
    onInitialized?: () => void; // SDK 初始化成功时调用
    onInitializationFailed?: (error: Error) => void; // SDK 初始化失败时调用
  };
}
```

**属性**

* isSupported() => boolean

  在当前运行环境中 `TossAds.initialize` 用于确认是否可以使用该功能的函数。在调用广告 SDK 初始化之前，必须先检查是否支持。

**示例**

{% tabs %}
{% tab title="tsx\[React]" %}

```tsx
import { TossAds } from '@apps-in-toss/web-framework';
import { useEffect, useState } from 'react';

function App() {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    // 检查支持情况
    if (!TossAds.initialize.isSupported()) {
      console.warn('无法使用横幅广告功能。');
      return;
    }

    // 初始化 SDK
    TossAds.initialize({
      callbacks: {
        onInitialized: () => {
          console.log('SDK 初始化完成');
          setIsInitialized(true);
        },
        onInitializationFailed: (error) => {
          console.error('SDK 初始化失败：', error);
        },
      },
    });
  }, []);

  return <div>{isInitialized ? '广告准备完成' : '广告准备中...'};
}
```

{% endtab %}

{% tab title="tsx\[ReactNative]" %}

```tsx
import React, { useEffect, useState } from 'react';
import { View, Text, Alert } from 'react-native';
import { TossAds } from '@apps-in-toss/framework';

export default function App() {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    // 检查支持情况
    if (!TossAds.initialize.isSupported()) {
      console.warn('无法使用横幅广告功能。');
      return;
    }

    // 初始化 SDK
    TossAds.initialize({
      callbacks: {
        onInitialized: () => {
          console.log('SDK 初始化完成');
          setIsInitialized(true);
        },
        onInitializationFailed: (error) => {
          console.error('SDK 初始化失败：', error);
          // 在原生环境中可以弹出 Alert 来通知用户/开发者
          Alert.alert('横幅广告初始化失败', String(error?.message ?? error));
        },
      },
    });
  }, []);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>{isInitialized ? '广告准备完成' : '广告准备中...'}</Text>
    </View>
  );
}
```

{% endtab %}
{% endtabs %}

***

**附加横幅广告（`attachBanner`)**

将横幅广告附加到特定 DOM 元素上。会应用样式预设（theme、tone、variant），并且返回的对象的 `destroy()` 方法可用于移除横幅。

`TossAds.initialize`请先调用并初始化 SDK 后再使用。

{% hint style="info" %}
**广告附加指南**

* 附加广告的元素内部需要保持为空。
* 容器的 `width`必须始终与屏幕宽度相同（`100%`).
* 如果作为固定型使用 `height: 96px` 推荐
  {% endhint %}

**签名**

```tsx
TossAds.attachBanner(
  adGroupId: string,
  target: string | HTMLElement,
  options?: TossAdsAttachBannerOptions
): TossAdsAttachBannerResult;
```

**参数**

* **adGroupId** · 必需 · `string`

  广告组级别的 ID。请输入从控制台发放的值。
* **target** · 必需 · `string | HTMLElement`

  要附加广告的 DOM 元素。 `HTMLElement` 可以直接传入对象，也可以传入 CSS 选择器字符串。
* **options** · `TossAdsAttachBannerOptions`

  可用于设置横幅样式及广告事件回调的选项对象。
* **options.theme** · `'auto' | 'light' | 'dark'`

  设置横幅主题。默认值为 `'auto'`，会根据系统深色模式设置自动切换。
* **options.tone** · `'blackAndWhite' | 'grey'`

  设置横幅背景色调。默认值为 `'blackAndWhite'`。
* **options.variant** · `'expanded' | 'card'`

  设置横幅形式。默认值为 `'expanded'`。
* **options.callbacks** · `AttachBannerCallbacks`

  可接收广告生命周期事件的回调对象。

  * **options.callbacks.onAdRendered** · `(payload) => void`

    广告渲染完成时调用。
  * **options.callbacks.onAdImpression** · `(payload) => void`

    当广告变为可在用户屏幕上展示的状态时调用。
  * **options.callbacks.onAdViewable** · `(payload) => void`

    当广告曝光被记录并产生收益时调用。
  * **options.callbacks.onAdClicked** · `(payload) => void`

    广告被点击时调用。
  * **options.callbacks.onNoFill** · `(payload) => void`

    当没有可展示的广告时调用。
  * **options.callbacks.onAdFailedToRender** · `(payload) => void`

    广告渲染失败时调用。

**TossAdsAttachBannerOptions**

```tsx
interface TossAdsAttachBannerOptions {
  theme?: 'auto' | 'light' | 'dark'; // 主题（默认值：'auto'）
  tone?: 'blackAndWhite' | 'grey'; // 背景颜色色调（默认值：'blackAndWhite'）
  variant?: 'card' | 'expanded'; // 横幅形式（默认值：'expanded'）
  callbacks?: TossAdsBannerSlotCallbacks;
}
```

`TossAds.attachBanner` 函数的选项类型。

| 选项          | 类型                            | 默认值               | 说明                                       |
| ----------- | ----------------------------- | ----------------- | ---------------------------------------- |
| `theme`     | `'auto' \| 'light' \| 'dark'` | `'auto'`          | 主题设置。 `auto`会根据系统深色模式自动切换                |
| `tone`      | `'blackAndWhite' \| 'grey'`   | `'blackAndWhite'` | 背景颜色色调                                   |
| `variant`   | `'card' \| 'expanded'`        | `'expanded'`      | 横幅形式。 `card`具有左右内边距 + `border-radius` 应用 |
| `callbacks` | `TossAdsBannerSlotCallbacks`  | -                 | 广告事件回调                                   |

**TossAdsAttachBannerResult**

```tsx
interface TossAdsAttachBannerResult {
  destroy: () => void;
}
```

`TossAds.attachBanner` 函数的返回类型。

* `destroy()`：移除已附加的横幅。建议在组件卸载时调用，以防止内存泄漏。

**TossAdsBannerSlotCallbacks**

```tsx
interface TossAdsBannerSlotCallbacks {
  onAdRendered?: (payload: TossAdsBannerSlotEventPayload) => void;
  onAdViewable?: (payload: TossAdsBannerSlotEventPayload) => void;
  onAdClicked?: (payload: TossAdsBannerSlotEventPayload) => void;
  onAdImpression?: (payload: TossAdsBannerSlotEventPayload) => void;
  onAdFailedToRender?: (payload: TossAdsBannerSlotErrorPayload) => void;
  onNoFill?: (payload: { slotId: string; adGroupId: string; adMetadata: {} }) => void;
}
```

横幅广告事件回调。

* `onAdRendered`: 广告已渲染。
* `onAdImpression`: 广告已展示在屏幕上。
* `onAdViewable`: 广告曝光已被记录。（产生收益的时点）
* `onAdClicked`: 用户点击了广告。
* `onAdFailedToRender`: 广告渲染失败。
* `onNoFill`: 没有可展示的广告。

**TossAdsBannerSlotEventPayload**

```tsx
interface TossAdsBannerSlotEventPayload {
  slotId: string;
  adGroupId: string;
  adMetadata: {
    creativeId: string;
    requestId: string;
  };
}
```

横幅广告事件负载。

* `slotId`：生成的槽位 ID
* `adGroupId`：广告组 ID
* `adMetadata`：广告元数据（creativeId、requestId）

**TossAdsBannerSlotErrorPayload**

```tsx
interface TossAdsBannerSlotErrorPayload {
  slotId: string;
  adGroupId: string;
  adMetadata: {};
  error: {
    code: number;
    message: string;
    domain?: string;
  };
}
```

横幅广告错误负载。

**返回值**

`TossAdsAttachBannerResult` 返回对象。可以调用该对象的 `destroy()` 方法来移除横幅。

**属性**

* isSupported() => boolean

  在当前运行环境中 `TossAds.attachBanner` 用于确认是否可以使用该功能的函数。在附加横幅广告之前必须先检查支持情况。

**示例**

```tsx
import { TossAds, TossAdsAttachBannerOptions } from '@apps-in-toss/web-framework';
import { useCallback, useEffect, useRef, useState } from 'react';

function BannerAdComponent({ adGroupId }: { adGroupId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const { isInitialized, attachBanner } = useTossBanner();

  useEffect(() => {
    if (!isInitialized || !containerRef.current) return;

    // 附加横幅
    const attached = attachBanner(adGroupId, containerRef.current, {
      theme: 'auto', // 根据系统设置自动切换
      tone: 'blackAndWhite', // 黑白背景
      variant: 'expanded', // 全宽展开形式
      callbacks: {
        onAdRendered: (payload) => {
          console.log('广告渲染完成：', payload.slotId);
        },
        onAdImpression: (payload) => {
          console.log('广告已展示：', payload.slotId);
        },
        onAdViewable: (payload) => {
          console.log('广告曝光已记录（产生收益）：', payload.slotId);
        },
        onAdClicked: (payload) => {
          console.log('广告被点击：', payload.slotId);
        },
        onNoFill: (payload) => {
          console.warn('没有可展示的广告：', payload.slotId);
        },
        onAdFailedToRender: (payload) => {
          console.error('广告渲染失败：', payload.error.message);
        },
      },
    });

    // 清理：调用 destroy
    return () => {
      attached?.destroy();
    };
  }, [isInitialized, adGroupId, attachBanner]);

  // 固定型横幅：width 100% + height 96px
  return <div ref={containerRef} style={{ width: '100%', height: '96px' }} />;
}

// 用于初始化及附加横幅的自定义 Hook
function useTossBanner() {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    if (isInitialized) return;

    TossAds.initialize({
      callbacks: {
        onInitialized: () => setIsInitialized(true),
        onInitializationFailed: (error) => {
          console.error('Toss Ads SDK initialization failed:', error);
        },
      },
    });
  }, [isInitialized]);

  const attachBanner = useCallback(
    (adGroupId: string, element: HTMLElement, options?: TossAdsAttachBannerOptions) => {
      if (!isInitialized) return;
      return TossAds.attachBanner(adGroupId, element, options);
    },
    [isInitialized],
  );

  return { isInitialized, attachBanner };
}
```

横幅广告错误负载。

***

**移除所有横幅槽位（`destroyAll`)**

移除所有已初始化的横幅槽位。

**签名**

```tsx
TossAds.destroyAll(): void;
```

**属性**

* isSupported() => boolean

  在当前运行环境中 `TossAds.destroyAll` 用于确认是否可以使用该功能的函数。可在整体移除横幅广告实例之前，用于检查支持情况。

**示例**

```tsx
// 页面跳转时移除所有横幅
useEffect(() => {
  return () => {
    TossAds.destroyAll();
  };
}, []);
```

***

### 使用模式

**初始化时机**

建议在应用启动时只初始化一次 SDK。推荐在以下时机进行初始化：

* 应用顶层组件（App.tsx）挂载时
* 在进入第一个展示广告的页面之前

```tsx
// ✅ 好例子：在应用启动时初始化
function App() {
  useEffect(() => {
    if (TossAds.initialize.isSupported()) {
      TossAds.initialize({
        callbacks: {
          onInitialized: () => console.log('SDK 准备完成'),
        },
      });
    }
  }, []);

  return <Router />;
}

// ❌ 坏例子：每个组件都重复初始化
function BannerComponent() {
  useEffect(() => {
    TossAds.initialize({
      /* ... */
    }); // 尝试重复初始化
  }, []);
}
```

**容器尺寸设置**

广告容器必须设置为正确的尺寸。

```tsx
// ✅ 固定型：推荐 width 100% + height 96px
<div ref={containerRef} style={{ width: '100%', height: '96px' }} />

// ✅ 内联型：width 100% + 不指定 height
<div ref={containerRef} style={{ width: '100%' }} />

// ❌ 错误示例：width 为固定值
<div ref={containerRef} style={{ width: '320px', height: '96px' }} />
```

**内存管理**

组件卸载时需要移除横幅，以防止内存泄漏。

`TossAds.attachBanner`是 `destroy()` 由于会返回包含该方法的对象，因此在清理时调用它即可。

```tsx
useEffect(() => {
  if (!isInitialized || !containerRef.current) return;

  // 附加横幅
  const attached = TossAds.attachBanner(adGroupId, containerRef.current, {
    callbacks: { ... },
  });

  // 清理：调用 destroy
  return () => {
    attached?.destroy();
  };
}, [isInitialized, adGroupId]);
```

**错误处理**

请始终提供 `onInitializationFailed`和 `onAdFailedToRender` 回调，以便应对错误。

```tsx
TossAds.initialize({
  callbacks: {
    onInitialized: () => {
      console.log('初始化成功');
    },
    onInitializationFailed: (error) => {
      console.error('初始化失败：', error);
      // 向用户提供适当的反馈
    },
  },
});

TossAds.attachBanner(adGroupId, element, {
  callbacks: {
    onAdFailedToRender: (payload) => {
      console.error('广告渲染失败：', payload.error.message);
      // 显示替代内容或重试
    },
  },
});
```

***

**可复用的自定义 Hook**

在多个页面使用横幅广告时，拆分为自定义 Hook 会很方便。

**useTossBanner**

这是一个同时处理 SDK 初始化和横幅挂载的 Hook。

```tsx
import { useCallback, useEffect, useRef, useState } from 'react';
import { TossAds, type TossAdsAttachBannerOptions } from '@apps-in-toss/web-framework';

export function useTossBanner() {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    if (isInitialized) return;

    TossAds.initialize({
      callbacks: {
        onInitialized: () => setIsInitialized(true),
        onInitializationFailed: (error) => {
          console.error('Toss Ads SDK initialization failed:', error);
        },
      },
    });
  }, [isInitialized]);

  const attachBanner = useCallback(
    (adGroupId: string, element: HTMLElement, options?: TossAdsAttachBannerOptions) => {
      if (!isInitialized) return;
      return TossAds.attachBanner(adGroupId, element, options);
    },
    [isInitialized],
  );

  return { isInitialized, attachBanner };
}
```

**使用示例**

```tsx
import { useRef, useEffect } from 'react';

function MyPage() {
  const bannerRef = useRef<HTMLDivElement>(null);
  const { isInitialized, attachBanner } = useTossBanner();

  useEffect(() => {
    if (!isInitialized || !bannerRef.current) return;

    const attached = attachBanner('your-ad-group-id', bannerRef.current, {
      theme: 'auto',
      tone: 'blackAndWhite',
      variant: 'expanded',
      callbacks: {
        onAdRendered: (payload) => console.log('广告渲染：', payload.slotId),
        onAdImpression: () => console.log('广告曝光'),
      },
    });

    return () => {
      attached?.destroy();
    };
  }, [isInitialized, attachBanner]);

  return (
    <div>
      <h1>我的页面</h1>
      {/* 固定式横幅：width 100% + height 96px */}
      <div ref={bannerRef} style={{ width: '100%', height: '96px' }} />

  );
}
```

> **参考**: `useTossBanner`即使在多个组件中调用也很安全。已初始化时不会尝试重复初始化。

***

### 广告政策 <a href="#policy" id="policy"></a>

#### Toss Ads SSP 政策 <a href="#ssp" id="ssp"></a>

请务必遵守以下政策。违规时，广告展示可能会受限。

**即使本政策未明确规定，刻意诱导广告展示、点击、效果，或造成用户误解的行为也可能被视为违反政策。**

如因违反政策而导致服务终止，所有合作方都必须遵守服务终止政策。

| 类型         | 禁止行为                                                      | 具体示例                                                                                                                                                                                                                                                                                                    | 政策标准                                                                                                            |
| ---------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| UI/UX 质量下降 | 使广告与内容的区分不清，诱导用户在与其意图无关的情况下消费或点击广告，或以影响正常服务使用的方式构建 UI 的行为 | <p></p><ul><li>用“推荐服务”“金融技巧”等伪装广告</li><li>修改 Toss Ads 指南之外的广告单元颜色·字体</li><li>擅自修改广告标题·标签·CTA 文案及设计</li><li>将广告放置在用户交互元素（按钮、游戏区域等）附近，造成非预期点击的结构</li><li>在同一屏幕上放置 2 个以上相同格式的广告时</li><li>使用户难以正常关闭页面或返回上一页的死路（Dead-end）结构</li><li>将广告与服务 CTA 的功能构建得让用户难以区分的结构</li><li>让正常使用服务所需的 CTA 难以被识别或访问的结构</li></ul> | <p></p><ul><li>广告必须保留 “Ad” 标识</li><li>所有广告 UI 都必须使用 web-base 标准组件</li><li>禁止构成会人为诱导广告效果或损害用户体验的 UI/UX</li></ul> |
| 篡改广告调用行为   | 更改或绕过 SDK 的默认事件流程或广告调用方式的行为                               | <ul><li>篡改 SDK Click / Impression 事件</li><li>不经过广告 SDK，使用自有逻辑调用广告，或绕过 SDK 事件进行实现的情况</li><li>通过阻止或异常控制 Back 按钮，妨碍用户正常关闭页面或返回上一页的情况</li></ul>                                                                                                                                                             | <p></p><ul><li>禁止篡改 SDK 默认事件（Click / Impression）结构</li><li>不可调用 SDK 外部 API</li></ul>                            |
| 异常流量及效果操纵  | 通过自动化或人为方式扭曲流量及广告效果的行为                                    | <ul><li>定期刷新广告区域</li><li>人为产生效果（点击、曝光等）的活动</li></ul>                                                                                                                                                                                                                                                    | <ul><li>如确认基于流量质量的异常模式，广告限制、处罚、结算暂缓</li></ul>                                                                   |
| 奖励·参与型点击引导 | 在广告点击的同时提供奖励或福利的行为                                        | <ul><li>“点击广告立即提供奖励”</li><li>“点击广告即可获得积分”</li></ul>                                                                                                                                                                                                                                                     | <ul><li>禁止将广告消费与奖励直接关联的结构</li><li>禁止点击奖励性质文案·活动联动</li></ul>                                                     |
| 隐藏广告或重叠    | 故意隐藏广告或被其他 UI 元素遮挡，使用户难以明确感知广告存在的行为                       | <p>• 透明广告 </p><p>• 在其他卡片 UI 后插入广告 DOM</p>                                                                                                                                                                                                                                                               | • 广告的展示状态必须能够清楚确认                                                                                               |

***

#### **UX / Product Principle 运营原则**

广告也应遵循 Toss 的 UX 原则。

| **Toss Principle**             | **适用标准**               | **示例**                 |
| ------------------------------ | ---------------------- | ---------------------- |
| **Simplicity**                 | 广告应当清晰明了，无需额外说明即可理解其含义 | 使用“立即查看”“查看广告”等明确的 CTA |
| **Clear Action**               | 用户应能预测点击广告后会发生什么       | 在重定向·新窗口打开时显示提示文案      |
| **No Deception (UX Red Rule)** | 广告不应在意外的时机、形式或位置出现     | 禁止在进入服务后立即展示全屏横幅       |
| **Value First**                | 广告不应妨碍客户的服务目标          | 禁止在支付/开户流程中插入广告        |

#### 使用限制及制裁措施

如 App in Toss 广告版位或服务违反本政策，可能会受到制裁。

***

**限制流程**

限制措施原则上会根据违规行为的累积程度分阶段适用。不过，根据违规类型或严重程度，即使单次违规也可能立即适用 30 天使用限制或永久使用限制。

※ 同时确认的违规，不论违规槽位数量，均按 1 次违规处理。之后若另有违规被确认，违规次数将累计。

<figure><img src="/files/9f8d3946f245bba10ca998e0b391b6195ef94273" alt=""><figcaption></figcaption></figure>

***

**不当收益处理**

因政策违规、无效流量或其他不正当方式产生的收益，可能被视为不当收益。

一旦确认不当收益，相关金额可能会被暂缓支付或拒绝支付，且已支付金额也可能同样被追缴。

***

**申诉流程**

* 若收到使用限制通知 **可在 30 天内申请申诉**可以。
  * 申诉资料可通过 Channel Talk 提交。
* 提交的资料将依据内部标准进行审核，必要时可能会要求补充资料。
  * 审核可能需要约 1 个工作周。
  * 对于申诉申请 **将重点审查制裁是否适当**，且仅仅修改违规事项或提交防止复发计划，并不能解除制裁。
  * 若通过提交的申诉资料确认，不成立作为制裁依据的违规事实，或制裁判断存在明显错误，则制裁可能会被解除。
* 若屡次或严重违规，服务使用可能会被永久限制。

***

**测试**

开发阶段务必使用测试广告 ID。使用真实广告 ID 进行测试将被视为违反政策，可能受到不利影响。

WebView 横幅广告测试 ID 为 [开始使用](#시작하기)可在此处查看。

发布前请务必确认以下事项。

* 确认广告是否正常加载。
* 确认点击后是否跳转到预期页面。
* 确认返回操作是否正常工作。
* 确认不会干扰支付或认证流程。

***

### 常见问题

<details>

<summary>\"This feature is not supported in the current environment\" 会发生错误</summary>

1. 请确认是否在 Toss 应用环境中运行。
2. 请确认应用版本是否满足要求。
3. `isSupported()` 请先通过方法确认是否支持。

</details>

<details>

<summary>SDK 初始化失败了</summary>

1. `onInitializationFailed` 请在回调中查看具体错误消息。
2. 请检查网络连接状态。
3. 已初始化的情况下 `[toss-ad] Already initialized.` 会发生错误。初始化在应用中只能进行一次，因此请全局管理状态以防止重复调用。

</details>

<details>

<summary>调用了 TossAds.attachBanner 但广告未显示</summary>

1. `TossAds.initialize`请先调用 `onInitialized` 并确认是否收到了回调。
2. 请确认 DOM 元素是否确实存在。React 中， `useEffect`在 `ref.current`为 `null`不是 null。
3. `onAdFailedToRender` 或 `onNoFill` 请在回调中确认错误。
4. `adGroupId`请确认 ID 是否正确。需要使用在 App in Toss 控制台中获取的 ID。

</details>

<details>

<summary>会发生 “[toss-ad] Failed to find target element” 错误</summary>

1. 请确认 DOM 元素是否确实存在。
2. 请确认选择器字符串是否正确。例如 `#banner`, `.ad-container`可以这样传入。
3. React 中 `ref.current`为 `null`不是 null。

</details>

<details>

<summary>广告已显示但回调未被调用</summary>

1. `callbacks` 将 option `TossAds.attachBanner`传给
2. 请确认是否已传入。
3. 请确认控制台是否输出错误。

</details>

<details>

<summary>我想移除横幅</summary>

`TossAds.attachBanner`由 返回的对象的 `destroy()`调用 `TossAds.destroyAll`如果需要移除整个页面的横幅槽位，可以使用

</details>

<details>

<summary>沙盒中应用内广告功能无法使用</summary>

沙盒中不支持应用内广告功能。

不便之处敬请谅解，请通过控制台内的二维码进行测试。

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/common/monetization/iaa/web-banner.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
