스팟잇 프로젝트중, PM으로부터 분석툴연결을 위한 요청이 들어왔습니다.
MVP 단계에서는 애플리케이션에 Google Analytics 스크립트를 직접 삽입하는 방식으로 이벤트를 추적했지만 새로운 분석툴이 추가될 때마다 코드를 수정하고 배포해야하는 번거로움이 있었습니다. 특히 GA 커스텀 이벤트뿐 아니라 Microsoft Clarity같은 도구의 연동요청이 추가되면서 추적환경을 한곳에서 관리하는 GTM 방식으로 전환하게 되었습니다.
이번 글에서는 Google Analytics(GA)와 Microsoft Clarity를 Google Tag Manager(GTM)로 관리하고 이를 프론트에서 연결하는 방법을 알아보겠습니다.
| 구분 | Google Analytics (GA4) | Microsoft Clarity |
|---|---|---|
| 하는 일 | 숫자 집계: 몇 명이 들어왔고, 어떤 버튼을 눌렀는지 카운트 | 화면 기록: 사용자가 페이지를 어떻게 움직였는지 영상/히트맵으로 보여줌 |
| 주로 쓰는 곳 | - 페이지뷰, 이벤트 클릭 수, 전환율 확인 - 유입 경로(검색/광고) 분석 | - 버튼/링크가 실제로 잘 눌리는지 확인 - 어디서 스크롤 멈추고, 어디서 많이 나가는지 확인 |
| 강점 | - 정량 데이터 (숫자 기반 지표) 확보에 강함 - 광고·마케팅과 잘 연동됨 | - 정성 데이터 (행동 패턴) 파악 가능 - 문제 상황을 영상으로 바로 재현 가능 |
| 단점 | - 왜 그런 행동을 했는지는 알기 어려움 | - 얼마나 많은 사용자가 그런 행동을 했는지는 약함 |
| 개발자 시선 | “이 버튼 클릭 수를 로그로 남겨서 나중에 볼 수 있다” | “유저가 버튼을 못 찾아서 클릭을 연타했구나” 같은 걸 영상으로 확인 가능 |

어플리케이션과 GTM을 연결하면 앱에서 일어나는 이벤트들을 GTM으로 보낼 수 있습니다. 앱이 이벤트를 보내면 GTM은 이벤트가 등록된 트리거가 있는지 확인하고 매칭되면 그 트리거와 연결된 태그정보를 GA 와 같은 분석툴에 전달할 수 있습니다.
리엑트를 사용한다면 아래 패키지로 손쉽게 태그 매니저를 붙일 수 있습니다.
npm install react-gtm-module
# (optional) 타입스크립트를 사용중이라면
npm install --save-dev @types/react-gtm-module
react-gtm-module라이브러리가 대신 GTM 스니펫을 DOM에 주입해줄 수 있도록 GTMInit컴포넌트를 만들고, Next를 사용하고 있으므로 루트 layout에 삽입해줍니다.
// GTMInit.tsx
'use client';
import { useEffect } from 'react';
import TagManager from 'react-gtm-module';
export default function GTMInit() {
useEffect(() => {
TagManager.initialize({
gtmId: process.env.NEXT_PUBLIC_GTM_ID!,
});
}, []);
return null;
}
//layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko" >
<body >
<GTMInit /> // ✅
{children}
</body>
</html>
);
}
먼저 트리거와 태그와의 관계를 짚고 넘어가 보도록 하겠습니다.
즉, 트리거가 조건을 만족하면 태그가 실행됩니다.
스팟잇은 팝업 스토어의 정보제공과 예약을 도와주는 서비스인데요. 이번에 PM이 요청한 것은 팝업 상세페이지의 예약하기 버튼이 클릭될 때마다 팝업 스토어의 식별자를 담은 이벤트를 수집하는 것이였습니다.
따라서 사용자가 "웨이팅하기"버튼을 클릭했을 때, 선택된 팝업ID와 추가 데이터들을 아래와 같이 넘겨주도록 하겠습니다.
const handleWaitingClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
if (status === 'NONE') { // 웨이팅하기 상태일때
const { text, url } = extractLinkMetaFromButton(e);
// GTM
TagManager.dataLayer({
dataLayer: {
event: 'popup_click',
popup_id: String(popupId),
link_text: text,
link_url: url,
},
});
...
}
};
GTM 콘솔창에서 트리거를 생성할 수 있습니다. 트리거 이름은 알아보기 쉽게 지으면 됩니다. 중요한점은 이벤트 이름(popup_click)과 dataLayer에서 푸쉬된 event의 이름이 동일해야 한다는 것입니다.
(해당 과정이 올바르지 않다면 디버깅 콘솔에서 트리거링 되지않습니다.)

동작원리를 간단하게 살펴보면 그 이유를 알 수 있습니다.
(1) 사용자가 웨이팅 버튼을 클릭합니다.
(2) 버튼에 연결된 이벤트 핸들러는 내부적으로 아래처럼 실행되며, 데이터 계층(dataLayer)에 이벤트 객체가 쌓이게 됩니다.
window.dataLayer.push({
event: 'popup_click', // ✅
popup_id: '8',
link_text: '웨이팅하기',
link_url: 'https://spotit.co.kr/detail/8',
});
(3) GTM 컨테이너는 항상 window.dataLayer를 감시중인데, (2) 번이 실행되면 GTM은 객체안의 event필드의 값을 확인해서 등록된popup_click이벤트가 있는지 찾습니다.
(4) 매칭된 트리거가 있다면, 해당 트리거에 연결된 태그(ex-GA4 이벤트)를 실행합니다.
트리거링 될때 GA4가 동작하도록 태그 유형을 선택하고 측정ID를 넣어줍니다.
- 측정 ID는 데이터 스트림(Data Streams) 메뉴의 상세 화면에서 (G-xxxx) 형태로 확인할수 있습니다.
- 해당 ID를 올바르게 입력해야 GTM -> GA4로 이벤트가 전달될 수 있습니다.

다음으로 이벤트 매개변수를 설정해줍니다. 이때 DLV 변수를 새롭게 만들어야 합니다.
우리는dataLayer.push()로 밀어넣은 값들을 GTM 안에서 꺼내서 써야 합니다. 이때 popup_id와 같은 서비스레이어 변수들은 GTM이 기본적으로 읽어오지 못합니다. popup_id를 GTM 변수로 등록해야 태그에서 활용할 수 있습니다.
콘솔창의 "변수"에서 새로 만들기 버튼을 클릭해 변수를 구성할 수 있습니다.

이제 만든 변수들은 태그에서 활용할 수 있습니다. 태그 -> 변수 선택란에서 새롭게 만든 변수를 선택해주면 됩니다.

사용자가 클릭하거나 페이지를 이동할 때 브라우저 DOM에서 바로 읽을 수 있는 변수들은 기본 변수로 다룰 수 있습니다.
Click 관련
Form 관련
Page 관련
기타
ex)
<button id="reserve" class="btn">웨이팅하기</button>
이런 버튼이 클릭된다면, Click Text = "웨이팅하기", Click ID = reserve, Click Classes = btn 처럼 읽어올 수 있습니다.
| DOM 변수 방식 (Click Text, Click ID, Page URL 등) | DataLayer 방식 (dataLayer.push) |
|---|---|
| 🚀 개발자가 코드를 건드리지 않아도 GTM에서 세팅이 가능합니다. | 🚀 이벤트 이름(popup_click)과 속성(popup_id, amount)은 서비스 로직에 종속되므로 UI 구조 바뀌어도 영향이 적습니다. |
| ⚠️ DOM 구조나 텍스트가 바뀌면 이벤트가 꺠질 수 있습니다. | 🚀 정확한 비즈니스 데이터(예약 ID, 결제 금액, 유저 상태 등)를 안정적으로 전달 가능 |
| ⚠️ CSS class, ID 네이밍 규칙 바뀌면 동일하게 깨짐 | 🚀 분석 툴/마케팅 툴 추가 시에도 동일한 데이터 재활용 가능 → 확장성 ↑ |
| ⚠️ PM/디자이너가 UI를 자주 바꾸는 프로젝트에서는 유지보수 부담 ↑ | ⚠️ 처음에는 개발자가 이벤트를 심어줘야 해서 초기 세팅 비용 ↑ |
만약 짧게 사용하려는 테스트나 캠페인이라면 DOM 변수방식이, 장기적인 서비스운영과 주요 이벤트 추적에서는 DataLayer 방식이 유리해 보입니다.
이번 경우는 웨이팅이라는 핵심 로직의 추적이 필요하므로 DataLayer 기반으로 이벤트를 설계하여 유지보수성을 높이는 방식을 선택하였습니다.

템플릿 갤러리에서 Microsoft Clarity (by Microsoft) 선택후, Project ID를 넣으면 태그를 쉽게 생성할 수 있습니다.
트리거/태그의 발화여부를 1차로 확인하는 방법
태그 관리자 페이지의 미리보기 버튼을 눌러 프리뷰 모드를 활성화할 수 있습니다.

Tags 탭에서 popup_click 태그가 fired 되었는지 확인할 수 있습니다.

GTM에서 GA4까지 이벤트가 실제로 전송되었는지 확인하는 2차 방법
GA4 콘솔의 DebugView를 통해 확인할 수 있습니다. 디버그뷰를 보기 위해서는 GTM 프리뷰 모드를 유지하거나 크롬 확장프로그램에서 GA Debugger를 켜야합니다.

실제 데이터가 GA 서버로 전송됐는지 확인하는 최종 방법
버튼을 클릭시에 collect?...&en=popup_click요청이 발생하는지 확인합니다.
tid와 같은 이벤트 파라이터가 포함되어 있어야 정상입니다.
제품에 GA와 같은 분석툴을 붙여보면서, 단순히 이벤트 로그를 남기는 작업이 아니라 제품을 더 잘 이해하기 위한 기반을 만드는 과정이라는 것을 느꼈습니다. 종종 이런 툴을 추가해주는 작업이 부가적인 일로 생각하기 쉬운데, 실제로는 이 데이터들은 PM과 디자이너가 제품을 개선하는 근거가 되기 때문에 프로덕트의 전체 품질과 직결되는 사항이란 것을 깨닫게 되었습니다. 또한 앞으로는 이벤트 하나를 심을 때도 “이 값이 단순 카운팅을 넘어서, 사용자 여정이나 전환 흐름을 어떻게 설명할 수 있을까?” 같은 제품 관점의 질문을 가져야 한다는 걸 배웠습니다.