개념
아무도 테스트하지 않는 기능
결제 버튼이 안 눌리면 30분 안에 신고가 들어온다. 그런데 결제 버튼을 눌렀을 때 발사돼야 할 purchase 이벤트가 안 나가면 아무도 모른다. 몇 주 뒤 마케팅팀이 "전환율이 이상하다"고
말할 때쯤이면 그 기간의 데이터는 복구할 수 없다. 수집되지 않은 이벤트는 소급해서 만들 수 없기 때문이다.
이 자리가 대체로 비어 있다. 마케터는 설계를 하고, 개발자는 구현을 하고, 설계대로 구현됐는지 확인하는 사람이 정해져 있지 않다. QA 가 그 자리를 가져가면 조직 전체의 의사결정 품질이 올라간다.
이 레슨은 그 검증 절차를 다룬다. 다루는 층은 셋이다.
① 웹 페이지의 dataLayer 개발자가 심은 값 — "무엇을 밀어 넣었나"
↓
② 태그 관리자(GTM) 트리거와 태그 — "언제 무엇을 보내기로 했나"
↓
③ 분석 도구(GA4) 수집된 결과 — "실제로 무엇이 도착했나"세 층을 각각 확인할 수 있어야 결함이 어느 층에서 생겼는지 를 말할 수 있다. "GA 에 데이터가 없다"만으로는 개발자도 마케터도 움직이지 못한다.
먼저 설계를 본다 — 측정 계획 검토
구현을 확인하기 전에 설계가 규칙을 지키는지 본다. 요구사항 리뷰(모듈 2)와 같은 일을 이벤트 설계서에 하는 것이다. GA4 의 규칙 중 QA 가 근거로 쓸 만한 것은 이 정도다.
이름 규칙
- 이벤트 이름은 대소문자를 구분한다.
add_to_cart와Add_To_Cart는 서로 다른 이벤트로 집계된다. 설계서에 표기가 섞여 있으면 그 자체가 결함이다 - 이름은 letter 로 시작하고 영문자·숫자·밑줄만 쓴다. 공백은 쓸 수 없다
firebase_,ga_,google_로 시작하는 이름은 예약돼 있어 쓸 수 없다. 매개변수 이름은 여기에 더해 밑줄로 시작하거나gtag.로 시작할 수 없다page_view,session_start,click,scroll,error처럼 GA4 가 자동으로 수집하는 이름을 커스텀 이벤트로 다시 쓰면 안 된다. 설계서에서 가장 자주 나오는 위반이다
수집 한도 (현재 GA4 기준, 원문에서 확인한 값)
| 항목 | 한도 |
|---|---|
| 이벤트 이름 길이 | 40자 |
| 이벤트당 매개변수 수 | 25개 |
| 매개변수 이름 길이 | 40자 |
| 매개변수 값 길이 | 100자 (page_title 300, page_referrer 420, page_location 1,000) |
| 속성당 사용자 속성 | 25개 (이름 24자, 값 36자) |
값 길이 100자 가 실무에서 자주 걸린다. 상품명·검색어·페이지 제목을 매개변수로 넣는 설계에서 긴 값이 잘려 나가고, 잘린 값은 그대로 집계된다. 설계서에서 "긴 문자열이 들어갈 수 있는 매개변수"를 표시하고 경계값을 시험 항목으로 잡는다 — 경계값 분석(모듈 3)을 태그에 적용하는 것이다.
전자상거래 이벤트는 필수 매개변수가 정해져 있다. purchase 는 currency·value·transaction_id·items 가 필요하고, add_to_cart·begin_checkout 은 currency·value·items 가
필요하다. value 는 상품별 price * quantity 의 합이며 배송비·세금은 제외한다. transaction_id 가 유일하지 않으면 매출이 중복 집계된다 — 레슨 6에서 이 문제를 정면으로 다룬다.
1층 — dataLayer 읽기
GTM 을 쓰는 사이트는 페이지의 값을 dataLayer 라는 배열에 밀어 넣고, GTM 이 그것을 읽어 태그를 발사한다. 구매 완료 페이지의 푸시는 보통 이렇게 생겼다.
window.dataLayer = window.dataLayer || [];
// 이전 이벤트의 ecommerce 객체를 먼저 비운다 (값이 섞이는 것을 막는 Google 권장 절차)
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'T-880123',
value: 52000,
tax: 4727,
shipping: 3000,
currency: 'KRW',
coupon: 'WELCOME10',
items: [
{ item_id: 'SKU-1001', item_name: '무선 마우스', price: 26000, quantity: 1 },
{ item_id: 'SKU-2044', item_name: '키보드 커버', price: 26000, quantity: 1 }
]
}
});QA 는 브라우저 콘솔에서 이 배열을 직접 볼 수 있다.
// 현재까지 쌓인 전체
dataLayer
// 마지막 푸시만
dataLayer[dataLayer.length - 1]
// purchase 이벤트만
dataLayer.filter(d => d.event === 'purchase')여기서 확인할 것.
- 값이 비어 있지 않은가 —
undefined·빈 문자열·0이 들어간 매개변수는 수집돼도 쓸모가 없다 - 타입이 맞는가 —
value: '52000'(문자열)과value: 52000(숫자)은 다르다. 문자열이면 집계에서 문제가 된다 - 화면 값과 같은가 —
value가 실제 결제 금액과 맞는지,items의 수가 주문 상품 수와 같은지. 여기서 레슨 1의 조회 와 대조하면 완벽하다 - 몇 번 푸시됐는가 — 같은
purchase가 두 번 들어 있으면 그게 곧 매출 중복이다. 새로고침·뒤로가기로 재현해 본다
2층 — GTM 미리보기로 "발사됐는가" 확인
GTM 컨테이너에 접근 권한이 있다면 미리보기 모드가 가장 정확하다. 절차는 이렇다(현재 콘솔 기준).
- GTM 작업공간(Workspace) 오른쪽 위의 미리보기(Preview) 를 누른다
- Tag Assistant 가 새 탭에서 열린다. 확인할 사이트 URL 을 입력하고 Connect 를 누른다
- 사이트가 새 창에서 열리고 "Connected" 표시가 뜬다. Tag Assistant 로 돌아와 Continue 를 누르면 디버그 화면이 나온다
- 사이트에서 검증할 동작을 수행한다(장바구니 담기, 결제 완료 등)
- 디버그 화면 왼쪽의 이벤트 목록 에서 해당 이벤트를 클릭한다
그 시점에서 볼 것이 넷이다.
| 탭 | 무엇을 확인하나 |
|---|---|
| Tags Fired | 발사돼야 할 태그가 실제로 발사됐는가 |
| Tags Not Fired | 발사되지 않은 태그와 그 이유(어느 트리거 조건이 안 맞았는가) |
| Variables | 태그가 읽은 변수 값. 여기서 undefined 가 보이면 원인이 확정된다 |
| Data Layer | 그 이벤트 시점의 dataLayer 상태 |
"Tags Not Fired" 를 보는 것이 핵심이다. 발사 안 된 태그의 트리거 조건을 펼치면 어느 조건에서 걸렸는지 를 보여 준다. 대부분의 수집 결함이 여기서 끝난다 — 트리거 조건이 페이지
경로를 /order/complete 로 걸어 뒀는데 실제 경로가 /order/complete/ 였다든가 하는 식이다.
3층 — GA4 DebugView 로 "도착했는가" 확인
GTM 에서 발사됐어도 GA4 에 도착했다는 보장은 없다. 마지막 확인은 DebugView 다.
디버그 모드를 켜는 방법(공식 문서 기준)
- Tag Assistant / GTM 미리보기 를 쓰면 디버그 모드가 자동으로 켜진다. 가장 간단한 방법이다
- gtag.js 직접 구현이면 설정에
debug_mode를 넣는다 —gtag('config', 'G-XXXXXXX', { 'debug_mode': true }); - GTM 이면 Google 태그 설정 또는 개별 이벤트 태그에
debug_mode매개변수를true로 넣는다 - 끄려면 매개변수를 제거한다.
false로 바꾸는 것으로는 꺼지지 않는다 — 문서에 명시된 주의사항이다
보는 곳: GA4 속성의 관리(Admin) → 데이터 표시(Data display) → DebugView. 콘솔 메뉴 이름은 바뀔 수 있으므로, 못 찾으면 관리 화면에서 "DebugView" 를 검색한다.
화면은 세 부분이다.
- 초 단위 스트림 — 최근 60초의 이벤트가 순서대로 흐른다. 이벤트를 클릭하면 매개변수와 값이 펼쳐진다
- 분 단위 스트림 — 최근 30분의 분당 이벤트 수
- 상단 이벤트·사용자 속성 — 빈도 높은 이벤트와 현재 사용자 속성 상태
기기 선택기가 있어 여러 기기를 구분해 볼 수 있다. 한 가지 함정이 있는데, 동의 모드(consent mode)나 클라이언트 측 개인정보 통제가 적용돼 있고 사용자가 분석 쿠키에 동의하지 않았다면 이벤트가 나타나지 않는다. "DebugView 에 안 보인다"가 곧 "태그가 깨졌다"는 아니다. 동의 배너를 어떤 상태로 두고 테스트했는지를 항상 기록한다.
층을 건너뛰지 않는 확인 — 네트워크 탭
세 층 중 어디서 끊겼는지 가장 빨리 알려 주는 것이 개발자 도구 네트워크 탭이다(모듈 9 레슨 10). GA4 는 수집 요청을 collect 경로로 보내므로 필터에 collect 를 넣으면 잡힌다(도메인은
지역·설정에 따라 다를 수 있으니 경로 조각으로 거르는 편이 안전하다).
요청을 클릭해 쿼리 문자열이나 페이로드를 보면 실제 전송된 값이 보인다. 자주 보는 키는 이 정도다.
| 키 | 뜻 |
|---|---|
tid | 측정 ID (G- 로 시작). 운영과 테스트 속성이 바뀌지 않았는지 확인하는 열쇠 |
en | 이벤트 이름 |
ep.* | 이벤트 매개변수 (문자열) |
epn.* | 이벤트 매개변수 (숫자) |
cid | 클라이언트 ID |
tid 확인은 습관으로 만들 가치가 있다. 스테이징에서 테스트한 데이터가 운영 속성으로 들어가 실적을 오염시키는 사고 가 드물지 않다.
판정표 — 어느 층에서 끊겼나
| dataLayer | GTM 미리보기 | DebugView | 판정 |
|---|---|---|---|
| 푸시 없음 | 이벤트 없음 | 없음 | 프런트엔드 구현 누락 — 개발팀 |
| 푸시 있음 | Tags Not Fired | 없음 | 트리거 조건 오류 — GTM 담당 |
| 푸시 있음 | Tags Fired | 없음 | 전송 차단(동의·광고 차단기·CSP) 또는 측정 ID 오류 |
| 푸시 있음 | Tags Fired | 있으나 값이 다름 | 변수 매핑 오류 — GTM 담당 |
| 푸시 값이 틀림 | Tags Fired | 틀린 값 그대로 | 데이터 원천 오류 — 개발팀 |
이 표 한 장이 이 레슨의 결론이다. 결함 리포트에 어느 행에 해당하는지 를 적으면 담당이 자동으로 정해진다.
실무에서 왜 필요한가
수집 결함은 되돌릴 수 없다 는 점에서 다른 결함과 성격이 다르다. 기능 결함은 고치면 그 이후 사용자가 정상 경험을 하지만, 3주간 수집되지 않은 purchase 이벤트는 영원히 빈칸이다. A/B
테스트를 그 기간에 돌렸다면 실험 결과도 함께 버려야 한다.
영향 범위도 넓다. 수집 데이터는 마케팅 예산 배분, 기능 우선순위, 투자 보고, 광고 최적화에 쓰인다. 중복 purchase 로 전환이 1.4배 부풀려지면 그 숫자를 근거로 광고비가 더 집행된다.
QA 가 릴리스 전에 30분 확인해서 막을 수 있는 일이다.
실무 감각으로 하나 덧붙이면, 릴리스 체크리스트에 태그 확인을 한 줄 넣는 것만으로도 절반은 잡힌다. 태그는 프런트엔드 리팩터링에서 가장 잘 깨진다. 버튼을 감싸는 DOM 구조가 바뀌면 GTM 의 클릭 트리거가 조용히 죽고, 기능 테스트는 전부 통과한다.
채용시장에서의 위치
"GA·GTM 이해" 또는 "데이터 기반 QA"는 커머스·플랫폼·그로스 조직 공고에서 우대사항으로 자주 보이지만, 이걸 실제로 검증해 본 QA 는 드물다. 면접에서 판정표를 설명할 수 있으면 그 자체로 차별점이 된다 — "dataLayer, GTM 미리보기, DebugView 를 각각 확인해서 어느 층에서 끊겼는지 나눠 리포트했습니다"는 문장은 마케팅·개발 양쪽과 일해 본 사람만 쓸 수 있다.
프로덕트 애널리스트·그로스 QA·데이터 QA 로 넘어가는 다리이기도 하다(모듈 45). 제품 지표를 읽는 쪽으로 가려면 그 지표가 어떻게 수집되는지 를 먼저 알아야 하고, 순서가 반대인 사람은 숫자를 의심할 줄 모른다.