이 글에서는 GTM와 GA4를 연동하여 AB 테스트 이벤트를 수집하는 방법을 다룬다.
우리 서비스에서는 기존에 GA4를 사용하여 데이터를 수집했지만, 각 버튼의 클릭률을 자세히 알고 싶어 GTM을 도입했다.
GTM을 적용한 후 각 버튼의 클릭률은 잘 수집되었지만, 기존에 사용하던 window.gtag 코드로 직접 수집하던 이벤트들은 더 이상 수집되지 않았다.
GTM을 설치하면서 기존의 gtag 관련 스크립트와 설정을 모두 삭제했기 때문이다. GTM만 설치 된 상태에서는 window.gtag 호출로는 GA4 이벤트가 수집되지 않는다.
| 방식 | 설명 | 특징 |
|---|---|---|
| window.gtag('event', ...) | gtag.js 직접 호출 방식 | GTM 없이 gtag.js 직접 삽입 시 정상 작동 |
| dataLayer.push({event: ...}) | GTM이 감지하는 이벤트 큐에 이벤트를 넣는 방식 | GTM으로 GA4 설정 시 필수, 이벤트 이름과 트리거 연결 필요 |
이벤트를 dataLayer.push 방식으로 보내고, GTM에서 트리거/태그를 설정했다.
// 변경 전 - gtag 직접 호출
window.gtag('event', eventName, parameters);
// 변경 후 - dataLayer.push로 전환
window.dataLayer.push({
event: 'eventName',
...params
});
예를 들어, 아래와 같이 이벤트를 보낸다면
sendGAEvent('map_navigation_click_header', {
test_name: 'map_ui_test',
variation: testGroup,
from_path: location.pathname,
to_path: '/map',
component: 'header_nav_a',
});
![]() | ![]() | ![]() |
|---|
이런식으로 GTM에서 변수, 트리거, 태그를 각각 만들어 일일이 설정해줬다.
이후 구글 애널리틱스에 잘 반영되는 것을 확인할 수 있었다.
A/B 테스트를 위한 이벤트였기 때문에, 사용자가 A인지 B인지를 구분할 사용자 속성도 별도로 수집해야한다. 이 속성은 사용자가 사이트에 처음 접속할 때 쿠키에 저장되는 정보로 결정되기 때문에, 마우스 클릭 이벤트처럼 특정 액션이 아니라 접속 시점(ABProvider에서) 적용된다.
window.dataLayer = window.dataLayer || [];는 반드시 GTM 스크립트보다 먼저 선언해야 한다. 그래야 GTM이 dataLayer에 push되는 이벤트를 실시간으로 감지해서 태그를 실행할 수 있다. 그래서 index.html의 GTM 스크립트 선언 이전에 dataLayer 초기화 코드를 추가했다.
// index.html
<head>
...
<script>
window.dataLayer = window.dataLayer || []; // GTM보다 먼저 선언
</script>
...
</head>
2.초기화가 GTM 컨테이너(작업 환경)가 로드되는 부분이고 dataLayer를 준비하는 단계다.
3.컨테이너 로드는 dataLayer에 push된 이벤트를 GTM이 감지하는 단계이다.
이 단계들이 끝난 후에 유저 속성 태그가 실행되는 것을 미리보기에서 확인할 수 있었다!
Q. window.dataLayer = window.dataLayer || [];를 html 상단이 아니라, 사용자 속성을 설정하는 코드 내에서 선언하면 안 되나?
window.dataLayer = window.dataLayer || []; // 여기
// GA4에 사용자 속성 설정
const userProperties: Record<string, string> = {};
Object.entries(testGroups).forEach(([testName, group]) => {
userProperties[`ab_test_${testName}`] = group;
});
window.dataLayer.push({
event: 'set_user_properties',
user_properties: userProperties,
});
A. 권장하지 않는다.
window.dataLayer가 아직 선언되지 않은 상태에서 코드가 실행된다면 GTM이 해당 배열을 감지하지 못할 수 있다.
실제로 코드 내부에서 선언해봤는데 정상 동작은 된다. 하지만 안전하게 index.html의 에서 먼저 선언했다.
테스트 환경에서는 window.dataLayer가 없기 때문에 아래와 같은 에러가 발생할 수 있다.
TypeError: Cannot read properties of undefined (reading 'push')
테스트 코드에서 미리 dataLayer를 선언해주면 된다.
beforeEach(() => {
(window as any).dataLayer = [];
});
끝.