> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aiderx.io/llms.txt
> Use this file to discover all available pages before exploring further.

# A/B 테스트

> 사용자별로 광고 구성을 나누고, 버킷별 노출·클릭·전환과 비용 지표를 비교합니다.

A/B 테스트는 같은 기간에 서로 다른 광고 구성을 제공하고 성과를 비교하는 방법입니다. A2에서는 광고 단위의 사용자를 버킷으로 나누고, 버킷마다 광고 항목과 선택 방식을 설정할 수 있습니다.

버킷은 비교할 구성을 담는 그룹입니다. 예를 들어 두 버킷에 서로 다른 광고 항목을 넣고 사용자 비중을 `1:1`로 설정해 클릭률이나 전환당 비용을 비교합니다.

> [!NOTE]
>
> 이 페이지는 A2 안의 광고 항목 구성을 비교하는 실험을 다룹니다. 기존 시스템과 A2 사이에서 요청을 나누는 방식, 기존 시스템의 결과를 합쳐 비교하는 방식은 적용 전에 별도로 정합니다.

## 시작하기 전에

* **접속 정보:** [API 주소와 액세스 토큰](https://docs.aiderx.io/development/ko/api-access-and-auth.md)을 준비합니다. 실험 조회·지표 조회에는 실험 읽기 권한, 생성·수정·삭제에는 쓰기 권한이 필요합니다.
* **대상과 광고 항목:** 운영 담당자와 비교할 광고 단위 및 광고 항목을 준비하고 각각의 ID를 확인합니다. 광고 항목이 해당 광고 단위에서 송출 가능한지도 확인합니다. 용어와 관계는 [주요 개념](https://docs.aiderx.io/guides/platform-overview/ko/core-concepts.md)에서 확인합니다.
* **사용자 ID:** 광고 요청에 같은 사용자의 ID를 일관되게 전달합니다. 요청 필드는 [광고 요청 API](https://docs.aiderx.io/ko/0.5.0/decision/ad-serving/serving-an-ad.md)에서 확인합니다.
* **데이터 전달:** [상품 카탈로그](https://docs.aiderx.io/development/ko/catalog.md), [사용자 행동 로그](https://docs.aiderx.io/development/ko/user-events.md), [광고 이벤트 추적](https://docs.aiderx.io/development/ko/ad-events-and-logs.md)의 전달 상태를 확인합니다.

Ad Manager에서 설정한다면 [A/B 실험 운영](https://docs.aiderx.io/guides/about-a2/ko/experiments.md)을 참고합니다.

## 비교 기준 정하기

실험을 만들기 전에 운영 담당자와 다음 항목을 정합니다.

| 항목 | 정할 내용 |
| - | - |
| 비교 대상 | 광고 단위, 버킷별 광고 항목과 선택 방식을 정합니다. |
| 주요 지표 | 클릭률, 전환율, CPA 등 판단에 사용할 지표를 정합니다. |
| 전환 | 구매·가입 등 목표 행동과 완료 시점, 어떤 광고에 연결할지 정합니다. |
| 비용과 매출 | 비용을 기록하는 방식과 매출의 단위를 맞춥니다. |
| 기간과 비중 | 시작·종료 시각, 시간대, 버킷별 사용자 비중을 정합니다. |

클릭률을 비교하려면 두 버킷에서 노출과 클릭을 같은 조건으로 기록합니다. CPA를 비교하려면 같은 전환 정의를 사용하고 비용이 집계되는지 확인합니다. 매출을 비교하려면 전환의 `conversion_data.sales`도 전달합니다.

주요 지표는 결과를 판단하기 위한 기준입니다. 실험 생성 요청에 별도의 KPI 필드를 넣지 않습니다.

### 지표별 필요한 데이터

| 비교 지표 | 먼저 확인할 데이터 |
| - | - |
| 클릭률 `ctr` | 같은 노출 추적 기준의 `imp`와 클릭 `clk`가 집계되는지 확인합니다. |
| 전환율 `cvr` | 같은 정의의 클릭 `clk`와 전환 `conv`가 집계되는지 확인합니다. A2의 전환율은 전환 ÷ 클릭 × 100입니다. |
| 전환당 비용 `cpa` | 전환과 광고 비용이 집계되는지 확인합니다. 비용 계산에는 버킷 지표의 `pub_revenue`를 사용합니다. |
| 매출 `sales` | 실험 버킷의 전환에 `conversion_data.sales`를 같은 단위로 전달하는지 확인합니다. |

같은 광고 단위·기간에서 비교하고, 비교하려는 설정 외의 조건은 유지합니다. 운영 중 설정을 바꾸면 변경 시각을 기록해 변경 전후 결과를 구분합니다.

## 사용자 배정

A2는 실험 ID와 광고 요청의 사용자 ID를 사용해 버킷을 결정합니다. 실험의 버킷 구성이 같다면 같은 사용자는 같은 버킷에 배정됩니다. 요청마다 버킷을 다시 무작위로 고르는 방식으로 구현하지 않습니다.

* 같은 사용자의 ID를 요청마다 바꾸지 않습니다.
* 사용자 ID가 없는 요청에는 버킷 배정이 적용되지 않습니다. 실험의 광고 항목이 일반 광고 경쟁에 포함되어 송출될 수 있으며, 이 요청의 성과는 실험 버킷 지표에 집계되지 않습니다.
* 실험 도중 버킷 비중이나 구성을 바꾸면 같은 사용자의 배정이 달라질 수 있으므로 변경 시점과 내용을 기록합니다.
* `line_item_rotate: "random"`은 배정된 버킷 안에서 광고 항목을 고르는 설정입니다. 사용자 버킷 배정과는 별개입니다.

`proportion`은 상대 비중입니다. `1:1`은 두 버킷에 같은 비중으로 사용자를 배정한다는 뜻이며, 실제 노출·클릭 수가 정확히 반씩 나뉜다는 뜻은 아닙니다.

## 설정 필드

### 실험

| 필드 | 필수 여부 | 설명 |
| - | - | - |
| `name` 문자열 | 필수 | 실험 이름입니다. |
| `target_type` 문자열 | 필수 | 이 가이드의 광고 단위 실험에는 `ad_unit`을 사용합니다. |
| `target_id` UUID 문자열 | 필수 | 비교할 광고 단위의 ID입니다. |
| `start_date` 날짜·시간 문자열 | 필수 | 시작 시각입니다. `2026-11-06T00:00:00+09:00`처럼 시간대를 포함합니다. |
| `end_date` 날짜·시간 문자열 | 필수 | 종료 시각입니다. 시작 시각보다 뒤여야 합니다. |
| `buckets` 객체 배열 | 필수 | 버킷을 1\~15개 설정합니다. 두 구성을 비교할 때는 두 개를 넣습니다. |
| `status` 문자열 | 선택 | `inactive`, `active`, `completed`를 사용합니다. 새 실험은 `inactive`로 생성합니다. 시작할 때 수정 API로 `active`로 바꿉니다. |
| `ext` JSON 값 | 선택 | 실험에 부가 정보를 저장합니다. |

### 버킷 `buckets[]`

| 필드 | 필수 여부 | 설명 |
| - | - | - |
| `name` 문자열 | 필수 | 버킷 이름입니다. |
| `proportion` 0 이상의 정수 | 필수 | 사용자 배정의 상대 비중입니다. 참여할 버킷에는 양수를 사용합니다. |
| `line_items` 객체 배열 | 필수 | 버킷에서 비교할 광고 항목을 최대 10개 넣습니다. 송출할 광고 항목을 하나 이상 넣습니다. |
| `line_item_rotate` 문자열 | 선택 | `sequential`, `weighted`, `random`, `score_aware` 중에서 설정합니다. 기본값은 `random`입니다. |
| `id` 정수 | 수정 시 필요 | 생성할 때는 생략합니다. 기존 버킷을 수정할 때는 응답에서 받은 ID를 그대로 넣습니다. |
| `is_deleted` 불리언 | 선택 | 기존 버킷을 삭제할 때 `true`로 보냅니다. 기본값은 `false`입니다. |

각 광고 항목에는 다음 값을 넣습니다.

| 필드 | 필수 여부 | 설명 |
| - | - | - |
| `line_items[].lid` UUID 문자열 | 필수 | 광고 항목의 ID입니다. |
| `line_items[].weight` 0 이상의 정수 | 필수 | 항목 선택에 사용할 상대 가중치입니다. 예제는 항목마다 `1`을 사용합니다. |

버킷의 `gating`, `gating_policy`와 광고 항목의 `gating` 등 고급 설정은 [실험 생성 API](</ko/0.5.0/data management/experiment/create-an-experiment>)의 스키마를 확인합니다. 비교하려는 설정 외의 조건은 동일하게 유지합니다.

## API로 실험 만들기

**1. 요청 본문 작성**

아래 내용을 `experiment-create.json`으로 저장합니다. 광고 단위 ID, 두 광고 항목 ID, 이름과 기간을 실제 값으로 바꿉니다. 생성 요청에는 실험 ID와 버킷 ID를 넣지 않습니다.

**2. 실험 생성**

생성 API를 호출합니다. HTTP `201` 응답에서 실험의 `id`와 `buckets[].id`를 보관합니다. 생성한 실험은 `inactive` 상태입니다.

**3. 설정 확인**

조회 API로 대상, 기간, 버킷별 광고 항목과 비중을 확인한 뒤 실험을 시작합니다.

```json experiment-create.json theme={null}
{
  "name": "광고 구성 비교",
  "target_type": "ad_unit",
  "target_id": "11111111-1111-4111-8111-111111111111",
  "start_date": "2026-11-06T00:00:00+09:00",
  "end_date": "2026-11-13T00:00:00+09:00",
  "buckets": [
    {
      "name": "control",
      "proportion": 1,
      "line_item_rotate": "random",
      "line_items": [
        { "lid": "22222222-2222-4222-8222-222222222222", "weight": 1 }
      ]
    },
    {
      "name": "variant",
      "proportion": 1,
      "line_item_rotate": "random",
      "line_items": [
        { "lid": "33333333-3333-4333-8333-333333333333", "weight": 1 }
      ]
    }
  ]
}
```

```bash theme={null}
curl -i -X POST "<A2_API_URL>/api/manager/experiments" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data-binary @experiment-create.json
```

`<experiment_id>`를 응답의 실험 ID로 바꾸어 조회합니다.

```bash theme={null}
curl "<A2_API_URL>/api/manager/experiments/<experiment_id>" \
  -H "Authorization: Bearer <token>"
```

API Reference: [생성](</ko/0.5.0/data management/experiment/create-an-experiment>) · [조회](</ko/0.5.0/data management/experiment/get-an-experiment>) · [목록](</ko/0.5.0/data management/experiment/list-experiments>)

## 실험 시작과 종료

상태는 `inactive` → `active` → `completed` 순서로 변경합니다. `active` 상태이면서 현재 시각이 시작·종료 기간 안에 있을 때 실험이 적용됩니다. 같은 대상(`target_type`과 `target_id`의 조합)에는 `active` 실험을 하나만 둘 수 있습니다.

광고 단위 실험과 상위 게재 위치(`placement`) 실험은 대상이 달라 동시에 활성화될 수 있습니다. 같은 요청에 적용 가능한 실험이 겹치면 A2는 실험 UUID가 가장 작은 하나만 적용합니다. 비교할 트래픽에 상위 게재 위치 실험이 겹치지 않는지도 확인합니다.

수정 API는 전체 설정을 받습니다. `status`만 보내지 않고 이름, 대상, 기간, 전체 버킷 구성을 함께 보냅니다. 다음은 앞선 실험에서 반환된 버킷 ID가 `1`, `2`인 경우의 시작 요청입니다. 실제 응답에서 받은 ID와 설정으로 바꿉니다.

```json experiment-update.json theme={null}
{
  "name": "광고 구성 비교",
  "target_type": "ad_unit",
  "target_id": "11111111-1111-4111-8111-111111111111",
  "start_date": "2026-11-06T00:00:00+09:00",
  "end_date": "2026-11-13T00:00:00+09:00",
  "status": "active",
  "buckets": [
    {
      "id": 1,
      "name": "control",
      "proportion": 1,
      "line_item_rotate": "random",
      "line_items": [
        { "lid": "22222222-2222-4222-8222-222222222222", "weight": 1 }
      ]
    },
    {
      "id": 2,
      "name": "variant",
      "proportion": 1,
      "line_item_rotate": "random",
      "line_items": [
        { "lid": "33333333-3333-4333-8333-333333333333", "weight": 1 }
      ]
    }
  ]
}
```

```bash theme={null}
curl -i -X PUT "<A2_API_URL>/api/manager/experiments/<experiment_id>" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data-binary @experiment-update.json
```

* **종료:** 최신 설정을 조회한 뒤 `status`를 `completed`로 바꾸어 전체 설정을 다시 보냅니다. 종료 시각이 지나면 트래픽에 적용되지 않지만 상태가 자동으로 `completed`로 바뀌지는 않습니다.
* **재시작:** 종료한 실험을 다시 시작할 수 없습니다. 새 비교는 새 실험으로 만듭니다.
* **버킷 수정:** 기존 버킷 ID를 유지합니다. 삭제할 버킷은 본문에서 빼지 않고 `is_deleted: true`로 보냅니다. 새 버킷은 ID를 생략합니다. 삭제한 ID를 포함해 한 실험에서 발급할 수 있는 버킷 ID는 총 15개입니다.
* **실험 삭제:** `inactive` 실험만 삭제할 수 있습니다. 삭제 API가 성공하면 HTTP `204`를 반환합니다.

```bash theme={null}
curl -i -X DELETE "<A2_API_URL>/api/manager/experiments/<experiment_id>" \
  -H "Authorization: Bearer <token>"
```

API Reference: [수정](</ko/0.5.0/data management/experiment/update-an-experiment>) · [삭제](</ko/0.5.0/data management/experiment/delete-an-experiment>)

## 실험 적용 확인

실험 설정을 저장한 뒤에는 실제 서비스 요청에서 광고가 반환된 응답으로 배정 결과를 확인합니다. 요청에는 같은 사용자의 ID를 일관되게 넣습니다. 광고가 반환되지 않는 경우에는 [광고 송출 (고급)](https://docs.aiderx.io/development/ko/serving-ad.md#no-ad-checklist)의 광고 없음 확인 항목을 먼저 확인합니다.

| 확인 위치 | 확인할 값 |
| - | - |
| `ext.ab_test.experiment_id` | 적용하려는 실험의 `id`와 같은지 확인합니다. |
| `ext.ab_test.bucket_id` | 실험 설정의 `buckets[].id` 중 하나인지 확인합니다. |

같은 사용자·실험·버킷 구성에서 같은 버킷이 반환되는지 확인합니다. 응답 구조는 [광고 요청 API](https://docs.aiderx.io/ko/0.5.0/decision/ad-serving/serving-an-ad.md)를 참고합니다. 배정 정보가 없으면 사용자 ID·상태·기간·대상을, 다른 실험 ID가 보이면 광고 단위와 상위 게재 위치의 실험 중첩을 확인합니다.

이 정보는 요청에 배정된 실험과 버킷을 확인하는 수단입니다. 광고 선택 결과나 노출·클릭·전환의 최종 집계까지 증명하지는 않으므로 아래 버킷 지표도 대조합니다. `on_ad_response`에서 확인용 요청을 추가하면 노출도 기록되므로 실제 서비스 요청 기록을 기준으로 확인합니다.

## 결과 조회

[실험 버킷 지표 API](</ko/0.5.0/data management/metric/get-experiment-bucket-metrics>)로 같은 기간의 버킷별 성과를 조회합니다. 다음 내용을 `experiment-metrics.json`으로 저장하고 실험 ID와 기간을 바꿉니다.

```json experiment-metrics.json theme={null}
{
  "experiment_id": "44444444-4444-4444-8444-444444444444",
  "from_datetime": "2026-11-06T00:00:00+09:00",
  "to_datetime": "2026-11-13T00:00:00+09:00",
  "interval": "daily",
  "timezone": "Asia/Seoul"
}
```

```bash theme={null}
curl -X POST "<A2_API_URL>/api/manager/metric/experiment" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data-binary @experiment-metrics.json
```

| 필드 | 필수 여부 | 설명 |
| - | - | - |
| `experiment_id` UUID 문자열 | 필수 | 조회할 실험의 ID입니다. |
| `from_datetime` 날짜·시간 문자열 | 필수 | 조회 시작 시각을 포함합니다. 시간대를 넣습니다. |
| `to_datetime` 날짜·시간 문자열 | 필수 | 조회 종료 시각은 포함하지 않습니다. 시작 시각보다 뒤여야 합니다. |
| `interval` 문자열 | 선택 | `hourly`, `daily`, `weekly`, `monthly`를 사용합니다. 기본값은 `daily`입니다. 한 번에 조회할 수 있는 범위는 각각 최대 7일, 60일, 90일, 90일입니다. |
| `timezone` 문자열 | 선택 | 시간 구간을 나눌 IANA 시간대입니다. 기본값은 `Asia/Seoul`입니다. |

응답의 `total`은 조회 기간의 버킷별 합계이며, `timeseries`는 시간 구간별 지표와 광고 항목별 내역입니다. `bucket_id`를 실험 설정의 버킷 ID와 연결합니다.

| 지표 | 의미 |
| - | - |
| `impression`, `click`, `conversion` | 노출·클릭·전환 횟수를 반환합니다. |
| `sales` | 전환에 전달한 매출의 합계를 반환합니다. |
| `pub_revenue` | A2에 집계된 광고 비용 값을 반환하며, 아래 비용 지표의 계산 기준으로 사용합니다. |
| `ctr` | 클릭 ÷ 노출 × 100으로 계산한 클릭률(%)을 반환합니다. |
| `cvr` | 전환 ÷ 클릭 × 100으로 계산한 전환율(%)을 반환합니다. |
| `cpa` | `pub_revenue` ÷ 전환으로 계산한 전환당 비용을 반환합니다. |
| `cpc`, `cpm` | 각각 `pub_revenue` ÷ 클릭, `pub_revenue` ÷ 노출 × 1,000으로 계산합니다. |
| `cps` | `pub_revenue` ÷ `sales`로 계산합니다. |

> [!WARNING]
>
> 분모가 0이면 계산 지표도 0을 반환합니다. 전환이나 비용이 수집되지 않은 상태의 CPA `0`을 성과가 좋다는 뜻으로 해석하지 않습니다. CPA를 비교하기 전에 비용 집계와 전환 전달을 확인합니다.

전환은 노출·클릭보다 늦게 발생할 수 있으므로 전환의 발생 시각과 조회 기간도 함께 확인합니다. 버킷 지표를 해당 기간에 노출된 사용자의 모든 후속 전환을 포함하는 누적값으로 해석하지 않습니다. 실험 기간 밖에서 발생한 전환까지 측정해야 한다면 원래 실험의 지표에 포함되는 범위를 별도로 확인합니다.

실험 전 정한 주요 지표로 비교하되, 같은 기간의 노출·클릭·전환과 버킷 비중도 함께 확인합니다. A2는 통계적 유의성을 계산하거나 성과가 좋은 버킷을 자동으로 선택하지 않습니다. 결과를 바탕으로 다음 적용 범위와 설정을 정합니다.

## 실험이 적용되지 않을 때

* 실험 상태가 `active`이고 현재 시각이 설정한 기간 안인지 확인합니다.
* 광고 요청의 광고 단위 ID와 실험의 `target_id`가 같은지 확인합니다.
* 광고 요청에 사용자 ID가 포함되어 있는지 확인합니다. ID가 없으면 실험 광고 항목도 일반 경쟁으로 송출될 수 있지만 버킷 지표에는 집계되지 않습니다.
* 광고 단위와 상위 게재 위치의 실험이 겹치는지 확인합니다. 요청에 적용 가능한 실험 중 UUID가 가장 작은 하나만 적용됩니다.
* 버킷 비중과 광고 항목, 해당 광고 단위의 송출 조건을 확인합니다.
* 지표가 비어 있다면 조회 기간·시간대와 [광고 이벤트 추적](https://docs.aiderx.io/development/ko/ad-events-and-logs.md)을 확인합니다. 설정 조회 성공만으로 실제 트래픽 적용과 집계까지 확인한 것은 아닙니다.

[검증과 문제 해결](https://docs.aiderx.io/development/ko/integration-verification-and-troubleshooting.md)에서 데이터 전달 상태를 함께 확인합니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.