GA4로 카페24 전자상거래 분석하기(2025년 업데이트)

💡 카페24 자사몰과 GA4를 연결할 때, 가장 먼저 해야 할 일은 ‘전자상거래’ 분석 세팅입니다. 단순히 GA4만 연결해 뒀다면 자사몰에 중요한 구매(purchase) 등 정보는 추적되지 않습니다. 이번 포스팅에서는 GTM을 이용해서 카페24에서 GA4 전자상거래 이벤트를 추적하는 방법을 알아보겠습니다. (네이버 페이, 카카오 페이 대응)

1. 개요

1) 전자상거래 이벤트란?

GA4는 사용자의 모든 행동을 ‘이벤트’로 분류해서 추적합니다. GA4를 연결만 해도 유입, 페이지 조회 등 기본 이벤트는 자동으로 추적되지만, 자사몰에서 중요한 장바구니, 구매 등 이벤트는 별도로 세팅이 필요합니다. 이러한 이벤트를 ‘전자상거래’ 이벤트라고 부릅니다. 주요 전자상거래 이벤트는 아래 표를 참고하세요.

전자상거래 이벤트 설명
view_item 상품 조회
add_to_cart 장바구니
begin_checkout 주문서 작성
purchase 구매

아임웹 등 일부 플랫폼에서는 API를 통해 홈페이지 관리자에서 편리하게 GA4 전자상거래 연동을 할 수 있습니다. 다만, 국내에서 가장 점유율이 높은 카페24 같은 경우 GA4 전자상거래 연동 옵션이 없어서 GTM이나 기타 솔루션을 사용해야 합니다.

이번 포스팅에서는 누구나 따라할 수 있도록 GTM을 사용한 방법을 안내합니다.

2) GTM과 GA4 사용법

GTM과 GA4의 기본적인 설치, 사용법은 아래 포스팅을 참고해 주세요.

참고로 카페24에서는 쇼핑몰 설정 → 기본 설정 → 검색엔진 최적화(SEO) → 코드 직접입력 메뉴에서 Head와 Body에 GTM 스니펫을 입력할 수 있습니다.

2. GTM 세팅

1) 변수 입력

아래 항목을 모두 사용자 정의 변수에 입력해 주세요.

a. 맞춤 자바스크립트 변수

자바스크립트 변수는 스크립트 추가가 필요합니다. 아래 이미지를 참고하여 변수명 – 변수 유형 – 스크립트를 작성해 주세요.

맞춤 자바스크립트 변수 설명 이미지
맞춤 자바스크립트 변수 설명 이미지

변수명: 01productInfo

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var productInfo = [{
    'item_id': iProductNo,
    'item_name': product_name,
    'price': product_price,
    'item_category': iCategoryNo
  }];
  return productInfo;
}

변수명: 02orderInfo

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var source = aBasketProductOrderData;
  var productInfo = [];
  for(var i = 0 ; i < source.length ; i++) {
      var productId = source[i].product_no;
      var productPrice = source[i].product_sale_price;
      var productQty = source[i].quantity;
      var productCate = source[i].main_cate_no;

      productInfo.push({
        'item_id': productId,
        'price': productPrice,
        'quantity': productQty,
        'item_category': productCate
      });
  }
  return productInfo;
}

변수명: 03orderId

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var source = EC_FRONT_EXTERNAL_SCRIPT_VARIABLE_DATA;
  var orderId = source.order_id;
	return orderId;
}

변수명: 04orderPrice

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var source = EC_FRONT_EXTERNAL_SCRIPT_VARIABLE_DATA;
  var revenue = source.payed_amount;
	return revenue;
}

변수명: 05shipFee

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var source = EC_FRONT_EXTERNAL_SCRIPT_VARIABLE_DATA;
  var shippingFee = source.total_basic_ship_fee;
	return shippingFee;
}

변수명: 06orderProductInfo

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var source = EC_FRONT_EXTERNAL_SCRIPT_VARIABLE_DATA.order_product;
  var productInfo = [];
  for(var i = 0 ; i < source.length ; i++) {
      var productId = source[i].product_no;
      var productName = source[i].product_name;
      var productPrice = source[i].product_price;
      var productQty = source[i].quantity;
      var productCate = source[i].category_no_2;

      productInfo.push({
        'item_id': productId,
        'item_name': productName,
        'price': productPrice,
        'item_category': productCate,
        'quantity': productQty
      });
  }
  return productInfo;
}

변수명: 07User_ID

변수 유형: 맞춤 자바스크립트

스크립트:

function(){
  var uid = EC_FRONT_EXTERNAL_SCRIPT_VARIABLE_DATA.common_member_id_crypt;
  return uid;
}

변수명: pushDataLayerForEcommerce

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
    var npay_trans_id = '';
    var times = {{time_string}};
    return function( act, productInfo, listName, dataLayer )	{
      
      switch( act ) {

          /* GA4 */
          case 'nPay_checkoutCartGA4':
          case 'nPay_checkoutGA4' :

              var total_cnt = productInfo.length;
              var total_price =0;
              for(var i=0;i<total_cnt;i++) {
                  total_price += (parseInt(productInfo[i].price) * parseInt(productInfo[i].quantity));
              }
              var tPrice = $('.totalPrice .total em').text();
              if ( tPrice ) total_price = tPrice.replace(/[^d]/g, '');
              npay_trans_id = times+'-npay'+listName.orderId // 여기서는 주문번호입니다.
            
              var orderInfo = {'transaction_id':npay_trans_id,'value':total_price, 'shipping':0, 'currency':'KRW', 'payment_type':'npay'};
              orderInfo.items = productInfo;
              if ( total_cnt > 0 ) {
                  var product_name = productInfo[0].item_name;
                  if ( total_cnt > 1 ) {
                      product_name = product_name + '외 ' + ( total_cnt - 1);
                  }
              }
              dataLayer.push({ 'ecommerce': null });
              dataLayer.push({'event':'nPaypurchaseG4', 'product_title':product_name, 'ecommerce': orderInfo});
          break;
        
          case 'kakao_checkoutGA4' :
          case 'kakao_checkoutCartGA4':
            
              var total_cnt = productInfo.length;
              var total_price =0;
              for(var i=0;i<total_cnt;i++) {
                  total_price += (parseInt(productInfo[i].price) * parseInt(productInfo[i].quantity));
              }
              var tPrice = $('.totalPrice.kd-clear .total em').text();
              if ( tPrice ) total_price = tPrice.replace(/[^d]/g, '');
              kakao_trans_id = times+'-kakao'+ listName.orderId ;// 여기서는 주문번호입니다.
            
              var orderInfo = {'transaction_id':kakao_trans_id,'value':total_price, 'shipping':0, 'currency':'KRW', 'payment_type':'kpay'};
              orderInfo.items = productInfo;
              if ( total_cnt > 0 ) {
                  var product_name = productInfo[0].name;
                  if ( total_cnt > 1 ) {
                      product_name = product_name + '외 ' + ( total_cnt - 1);
                  }
              }
              dataLayer.push({ ecommerce: null });
              dataLayer.push({'event':'kPaypurchaseG4', 'product_title':product_name, 'ecommerce': orderInfo});
          break;

      }
    }
}

변수명: actionEcommerce

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
    var pushDataLayer = {{pushDataLayerForEcommerce}};

    return function(event, act, dataLayer, productData ) {
        switch(act) {
            /* GA4 용 */
            case 'nPay_checkoutGA4' :
            case 'kakao_checkoutGA4' :
                var getProductInfo = {{getProductInfoFromOptionForGA4}};
                var productInfo = getProductInfo();
                if( productInfo.length ) pushDataLayer(act, productInfo, productData, dataLayer);
            break;
            case 'nPay_checkoutCartGA4':
            case 'kakao_checkoutCartGA4':
                var getProductInfo = {{getProductInfoFromBasketForGA4}};
                var productInfo = getProductInfo(productData);
                if( productInfo.length ) pushDataLayer(act, productInfo, productData, dataLayer);
            break;
        }
    };
}

변수명: time_string

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  var today = new Date();
  var year = today.getFullYear();
  var month = ('0' + (today.getMonth() + 1)).slice(-2);
  var day = ('0' + today.getDate()).slice(-2);
  var hours = ('0' + today.getHours()).slice(-2);
  var minutes = ('0' + today.getMinutes()).slice(-2);
  var seconds = ('0' + today.getSeconds()).slice(-2);
  var timeString = year + month + day + hours + minutes + seconds;

  return timeString;
}

변수명: getProductInfoFromBasketForGA4

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  
  return function( position ) {
      var productInfo = [];
      var getProductVariant = {{getProductVariant}};
      if (typeof position !== 'undefined') {
          var localPosition = position.hasOwnProperty('position') ? position.position : position;
          var loop = localPosition.length;
          for( var i =0; i < loop ; i++ ) {
              var loop_position = localPosition[ i ];
              var variant = getProductVariant(aBasketProductData[loop_position].option_str);
              productInfo.push({
                  'item_id': aBasketProductData[loop_position].product_no,
                  'item_name': aBasketProductData[loop_position].product_name,
                  'item_category': aBasketProductData[loop_position].main_cate_no,
                  'item_variant' : variant,
                  'price': aBasketProductData[loop_position].product_price,
                  'quantity': aBasketProductData[loop_position].quantity,
              });
          }
      }
      return productInfo;
    };
}

변수명: getProductInfoFromOptionForGA4

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
  
    return function() {
        var productInfo = [];
        var isCheck = false;
        var isSoldOut = false;
        if ( typeof oProductList != 'undefined' ) {
            if ( typeof option_stock_data != 'undefined' ) {
                var products = JSON.parse(option_stock_data);
                if ( typeof add_option_data != 'undefined' ) {
                    var addedProduct = JSON.parse(add_option_data);
                    for( idx in addedProduct ) {
                        if( addedProduct[idx].item_count > 1 ) {
                            var items = JSON.parse( addedProduct[idx].option_stock_data ) ;
                            for( i in items ) {
                                items[ i ].product_no = idx; items[ i ].product_name = addedProduct[idx].product_name;
                            }
                            products = Object.assign(products, items );
                        } else {
                            var items = '{"'+addedProduct[idx].item_code+'" : {"option_price" :'+addedProduct[idx].product_price+', "option_value_orginal": [], "product_no": "'+idx+'","product_name": "'+addedProduct[idx].product_name+'", "is_auto_soldout":"'+addedProduct[idx].is_auto_soldout+'" }}';
                            products = Object.assign(products, JSON.parse(items) );
                        }
                    }
                }
                for(idx in oProductList){
                    var quantity = oProductList[idx];
                    var price = products[idx].option_price;
                    var options = products[idx].option_value_orginal;
                    var variant = '';
                    options.forEach(function(val){ variant += (','+ val); })
                    variant = variant.substr(1);
                    var productNo = '', productName = '';
                    if (products[idx].hasOwnProperty('product_no') ) {
                        productNo = products[idx].product_no;
                        productName = products[idx].product_name;
                    } else {
                        productNo = iProductNo;
                        productName = product_name;
                        if (!isCheck ) isCheck = true;
                    }
                    if ( products[idx].is_auto_soldout == 'T' && products[idx].stock_number == 0 ) {
                        if( !isSoldOut ) isSoldOut = true;
                    }
                    productInfo.push({
                                'item_id': productNo,
                                'item_name': productName,
                                'item_category': iCategoryNo,
                                'item_variant' : variant,
                                'price': price,
                                'quantity': quantity,
                    });
                };
                if( isSoldOut ) productInfo = [];
            } else {
                var quantity = 0;
                for(idx in oProductList) {
                    quantity = oProductList[idx];
                }
                if (!isCheck ) isCheck = true;
                productInfo.push({
                    'item_id': iProductNo,
                    'item_name': product_name,
                    'item_category': iCategoryNo,
                    'price': product_price,
                    'quantity': quantity,
                });
            }
        }
        if (isCheck) return productInfo;
        else return [];
    }
}

변수명: getProductVariant

변수 유형: 맞춤 스크립트

스크립트:

function() {
    return function( option_str ) {
        var rtn = '';
        if ( Array.isArray(option_str) ) {
            rtn = option_str[0].replace(/^[\[]옵션:(.+)\]$/, '$1').trim().replace(/[\/]/g, ',');
        } else {
            if ( option_str ) rtn = option_str.replace(/^[\[]옵션:(.+)\]$/, '$1').trim().replace(/[\/]/g, ',');
        }
        return rtn;
    };
}

변수명: getPositionFromBasket

변수 유형: 맞춤 자바스크립트

스크립트:

function() {
    return function( posAll ) {
        posAll = (typeof posAll !== 'undefined') ? posAll : true;
      
        var position = [];
        var productInfo = null;
        if ( mobileWeb ) {
            productInfo = $('.ec-base-prdInfo.xans-record-:has(input[id^=basket_chk_id])');
        } else {
            productInfo = $('tr.xans-record-:has(input[id^=basket_chk_id])');
            if ( !productInfo.length ) productInfo = $('.prdList .item.xans-record-');
        }
        var len = productInfo.length;
        for(i=0;i<len;i++) {
            if ( posAll ) {
                position.push(i);
            } else {
                var temp =$(productInfo[i]).find('input[id^=basket_chk_id]:checked').length;
                if ( temp ) position.push(i);
            }
        }
        return position;
    };
}

b. 데이터 영역 변수

데이터 영역 변수는 아래 이미지를 참고하여 하나씩 추가해 주세요.

데이터 영역 변수 설명 이미지
데이터 영역 변수 설명 이미지

변수명 변수 유형 데이터 영역 변수 이름
Ecommerce Currency 데이터 영역 변수 ecommerce.currency
Ecommerce Items 데이터 영역 변수 ecommerce.items
Ecommerce Payment Type 데이터 영역 변수 ecommerce.payment_type
Ecommerce Shipping 데이터 영역 변수 ecommerce.shipping
Ecommerce Transaction ID 데이터 영역 변수 ecommerce.transaction_id
Ecommerce Value 데이터 영역 변수 ecommerce.value

2) 트리거 입력

주요 전자상거래 이벤트인 view_item, add_to_cart, begin_checkout, purchase에 대한 트리거 세팅입니다. 네이버 페이, 카카오 페이도 대응됩니다.

각 사이트 구조에 따라 실행 조건이 달라질 수 있습니다. 아래 이미지를 참고하여 트리거 항목에 하나씩 추가해 주세요.

a. 맞춤 이벤트 트리거

맞춤 이벤트 트리거 설명 이미지
맞춤 이벤트 트리거 설명 이미지

트리거 이름 이벤트 이름 비고
06view_item view_item
07add_to_cart add_to_cart
08begin_checkout begin_checkout
09purchase purchase
13npay_purchase ^(nPaypurchaseG4|kPaypurchaseG4)$ 체크: 일치하는 정규 표현식 사용

b. 그외 이벤트 트리거

그 외 이벤트 트리거 설명 이미지
그 외 이벤트 트리거 설명 이미지

트리거 이름 트리거 유형 필터 비고
02viewitem 페이지뷰 – DOM 사용 가능 Page Path 정규 표현식과 일치 ^(?=.*product)(?=.*category)(?=.*display).*
03actionCart 클릭 – 모든 요소 Click Text 포함 장바구니
04orderform 페이지뷰 – DOM 사용 가능 Page Path 포함 /order/orderform.html
05orderresult 페이지뷰 – DOM 사용 가능 Page Path 포함 /order/order_result.html
10dom+purchase 트리거 그룹 [05orderresult] and [09purchase] (2개 트리거 결합)
11view_detail 페이지뷰 – DOM 사용 가능 Page Path 정규 표현식과 일치 ^(\/product\/[^\/]+\/[\d]+\/|\/product\/detail.html|\/product\/basket_option.html)
12view_cart 페이지뷰 – DOM 사용 가능 Page Path 정규 표현식과 일치 ^\/order\/basket.html

3) 태그 입력

주요 전자상거래 이벤트인 view_item, add_to_cart, begin_checkout, purchase에 대한 태그 세팅입니다. 네이버 페이, 카카오 페이도 대응됩니다.

아래 이미지를 참고하여 태그 항목에 하나씩 추가해 주세요.

a. 맞춤 HTML 태그

맞춤 HTML 태그 이미지 설명
맞춤 HTML 태그 이미지 설명

태그명: view_item

스크립트:

<script>
  dataLayer.push({
    "event": "view_item",
    "ecommerce":	{
    "currency": "KRW",
    "User_ID": {{07User_ID}}, 
    "items": {{01productInfo}}
  }
});
</script>

트리거: 11view_detail

태그명: add_to_cart

스크립트:

<script>
  dataLayer.push({
  "event": "add_to_cart",
  "ecommerce":	{
    "currency": "KRW",
    "User_ID": {{07User_ID}},
    "items": {{01productInfo}}
  }
});
</script>

트리거: 03actionCart

태그명: begin_checkout

스크립트:

<script>
  dataLayer.push({
    "event":	"begin_checkout",
    "ecommerce":	{
    "User_ID": {{07User_ID}},
    "currency": "KRW",
    "items": {{02orderInfo}}
  }
});

</script>

트리거: 04orderform

태그명: purchase

스크립트:

<script>
  dataLayer.push({
  "event":	"purchase",
  "ecommerce":	{
    "transaction_id": {{03orderId}},
    "User_ID": {{07User_ID}},
    "currency": "KRW",
    "shipping": {{05shipFee}},
    "value": {{04orderPrice}},
    "items": {{06orderProductInfo}}
  }
});

</script>

트리거: 05orderresult

태그명: npay_view_item

스크립트:

<script>
var dataLayer = dataLayer || [];
var actEcommerce = {{actionEcommerce}};

$(document).delegate( 'a[id^=NPAY_BUY_LINK_IDNC_ID_]', 'click', function(event){
    var orderId = $(this).attr('id').replace(/^NPAY_BUY_LINK_IDNC_ID_(.*)/, '$1');
    actEcommerce(event,'nPay_checkoutGA4', dataLayer, {'orderId':orderId});
});

$(document).delegate( '.__checkout_btn_buy', 'click', function(event){
    var orderId = $('#checkoutContainer').data('id');
    actEcommerce(event,'kakao_checkoutGA4', dataLayer, {'orderId':orderId});
});
</script>

트리거: 11 view_detail

태그명: npay_basket

스크립트:

<script>
var dataLayer = dataLayer || [];
var actEcommerce = {{actionEcommerce}};
var getPosition = {{getPositionFromBasket}};

// Naver Pay 
$('a[id^=NPAY_BUY_LINK_IDNC_ID_]').bind('click', function(event){
    var position = getPosition();
    var orderId = $(this).attr('id').replace(/^NPAY_BUY_LINK_IDNC_ID_(.*)$/, '$1');
    actEcommerce(event,'nPay_checkoutCartGA4', dataLayer, { 'position' : position, 'orderId': orderId} );
});
// kakao Pay 
$('.__checkout_btn_buy').bind('click', function(event){
    var position = getPosition();
    var orderId = $('#checkoutContainer').data('id');
    actEcommerce(event,'kakao_checkoutCartGA4', dataLayer, { 'position' : position, 'orderId': orderId} );
});
</script>

트리거: 12view_cart

b. GA4 이벤트 태그

GA4 이벤트 태그 설명 이미지
GA4 이벤트 태그 설명 이미지

✅ user_id는 필수 요소는 아니어서 설명에서 제외하였습니다. 또한 대부분 국내에서만 전자상거래가 이루어지기에, 통화 단위는 KRW로 고정하였습니다. 만약 해외에서도 전자상거래가 발생한다면 통화 단위의 변수 처리가 필요합니다.

태그 이름 이벤트 이름 매개변수 트리거
view_item_event view_item items | {{01productInfo}}
currency | KRW
06view_item
add_to_cart_event add_to_cart items | {{01productInfo}}
currency | KRW
07add_to_cart
begin_checkout_event begin_checkout items | {{01productInfo}}
currency | KRW
08begin_checkout
purchase_event purchase currency | KRW
items | {{06orderProductInfo}}
shipping | {{05shipFee}}
transaction_id | {{03orderId}}
value | {{04orderPrice}}
10dom+purchase
npay_purchase_event purchase currency | {{Ecommerce Currency}}
items | {{Ecommerce Items}}
shipping | {{Ecommerce Shipping}}
transaction_id | {{Ecommerce Transaction ID}}
value | {{Ecommerce Value}}
payment_type | {{Ecommerce Payment Type}}
13npay_purchase

3. 유의할 점

1) GA4 전자상거래 지표는 인사이트 분석 용도로만 사용합니다.

GA4에서 추적되는 전자상거래 매출은 카페24 관리자나 PG사에서 확인 가능한 실제 매출과는 차이가 날 수 있습니다. (GA4 자체의 유실, 스크립트 오집계 등 다양한 원인으로 인해)

특히 네이버 페이나 카카오 페이와 같은 결제 매체는 사이트 외부에서 완료가 되기 때문에, 완료 전 이탈하는 경우에도 구매 이벤트로 추적되게 됩니다. (버튼 클릭 시 구매로 산정)

그렇기 때문에 GA4 전자상거래 데이터는 마케팅 효율 등 인사이트 분석 용도로 사용해야지, 실제 매출 관리 용도로 활용해서는 안됩니다.

다만, 실제 매출과 GA4 지표가 심하게 차이난다면 스크립트 등 기본 세팅에 문제가 있다고 볼 수 있습니다. 이 경우는 세팅 항목 점검이 필요합니다.

2) 사이트 구조, 업데이트 항목에 따라 실행 조건 등 세부 항목이 달라질 수 있습니다.

카페24의 경우 주문, 결제 등 주요 구조는 모든 자사몰이 동일한 구조이기에 큰 문제는 없으나, 사이트 구조나 향후 업데이트 여부에 따라 세부 항목이 달라질 수 있습니다.

마무리

이번 가이드에서는 카페24 자사몰의 전자상거래 데이터를 GA4와 연동하여 분석하는 방법을 알아보았습니다.

혹시 궁금한 점이나 추가적인 경험이 있다면 댓글 혹은 상담 문의를 통해 공유해 주세요!

“GA4로 카페24 전자상거래 분석하기(2025년 업데이트)”에 대한 2개의 생각

  1. 알려주신대로 세팅을 하니까 각 이벤트가 중복으로 여러 번 집계 되는데 해결 방법이 있을까요?
    ex) 장바구니 담기 1회만 해도 add_to_cart 이벤트 3회로 집계됨.

    응답
    • 안녕하세요! 혹시 이벤트가 중복 집계될 때 장바구니만 문제가 있으신건가요, 아니면 다른 이벤트도 문제가 있으신가요? 장바구니의 경우는 각 사이트마다 트리거 세팅이 달라져야 합니다.

      응답

댓글 남기기