# AI 상품 추천: 데이터 호출형(이지웰)

## **1. 시스템 구조도**

<figure><img src="https://files.helpdocs.io/p92xn84cjv/articles/n4klfe09xw/1711528840377/image.png" alt=""><figcaption></figcaption></figure>

***

## **2. 개요**

* 스크립트 LOAD 완료된 후 원하는 시점에 추천 상품 목록을 가져와서 사용할 수 있습니다.
* 추천에 필요한 데이터만 전달 하는것으로 고객사 화면에 맞는 디자인을 구성 하셔야 됩니다.

***

## **3. 연동 방식**

* 고객사에서 그루비에서 추천 상품 요청 시 데이터를 바로 전달합니다.
* 비동기식이라 요청이 느려졌을 경우 html에 추천 리스트를 표현하지 못하는 경우가 존재합니다.

```javascript
groobee.getGroobeeRecommendAsync("캠페인키", 타임아웃).then( data =>  { console.log(data); } );
```

***

## 4. 추천 상품 조회(getGroobeeRecommendAsync)

* 고객사에서 추천 상품 요청 시 전달해주는 함수입니다.
* **정의**
  * 역할: 추천 상품 조회
  * 함수명: groobee.getGroobeeRecommendAsync
* **파라미터**

<table><thead><tr><th width="155.140625">항목</th><th width="84.67578125">타입</th><th width="85.08203125">필수</th><th>설명</th></tr></thead><tbody><tr><td>campaignKey</td><td>string</td><td>  Y</td><td><strong>캠페인키</strong></td></tr><tr><td>timeSet</td><td>int</td><td>  Y</td><td><strong>타임아웃 시간 (기본 1000ms)</strong></td></tr><tr><td>{}</td><td>object</td><td>  Y</td><td><strong>이지웰 추천 필터링 정보 (하위참조)</strong></td></tr></tbody></table>

**— 이지웰 추천 필터링 정보(object) – 재구축(마켓/체크인 제외)**

<table><thead><tr><th width="190.53515625">필드명</th><th width="128.4912109375">타입</th><th width="79.32421875">필수</th><th>설명</th></tr></thead><tbody><tr><td>channel</td><td>string</td><td>N</td><td>고객사 채널정보</td></tr><tr><td>category</td><td>string</td><td>N</td><td>채널이 101, 102, 106 일때 필요</td></tr><tr><td>point</td><td>int</td><td>N</td><td>고객사 포인트</td></tr><tr><td>vendorCd</td><td>string</td><td>Y</td><td>고객사 코드</td></tr><tr><td>cnt</td><td>int</td><td>N</td><td>상품응답 개수</td></tr><tr><td>fallbackAlgorithmList</td><td>array&#x3C;string></td><td>N</td><td>폴백 알고리즘 리스트(하단의 알고리즘 리스트 참조)</td></tr><tr><td>giftYn</td><td>string</td><td>N</td><td>선물하기 추천 요청시 Y로 요청</td></tr></tbody></table>

{% hint style="danger" %} <mark style="color:red;">cnt 필드를 보내주지 않으시면 이지웰에 설정된 최대 200개의 상품이 내려갑니다.</mark>
{% endhint %}

{% hint style="success" %}
**전체 상품을 추천하시려면 channel에 빈값을 넣어주시고, vendorCd에 고객사 코드만 넣어주세요.**&#x20;

**vendorCd로만 필터해서 재구축, 마켓, 체크인의 상품중에 추천이 됩니다.**&#x20;
{% endhint %}

{% hint style="success" %}
**채널이 브랜드몰(101), 5대복지(102), 전문관(106) 일때는 category에 카테고리를 넣어주세요.**&#x20;

**선물하기 페이지에서 호출하실때는 채널값은 빈값으로 해서 giftYn에 Y를 넣어서 호출 해 주세요.**&#x20;
{% endhint %}

**— 이지웰 추천 필터링 정보(object) – 대응개발(마켓)**

<table><thead><tr><th width="195.00390625">필드명</th><th width="126.86328125">타입</th><th width="75.5234375">필수</th><th>설명</th></tr></thead><tbody><tr><td>vendorType</td><td>string</td><td>Y</td><td>대응개발 구분값 - 고정값 : MARKET</td></tr><tr><td>channel</td><td>string</td><td>N</td><td>고객사 채널정보</td></tr><tr><td>vendorCd</td><td>string</td><td>Y</td><td>고객사 코드</td></tr><tr><td>cnt</td><td>int</td><td>N</td><td>상품응답 개수</td></tr><tr><td>fallbackAlgorithmList</td><td>array&#x3C;string></td><td>N</td><td>폴백 알고리즘 리스트(하단의 알고리즘 리스트 참조)</td></tr></tbody></table>

{% hint style="danger" %} <mark style="color:red;">cnt 필드를 보내주지 않으시면 이지웰에 설정된 최대 200개의 상품이 내려갑니다.</mark>
{% endhint %}

**— 이지웰 추천 필터링 정보(object) – 대응개발(체크인)**

<table><thead><tr><th width="196.77734375">필드명</th><th width="132.845703125">타입</th><th width="61.681640625">필수</th><th>설명</th></tr></thead><tbody><tr><td>vendorType</td><td>string</td><td>Y</td><td>대응개발 구분값 - 고정값 : CHECK_IN</td></tr><tr><td>channel</td><td>string</td><td>N</td><td>고객사 채널정보</td></tr><tr><td>cityCd</td><td>string</td><td>N</td><td>도시코드</td></tr><tr><td>areaCd</td><td>string</td><td>N</td><td>지역코드</td></tr><tr><td>roomType</td><td>string</td><td>N</td><td>숙소유형</td></tr><tr><td>roomClass</td><td>string</td><td>N</td><td>숙소등급</td></tr><tr><td>vendorCd</td><td>string</td><td>Y</td><td>고객사 코드</td></tr><tr><td>cnt</td><td>int</td><td>N</td><td>상품 응답 개수</td></tr><tr><td>fallbackAlgorithmList</td><td>array&#x3C;string></td><td>N</td><td>폴백 알고리즘 리스트(하단의 알고리즘 리스트 참조)</td></tr></tbody></table>

{% hint style="danger" %} <mark style="color:red;">cnt 필드를 보내주지 않으시면 이지웰에 설정된 최대 200개의 상품이 내려갑니다.</mark>
{% endhint %}

**— 이지웰 추천 필터링 정보(object) – 대응개발(해외패키지)**

<table><thead><tr><th width="196.77734375">필드명</th><th width="132.845703125">타입</th><th width="61.681640625">필수</th><th>설명</th></tr></thead><tbody><tr><td>vendorType</td><td>string</td><td>Y</td><td>대응개발 구분값 - 고정값 : TRIP</td></tr><tr><td>cityCds</td><td>array&#x3C;string></td><td>N</td><td>도시코드</td></tr><tr><td>areaCd</td><td>string</td><td>Y</td><td>국가코드</td></tr><tr><td>vendorCd</td><td>string</td><td>Y</td><td>고객사 코드</td></tr><tr><td>cnt</td><td>int</td><td>N</td><td>상품 응답 개수</td></tr></tbody></table>

{% hint style="danger" %} <mark style="color:red;">cnt 필드를 보내주지 않으시면 이지웰에 설정된 최대 200개의 상품이 내려갑니다.</mark>
{% endhint %}

***

**폴백 알고리즘 리스트**&#x20;

{% hint style="warning" %}
캠페인별로 특정 폴백알고리즘을 노출하기 원하시면 아래 8개 알고리즘 코드 중 선택해서 넣어주시면 됩니다. \
ex)&#x20;

&#x20;"fallbackAlgorithmList" : \["ST02"] - ST02 상품이 내려갑니다.&#x20;

&#x20;"fallbackAlgorithmList" : \["ST02", "ST04"] - ST02, ST04 둘중 하나가 랜덤하게 내려갑니다.
{% endhint %}

| 사용 가능한 폴백 알고리즘 코드 | 설명               |
| ----------------- | ---------------- |
| ST02              | 많이 본 상품 TOP N    |
| ST03              | 많이 구매한 상품 TOP N  |
| ST04              | 추천 클릭률 TOP N     |
| ST05              | 실시간 많이 본 TOP N   |
| ST06              | 주문 전환율 TOP N     |
| ST07              | 추천 유입률 TOP N     |
| ST09              | 많이 담은 상품 TOP N   |
| ST10              | 실시간 많이 구매한 TOP N |

**작성 예**

```javascript
//추천 필터링 정보
let queryObj = {
       "channel" : "LG"
     , "point" : 300000
     , "vendorCd" : "A001"
     , "cnt" : 5
     , "fallbackAlgorithmList" : ["ST02","ST04","ST06","ST07","ST09"]
};
groobee.getGroobeeRecommendAsync("캠페인키", 3000, queryObj).then(data =<  { console.log(data); });              
```

**결과 값**

```javascript
{
    "campaignKey": "캠페인키",
    "algorithmCd": "ST02",
    "goodsList": [
        {
            "serviceKey": "서비스 키",
            "goodsNm": "[해외배송] 베르사체 오디세아 스니커즈 1015437-1A10925-2R44P White- Palladium",
            "goodsCd": "1011032410403",
            "goodsImg": "https://contents-qa.ezwelfare.net/ezwel-image/welfare_shop/upload/2025/06/16/7v4bLVxiMdNsTCwzp9FmlD…,
            "goodsCateNm": "해외직구",
            "goodsCate": "70020608",
            "goodsPrc": 1380000,
            "goodsSalePrc": 717000
        }, ...
    ]
}

```

***

## **5. DI(노출)**

* 실제 고객사에서 노출시킨 상품 정보를 그루비로 보내줍니다.
* 그루비로 노출시킨 상품 정보를 보내주면 통계에 집계되어 어드민에서 확인 가능합니다.
* **정의**
  * 역할: 전시되는 상품을 그루비에서 노출 처리
  * 함수명: groobee.send
* 파라미터

<table><thead><tr><th width="202.68359375">항목</th><th width="80.6328125">타입</th><th width="76.9375">필수</th><th>설명</th></tr></thead><tbody><tr><td>type</td><td>string</td><td>Y</td><td>노출 코드("DI" 고정 값)</td></tr><tr><td>{}</td><td>object</td><td>Y</td><td><strong>노출 관련 object (하위참조)</strong></td></tr></tbody></table>

**— 노출 관련 object**

<table><thead><tr><th width="203.88671875">필드명</th><th width="134.3125">타입</th><th width="77.58984375">필수</th><th>설명</th></tr></thead><tbody><tr><td>algorithmCd</td><td>string</td><td>Y</td><td>알고리즘 코드</td></tr><tr><td>campaignKey</td><td>string</td><td>Y</td><td>추천 캠페인키</td></tr><tr><td>campaignTypeCd</td><td>string</td><td>Y</td><td>캠페인 타입("RE" 고정 값)</td></tr><tr><td>goods</td><td>array&#x3C;object></td><td>Y</td><td><strong>실제로 노출된 상품 코드 리스트</strong> <strong>(하위참조)</strong><br>[ { goodsCd: "상품코드1" }, {}, ... ]</td></tr></tbody></table>

**— goods** 배열 내부 객체 구조 **(실제로 노출된 상품 코드 리스트)**

<table><thead><tr><th width="203.88671875">필드명</th><th width="81.42578125">타입</th><th width="77.58984375">필수</th><th>설명</th></tr></thead><tbody><tr><td>goodsCd</td><td>string</td><td>Y</td><td>상품 코드</td></tr></tbody></table>

<pre class="language-javascript"><code class="lang-javascript">groobeeObj = {
   algorithmCd : "알고리즘코드",
<strong>   campaignKey : "추천캠페인키",
</strong>   campaignTypeCd : "RE", //고정
   goods: [
      {goodsCd: "노출된 상품코드1"},
      {goodsCd: "노출된 상품코드2"},
      ...
      ]
groobee.send("DI", groobeeObj);
</code></pre>

***

## **6. CL(클릭)**

* 고객이 클릭한 상품 정보를 그루비로 보내줍니다.
* 고객이 클릭한 상품 정보를 그루비로 보내주면 통계에 집계되어 어드민에서 확인 가능합니다.
* **정의**
  * 역할: 고객이 클릭한 상품을 그루비에서 클릭 처리
  * 함수명: groobee.send
* 파라미터

<table><thead><tr><th width="197.77734375">항목</th><th width="134.078125">타입</th><th width="93.77734375">필수</th><th>설명</th></tr></thead><tbody><tr><td>type</td><td>string</td><td>Y</td><td>클릭 코드("CL" 고정 값)</td></tr><tr><td>{}</td><td>object</td><td>Y</td><td><strong>클릭 관련 object (하위참조)</strong></td></tr></tbody></table>

**— 클릭 관련 object**

<table><thead><tr><th width="197.8828125">필드명</th><th width="134.28515625">타입</th><th width="96.49609375">필수</th><th>설명</th></tr></thead><tbody><tr><td>algorithmCd</td><td>string</td><td>Y</td><td>알고리즘 코드</td></tr><tr><td>campaignKey</td><td>string</td><td>Y</td><td>추천 캠페인키</td></tr><tr><td>campaignTypeCd</td><td>string</td><td>Y</td><td>캠페인 타입("RE" 고정 값)</td></tr><tr><td>goods</td><td>array&#x3C;object></td><td>Y</td><td><strong>실제로 클릭된 상품 코드 (하위참조)</strong><br>[ { goodsCd: "상품코드1" }]</td></tr></tbody></table>

— goods 배열 내부 객체 구조 (**실제로 클릭된 상품 코드**)

<table><thead><tr><th width="203.88671875">필드명</th><th width="81.42578125">타입</th><th width="77.58984375">필수</th><th>설명</th></tr></thead><tbody><tr><td>goodsCd</td><td>string</td><td>Y</td><td>상품 코드 (<strong>실제 클릭한 상품 1개</strong>)</td></tr></tbody></table>

```javascript
groobeeObj = {
   algorithmCd : "알고리즘코드",
   campaignKey : "추천캠페인키",
   campaignTypeCd : "RE", //고정
   goods: [
        {goodsCd: "고객이 클릭한 상품코드1"}
        ]
}

groobee.send("CL", groobeeObj);
```

***

## **7. 작성 예시**

코드 작성 예시를 보여줍니다.

{% code overflow="wrap" lineNumbers="true" %}

```javascript
//작성 예시일 뿐 고객사의 코드에 맞게 수정해 주시면 됩니다.
//아래 코드가 정답이 아닙니다. 참고만 부탁드립니다.
function groobeeRecommendCall () {

  let queryObj = {
    "channel" : "LG", 
    "point" : 300000,
    "vendorCd" : "A001",
    "cnt" : 5,
    "fallbackAlgorithmList" : ["ST02","ST04","ST06","ST07","ST09"]
  };
  
  //함수가 존재하는지 체크
  if (groobee && groobee.getGroobeeRecommendAsync) {
    //groobee.getGroobeeRecommendAsync 함수를 정상적으로 호출이 될 경우
    groobee.getGroobeeRecommendAsync('RE6b33946d7add471dbd33f35347b5c06f', 3000, queryObj)
    .then(data => {
      고객사처리함수(data);
    })
  } else {
    //groobee.getGroobeeRecommendAsync 함수가 정상적으로 호출이 되지 않을 경우
    let tryCnt = 0;
    let _timer = setInterval(()=> {
      
    // 3회 넘어갈시 중지
    if(tryCnt==3){
        clearInterval(_timer);
        $('#지정된ID').hide();
        return;
    }
    tryCnt++;
    
    // function 존재시에만 실행
    if(groobee.getGroobeeRecommendAsync && typeof groobee.getGroobeeRecommendAsync == 'function') {
        groobee.getGroobeeRecommendAsync('RE6b33946d7add471dbd33f35347b5c06f', 3000, queryObj)
        .then(data =< {
          고객사처리함수(data);
        })
        clearInterval(_timer);
    }}, 500);
  }
}

function 고객사처리함수(data) {
  console.log('recommendData :::', data);
  if (data && data.goodsList) {
    //고객사 추천상품 노출 및 데이터처리
    ...code 
    /*
      추천 상품 선별 및 노출작업
      각 상품 클릭 시 이벤트 연결처리도 필요 아래 clickGroobeeProduct(함수명은 자유)
      예시일 뿐 고객사에 맞춰서 코드는 새로 작성할 것
    */
    let html = "<ul>"; 
    for (let i = 0; i < data.goodsList.length; i++) { 
      //--------------groobee 클릭(CL) 처리 START----------------
      html += `<li onClick="clickGroobeeProduct(${data.campaignKey}, ${data.algorithmCd}, ${data.goodsList[i].goodsCd})">${data.goodsList[i].goodsNm}</li>`;
      //--------------groobee 클릭(CL) 처리 END----------------
    }
    html += "</ul>";
    
    $('#지정된ID').append(html);
    $('#지정된ID').show();
    
    //--------------groobee 노출(DI) 처리 START----------------
    groobeeDisplayInsert(data.campaignKey, data.algorithmCd, data.goodsList);
    //--------------groobee 노출(DI) 처리 END------------------
  } else {
    $('#지정된ID').hide();
  }
}

function groobeeDisplayInsert(campaignKey, algorithmCd, goodsList) {
  //상품목록이 존재하는지 체크
  if (!goodsList || goodsList.length == 0) return;
  let goods = [];
    for (let i = 0; i < goodsList.length; i++) {
      let newObj = {goodsCd: goodsList[i].goodsCd};
      goods.push(newObj);
  } 
    
  let groobeeObj = {
    algorithmCd: algorithmCd, //알고리즘코드 (추천받을때 받은 algorithmCd)
    campaignKey: campaignKey, //캠페인키
    campaignTypeCd: 'RE',     //고정값
    goods: goods
  }
  groobee.send('DI', groobeeObj);
}

function clickGroobeeProduct(campaignKey, algorithmCd, goodsCd) {
  //추천 클릭처리
  let groobeeObj = {
    algorithmCd: algorithmCd, //알고리즘코드 (추천받을때 받은 algorithmCd)
    campaignKey: campaignKey, //캠페인키
    campaignTypeCd: 'RE',     //고정값
    goods: [
      {goodsCd: goodsCd}
    ]
  }
  groobee.send('CL', groobeeObj);
  
  //고객사 페이지 이동처리
  code....
}    
```

{% endcode %}

***

## **8. 변경이력**

<table><thead><tr><th width="74.84375">버전</th><th width="120.48828125">날짜</th><th width="423.5625">변경이력</th><th>담당자</th></tr></thead><tbody><tr><td>-</td><td>2025.07.24</td><td>초안작성</td><td>김상훈</td></tr><tr><td>1.02</td><td>2025.09.28</td><td>대응개발(마켓/체크인) 추천 필터링 정보 추가</td><td>김상훈</td></tr><tr><td>1.03</td><td>2025.10.15</td><td>추천상품 응답시 캠페인별 상품개수 조절하기 위한 필터링 정보 추가</td><td>김상훈</td></tr><tr><td>1.04</td><td>2025.10.22</td><td>필터항목의 필수 여부 수정</td><td>김상훈</td></tr><tr><td>1.05</td><td>2025.10.28</td><td>체크인 필터링 항목 필수 여부 변경<br>(도시코드, 지역코드, 숙소유형, 숙소등급 : Y → N )</td><td>김상훈</td></tr><tr><td>1.06</td><td>2025.11.07</td><td>폴백 알고리즘 필터 추가</td><td>이도환</td></tr><tr><td>1.07</td><td>2025.11.12</td><td>재구축 필터링 정보에 category, giftYn 추가</td><td>김상훈</td></tr><tr><td>1.08</td><td>2025.12.12</td><td>대응개발(해외패키지) 추천 필터링 정보 추가 </td><td>이도환</td></tr></tbody></table>


---

# Agent Instructions: 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:

```
GET https://docs.groobee.ai/developer-guide/script-guide/ai-recommendation/custom/ezwel.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
