# 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><tr><td></td><td></td><td></td><td></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>grbChannelCode</td><td>string</td><td>N</td><td>고객사 채널정보</td></tr></tbody></table>

**작성 예**

```javascript
//추천 필터링 정보
let queryObj = {
       "grbChannelCode" : "10100"
};
groobee.getGroobeeRecommendAsync("캠페인키", 3000, queryObj).then(data =<  { console.log(data); });              
```

**결과 값**

```javascript
{
    "campaignKey": "캠페인키",
    "algorithmCd": "ST02",
    "goodsList": [
        {
            "serviceKey": "서비스 키",
            "goodsNm": "[무료배송]조미구이 대천김(선물상자20봉)",
            "goodsCd": "G0000650",
            "goodsImg": "https://image.shshopping.co.kr/api/data001/shcy-uploads/file/shcy/b2c/UPLOAD/images/goods/G0/00/06/50/G0000650_01_500.gif"
            "goodsCateNm": "돌김",
            "goodsCate": "100105100101",
            "goodsPrc": 54000,
            "goodsSalePrc": 49000
        }, ...
    ]
}

```

***

## **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 = {
       "grbChannelCode" : "10100"
  };
  
  //함수가 존재하는지 체크
  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>2026.01.20</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/suhyeop.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.
