일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 개발자
- recommendation system
- hadoop
- 하둡
- 클라우데라
- kafka
- Data engineering
- Python
- apache spark
- pyspark
- 블로그
- dataengineer
- cloudera
- 빅데이터
- Terraform
- 하둡에코시스템
- AWS SageMaker
- 개발자혜성
- 데이터엔지니어
- spark
- Spark structured streaming
- kubernetes
- eks
- 추천시스템
- 데이터엔지니어링
- DataEngineering
- 빅데이터플랫폼
- redis bloom filter
- mlops
- BigData
- Today
- Total
Hyesung Oh
구글태그매니저 GTM 구글 애널리틱스 GA 딥다이브 본문
GTM vs GA
구글태그매니저(GTM) 와 구글 애널리틱스(GA)의 설치면에서 차이를 본다면 아래 그림과 같다.
구글애널리틱스(GA) : 웹사이트에 GA 스크립트를 삽입한다.
구글 태그매니저는(GTM) : 웹사이트의 GTM 스크립트를 삽입 후, GTM 을 통해 GA를 연결한다. 이로써, 구글 태그매니저는 GA의 관리자 역할을 한다.
- 구글애널리틱스(GA)는 여러 유입/행동 레포트나 중요사항에 대한 목표/전환을 설정할 수 있다.
- 구글 태그매니저는(GTM)은 레포트나, 목표/전환을 제공하지는 않는다. 다만 여러 GA 같은 tool 을 설치/관리하게 해준다. middle-man 개념으로 보면 되겠다.
- 구글애널리틱스(GA)는 구글 태그매니저는(GTM) 없이도, 설치되어 사용될 수 있다. 구글 태그매니저는(GTM)도 구글애널리틱스(GA) 없이 (다른 툴들이) 설치되어 사용할 수 있다.
실무에서 GA 외에도 다양한 Thrid Party로의 이벤트 전송을 위해 중간 매개체로 활용할 수 있는 GTM을 많이 활용하는 것으로 알고 있다. 이번 포스트에서는 GTM 작동원리 및 GTM을 이용해 GA로 사용자 행동 로그를 올바르게 보내기 위해 노력한 과정에서 알게된 내용에 대해 정리해보았다.
GTM
Google Tag Manager DataLayer 문서를 참고하였습니다.
DataLayer
개념
데이터 영역은 Google 태그 관리자와 gtag.js에서 태그에 정보를 전달하기 위해 사용하는 객체입니다. 이벤트 또는 변수는 데이터 영역을 통해 전달될 수 있으며, 트리거는 변수 값을 기반으로 트리거를 설정될 수 있습니다.
웹에선 window라는 전역객체가 있다. dataLayer는 window 객체를 통해 접근할 수 있는 전역객체이다.
데이터 영역 객체 내에 선언된 각 변수는 방문자가 현재 페이지에 머무르는 동안만 유지됩니다.
하지만 이는 페이지가 이동 될 때 마다 초기화 되는 객체라는 것에 유의해야한다.
클라이언트는 dataLayer를 통해 GTM에 구성된 태그 및 트리거를 작동하여 GA로 사용자 행동 로그를 보낸다. 이는 뒤에 나올 user_id를 다루기 위해 중요한 개념이므로 꼭 기억해두길 바란다.
설치
태그 관리자 웹페이지 설치의 경우 데이터 영역을 만들어야 합니다. 아래의 강조표시된 코드는 태그 관리자가 로드되기 전에 데이터 영역이 설정된 위치를 보여줍니다.
<script>
window.dataLayer = window.dataLayer || [];
</script>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- End Google Tag Manager -->
정보처리 방식
컨테이너가 로드되면 태그 관리자가 큐에 추가된 모든 데이터 영역 푸시 메시지를 처리하기 시작합니다. 태그 관리자는 선입 선출 방식으로 메시지를 처리합니다. 각 메시지는 수신된 순서에 따라 한 번에 하나씩 처리됩니다. 메시지가 이벤트인 경우, 태그 관리자가 다음 메시지로 넘어가기 전에 충족된 트리거 조건이 있는 모든 태그가 실행됩니다.
이를 이해하려면 아래 태그와 트리거에 대해 먼저 알아야한다고 생각한다.
태그와 트리거
dataLayer 객체는 event 키를 사용하여 이벤트 전송을 시작합니다. 전체 사이트 태그와 태그 관리자는 event라는 특수한 데이터 영역 변수를 사용합니다. 이 변수는 사용자가 웹사이트 요소와 상호작용할 때 자바스크립트 이벤트 리스너가 태그를 실행하는 데 사용됩니다. 예를 들어 사용자가 구매 확인 버튼을 클릭할 때 전환 추적 태그를 실행할 수 있습니다. 이벤트는 사용자가 링크, 버튼, 스크롤 등의 웹사이트 요소와 상호작용할 때마다 호출할 수 있습니다. 이 기능은 이벤트가 발생할 때 dataLayer.push()를 호출하여 수행됩니다. dataLayer.push()를 통해 이벤트를 전송하는 문법은 다음과 같습니다.
GTM에서 설정할 수 있는 태그에는 여러가지가 있고 그 중에서, GA4이벤트라는 태그 유형에 대해서 다뤄보려한다. 트리거는 태그에 설정되어 클라이언트에서 트리거를 작동시키는 함수를 호출하면, 해당 트리거가 부착된 (설정된) 태그가 작동하는 구조이다.
여기서 유의할 점은, dataLayer에 직접 값을 대입하는 것이 아니라, dataLayer.push() 를 통해 값을 추가하여야 한다는 것이다.
window.dataLayer 변수를 덮어쓰지 않음: 데이터 영역을 직접 사용하면(예: dataLayer = [{'item': 'value'}]) ), dataLayer 의 기존 값이 덮어쓰여집니다. 태그 관리자 설치는 window.dataLayer = window.dataLayer || []; 를 사용하여 컨테이너 스니펫 또는 최적화 도구 페이지 숨김 스니펫 위의 소스 코드에서 최대한 높은 위치에 데이터 영역을 인스턴스화해야 합니다. dataLayer 가 선언된 후 dataLayer.push({'item': 'value'}) 를 사용하여 값을 추가합니다.
트리거를 작동시키는 방법에 대해선 아래서 다루도록 하고 여기서 한 가지 더 집고 넘어갈 점은, 트리거는 태그와 독립적이란 것이다. 예를 들면, A라는 트리거는 1,2,3,4 태그 모두에 부착될 수 있다. 이를 잘활용하면 하나의 트리거로 복수의 이벤트를 발생시킬 수 있다. 더 자세한 내용은 뒤에서 다루도록 하겠다.
[예제] 사용자가 AddToCart - GA4라고 정의한 태그 및 소스코드를 통해 작동 원리를 이해해보자.
아래 화면을 보면 이벤트 매개변수로 Items를, 유저 속성 값으로 {{UserID(uid)}} 와 {{DeviceType}}을 받고 있다. 우선, 이 두가지의 차이점이 궁금할테지만, 그 전에 이벤트와 이벤트 매개변수에 대해서 먼저 알아보자.
이벤트와 매개변수
이벤트와 매개변수는 자바스크립트 코드에서 dataLayer 전역객체에 넘겨주는 인자이다. 아래 코드를 보자.
첫 번째로, AddToCart라는 이벤트 이름을 넘겨주고 있다. 이는 GTM에서 설정한 트리거를 발생시키기 위한 이벤트 이름으로, GTM 트리거 구성에서 설정한 이벤트 이름이 코드상의 파라미터명과 다르면 작동하지 않으니 주의해야한다. 아래 Event - AddToCart 라는 트리거 구성을 보면 이벤트 이름이 AddToCart로 설정되어 있는 것을 확인 할 수 있다.
흐름을 정리하면 다음과 같다.
dataLayer에 AddToCart push → GTM은 해당 이벤트가 발생하였다고 인지하고 Event - AddToCart 트리거를 작동 → Event - AddToCart 트리거가 부착된 AddToCart - GA4 를 실행 → GA로 이벤트 값을 전송.
두 번째로, AddToCart와 함께 넘겨준 { items } 값은 sendEvent 함수 내에서 dataLayerValues.event_params로서 전역객체인 dataLayer에 넘겨주는 이벤트 매개변수이다. (제일 하단에 this.pushDataLaye(dataLayerValues) 부분).
AddToCart - GA4 태그 구성 화면에서 볼 수 있는 이벤트 매개변수로서, GTM 태그 구성에서 파싱되어 GA로 함께 전송된다.
해당 변수는, 태그매니저 작업공간 좌측 변수 탭에서 설정가능하다. 아래와 같이 자바스크립트 코드에서 event_params.itmes로 dataLayer에 push하면 GTM에서는 위에 {[Items}} 처럼 Items라는 변수명으로 받겠다는 의미이다.
세 번째, uId라는 값을 넘겨주고 있는데, 이는 GTM 태그 구성에서 사용자 속성에 사용되는 값이다.
코드에서는 dataLayerValues.event_params에 data(이벤트 매개변수)와 함께 uId라는 값으로 넘겨주고 있고, GTM 태그 구성에서 {{UserID(did)}} 포맷으로 받아 GA로 함께 전송되는 값이다.
마찬가지로, 변수탭에서 UserId(uid)는 uId라는 변수명으로 자바스크립트 코드에서 dataLayer에 push되는 값을 받겠다는 의미이다.
특히나 user_id는 실무에서 가장 속을 썩였던 부분이기도 한데, 그래서 좀 더 자세히 다뤄보도록 하겠다.
user_id
비로그인 상태의 사용자 행동 로그라면 상관없지만, 로그인 이후의 행동로그를 추적하고 할 때는 사용자 식별 값이 필요한데, 여기에 user_id 라는 값이 사용된다.
얼핏보면 사용자 id는 개인정보 아니냐 할 수 있겠지만 이는 실제 사용자 ID 값이 아닌 사내 개발시스템에서 부여한 사용자 고유 식별자일뿐이다. 클라이언트에서는 쿠키 또는 서버에 저장된 유저식별자 값을 사용하여 세팅한다.
그러면 위에서 설명한 것 처럼, dataLayer에 uId를 이벤트 전송시 함께 전달해주면 되지 뭐가 문제냐 할 수 있겠다. 결론부터 말하면 문제없다. 하지만 첫 단추를 잘꿰었다면 문제없지만, 아니라면 GTM 및 GA에서 user_id를 가져다가 사용하는 내부동작이 표면에 잘 드러나지 않기 때문에 디버깅에 애를 먹을 수 있다.
예를 들면, 로그인 이벤트 이후 상품을 클릭한 유저의 로그에 user_id가 누락된 경우 어디서 부터 잘못되었는지 찾기 힘들 수도 있단 말이다. 왜냐하면 user_id는 GTM 디버그 모드에서도 추적할 수 없도록 되어있어 코드에서 잘못되었는지, GTM 태그 구성에서 잘못되었는지 단번에 원인을 파악하기 힘들기 때문이다. 적어도 내 경험상은 그랬다.
사전 세팅 사항
기본적으로 user_id를 세팅하려면, 먼저 GA4 Configuration 태그를 구성해한다. 메뉴얼을 따라가면 쉽게 설정할 수 있다. 간단히 정리하면 아래와 같다.
- 태그 매니저 변수생성에서 GTM 변수명과 그에 대응되는 자바스크립트 코드 변수명을 생성한 후 (변수명은 자유이다)
2. GA4 Configuration 태그 구성에서 아래와 같이 변수에서 생성했던 UserID(uid)를 user_id 값에 설정을 하면된다.
user_id 세팅 원리
우리의 경우 해당 태그에 아래와 같이 2개의 트리거를 설정해두었다.
따라서 자바스크립트에서 아래와 같이 UidChagned라는 이벤트 이름을 dataLayer에 push하면 트리거가 작동하여 GA4 configuration 태그에서 user_id를 잘세팅하게 되는 것이다.
의도대로 잘호출이 되었다면 이후 동일 페이지내에서 사용자 행동은 user_id가 포함된 상태로 전송 할 수 있느냐? 정답은 아니다. 이를 가능하게 하려면, 위의 예시인 AddToCart 태그 구성 처럼 구성 태그에 [Configuration] GA4를 설정해주어야한다. 또한 위의 예시 처럼 태그 구성 내 사용자 속성으로 user_id를 세팅해주어야 한다.
한 가지 의문인 것은, 위처럼 해당 이벤트 태그 구성에서 사용자 속성으로 user_id를 설정하지 않은 태그일지라도 user_id가 잘세팅이 되는 경우가 있었다.
추측하기로는, 페이지내에서 user_id를 세팅하는 이벤트가 호출이 한번이라도 된 경우, 이후 동일 페이지 내 사용자 액션은 그에 해당하는 GTM 태그 구성에 user_id 설정이 없거나 구성태그가 설정이 되어있지 않더라도 GA에서 알아서 해당 이벤트 로그에 user_id를 매핑을 해주는 것으로 생각하고 있다.
위의 문제가 모두 해결되었다면 이제 모든 페이지에서 로그인 유저의 user_id가 누락없이 알아서 잘전송이 되느냐? 예상하다시피 정답은 아니다. 매 페이지 이동 시 uid를 다시 세팅해주지 않으면, 정확히는 [Configuration] GA4 구성 태그를 실행하는 트리거를 작동하지 않으면 user_id는 누락된다.
우리의 경우 setUid라는 함수로 필요한 과정을 추상화를 해두었고, 해당 함수를 매 페이지 랜딩시 호출하고있다.
과정을 좀 자세히 나열하면, setUid 함수 호출 → dataLayer에 UidChanged, uId push → GTM의 UidChanged라는 트리거를 작동 → 해당 트리거가 부착된 [Configuration] GA4 구성 태그를 실행 → user_id가 해당 페이지내 dataLayer 전역객체에 세팅이 되는 순서이다.
이는 uId를 쿠키 또는 서버에 저장해서 사용하도록 하여 클라이언트에서 간단히 구현 가능한 부분으로 생각된다.
Plus
GA 자동 수집 이벤트
GTM을 통해 GA를 설치하고 나면 GTM을 통해서만 이벤트를 GA로 보내게 되는 것이 아니다. GA에는 자체 수집 이벤트가 있는데 page_view와 같은 것들이 대표적인 예시다. GA4 자체수집 이벤트 목록 참고
따라서 해당 사항을 모르고 page_view와 같은 이벤트를 GTM을 통해서 추가로 핸들링하게 되면 이벤트가 중복전송이 되게 되는 것이다. 따라서 실무에서는 가급적이면 GA 자체수집 이벤트는 비활성화 하고 GTM을 통한 이벤트 핸들링으로 일원화를 하는게 좋다고 생각한다.
긴 글 읽어주신 모든 분들께 감사드리며 잘못된 내용은 댓글로 지적 주시면 책임감을 가지고 수정하겠습니다.