GA4 : React 환경에서 User ID 수집 기능 개발하기

김혜진
teammint
Published in
10 min readJul 28, 2023

우리 서비스는 어떤 사람들이 이용할까?

회의에서 “서비스를 유저들이 얼마나 잘 이용하는지 알고 싶다”는 의견이 나왔습니다.

회원가입 시 수집하는 연차와 직무 정보를 이용해 우리 서비스의 코어 유저들은 몇 년 차인지, 어떤 직무를 갖고 있는지 유저의 페르소나를 그려보고자 했는데요. 웹 로그 분석 툴인 GA를 통해 유저들의 활동을 분석하고자 했습니다.

ga4 report
똑똑, 여러분들은 누구인가요?

그런데, GA 보고서를 살펴보니 앱 인스턴스 ID에 낯선 숫자들만 나열되어 있었는데요. ID를 눌러 사용자의 정보를 확인해 봐도 기기, 브라우저와 같은 정보만 나올 뿐, 어떤 사람인지 알 수 있는 고유한 정보는 없었습니다.

이 낯선 숫자들은 무엇일까?

보고서에 나온 앱 인스턴스 ID에 대해 이해하려면, 먼저 GA의 사용자 식별 기준에 대해서 알아야 합니다. GA는 사용자를 식별할 때 기본적으로 기기 기반의 클라이언트 ID (cid)를 사용합니다.

이러한 cid는 데이터를 정확하게 분석할 수 없다는 문제점을 갖고 있습니다. page_view 이벤트가 많이 발생했다 하더라도, 1명이 여러 대의 기기를 쓰다보니 어떤 사람들이 page_view를 더 많이 발생시키는지는 정확히 알 수 없던 것이죠.

개별 유저를 구분할 수 있는 방법을 찾아보던 중 User ID의 존재를 알게 되었는데요. 왜 uid가 유저 활동 분석에 유용한지 cid와의 비교를 통해 소개를 해드리려고 합니다.

1. User ID vs CID

User ID (사용자 ID)는 기기에서 공통으로 사용되는 고유한 식별자를 뜻합니다. 이러한 User ID는 왜 필요할까요? 자세하게 설명하기 전에, 먼저 클라이언트 ID (cid)에 대해 알아보겠습니다.

GA는 스마트폰(앱), PC(웹) 등 기기에 따라 사용자를 구분합니다. 이때, 기기에 대해 쿠키 기반의 클라이언트 ID를 부여하는데요. 실제로 개발자 도구에서 확인해 보면 cid가 포함되어 있는 _ga 쿠키를 확인할 수 있습니다.

cid의 단점은 데이터 분석이 정확하지 않을 수 있다는 것입니다. 만약 제가 medium를 앱으로 들어오고, 웹으로도 들어왔다면 medium은 2명의 사용자가 들어왔다고 판단하게 됩니다.

만약, 기기에서 공통으로 사용되는 uid가 있다면 고유한 사용자를 식별할 수 있습니다. 이러한 uid는 로그인 이후에 암호화된 값을 GA에 전송하는 방식으로 수집할 수 있습니다.

2. User ID 활용 사례

전체 유저 vs 로그인한 유저의 데이터를 비교할 수 있습니다.
아래는 GA에서 [모든 사용자]와 [사용자 ID로 로그인함]이 yes인 유저를 비교한 화면입니다. 로그인한 사용자의 참여 시간이 5배 이상 높은 걸 알 수 있었는데요. 단순 참여 시간뿐만 아니라 이벤트 발생 횟수도 비교할 수 있습니다.

ga4 user id

유저 활동 분석에 활용할 수 있습니다.
GA의 [탐색] 메뉴에서는 [사용자 개별화 분석] 보고서를 만들 수 있는데요. 이 때, 사용자 개별화 분석 보고서에 있는 앱 인스턴스 ID는 uid 수집을 따로 하지 않으면 기기 id인 cid가 사용됩니다.

누구인지 너무 궁금하지만, 기기 ID만 있어서 아쉽다

이렇게 활동 로그가 쌓였지만, cid만으로는 사용자가 어떤 사람인지 정확하게 알 수 없습니다. 하지만 이제 uid를 사용한다면 GA는 여러 기기를 1명의 사용자로 식별하게 됩니다. 이와 더불어 유저의 멤버십 등급, 마지막 접속일 등을 사용자 속성으로 uid와 함께 전송하게 되면 GA상에서 유저의 정보를 더 정확하고 자세하게 알 수 있습니다.

3. User ID 주의사항

uid, 사용자 속성은 개인을 식별할 수 없는 값을 사용해야 합니다. 이메일, 주민등록번호 앞자리 등 개인을 식별할 수 있는 값들을 전송하게 되면 GA의 정책을 위반하게 된다는 점을 주의하셔야 합니다. (참고 : [GA4] User-ID를 활용한 플랫폼 간 활동 측정)

만약 회원 번호 등의 유저 DB를 활용하고자 한다면, 더 이상 식별할 수 없는 형태로 변경하기 위해 최소 SHA-256을 활용한 암호화가 요구되는데요. 전송하는 값이 적절한 암호화가 이루어졌는지 꼭 검토하셔야 합니다.

4. 개발은 어떻게 하나요?

GA 연동은 보통 프론트엔드 개발자가 진행하게 되는데요. 개발자가 해야 할 일은 3가지입니다. 하나씩 자세하게 살펴보겠습니다.

  • 스크립트 삽입
  • User ID와 사용자 속성 전송하기
  • GTM/GA 콘솔 세팅

5. 스크립트 삽입

만약 GTM, GA4를 모두 사용하신다면 GTM 스크립트만 설치하면 됩니다. 저는 GTM을 사용하기 때문에 GTM 스크립트를 설치했는데요. 보통은 이러한 코드들을 넣으라는 가이드가 나옵니다. 이 가이드를 그대로 따라 하셔도 되는데, 개발자에게 더 편한 방법이 있습니다.

google tag manager script

저는 GTM 설치를 편하게 도와주는 react-gtm-module 라이브러리를 활용했는데요. 사용 방법이 매우 쉽습니다.

// 위치는 Layout.tsx 등.. 
// 모든 페이지가 공유하는 파일에 넣어주세요

import TagManager from "react-gtm-module";

useEffect(() => {
TagManager.initialize({
gtmId: GTM ID 입력,
});
}, []);

이렇게 init을 하면 공식 가이드에 있는 스크립트 코드가 그대로 삽입이 됩니다. 스크립트 코드가 실제로 잘 삽입되었는지 확인하고 싶다면, 개발자 도구 elements에서 확인할 수 있습니다.

6. User ID와 사용자 속성 전송하기

여기서 살짝 까다로울 수 있는데요. User ID와 사용자 속성은 initialize를 하기 전에 dataLayer에 미리 넣어줘야 합니다.

처음에는 init을 하고 dataLayer에 user_id를 담았더니, user_id 전송이 안 되는 문제가 있었는데요. dataLayer에 미리 넣어서 init을 해야한다는 답변이 있어, 이를 참고해 코드 순서를 반대로 해보니 잘 전송되는 걸 확인할 수 있었습니다.

import TagManager from "react-gtm-module";

useEffect(() => {
TagManager.dataLayer({
dataLayer: {
user_id: "value",
user_grade: "value",
lastLoggedIn: "value",
},
});

TagManager.initialize({
gtmId: GTM ID 입력,
});
}, []);

또한, user_id를 받아오는 API 가 있다면 API 호출 결과를 받아오기 전까지는 gtm init이 되지 않도록 ealry return을 해줘야 합니다.

import TagManager from "react-gtm-module";

const { loading, 그 외 값들.. } = useSessionQuery();

useEffect(() => {
if (!loading) return;

TagManager.dataLayer({
dataLayer: {
user_id: "value",
user_grade: "value",
lastLoggedIn: "value",
},
});

TagManager.initialize({
gtmId: GTM ID 입력,
});
}, [loading]);

user_id와 사용자 속성은 후속 글에서 설명할 GA 구성태그의 매개변수이기 때문인데요. 구성 태그의 매개변수는 정적으로 유지되기 때문에, 한번 값이 정해지면 새로고침을 하지 않는 이상 값이 동적으로 바뀌지 않는 현상이 있었습니다.

GA4 구성 태그에서 설정된 매개변수는 페이지에서 발생하는 모든 이벤트에서 정적으로 유지됩니다. 매개변수는 구성 태그가 다시 실행될 때만 (일반적으로 다음에 페이지가 로드될 때) 새로고침됩니다.
출처 : [GA4] Google 태그 관리자에서 Google 애널리틱스 4 태그 구성하기

이처럼 동적으로 변경되는 매개변수가 아니기 때문에, loading 중일 때는 ealry return을 해서 dataLayer에 user_id가 undefined로 할당되지 않도록 해야 했습니다.

사실 처음에는 user_id를 보냈는데, GA에서 사용자로 로그인함 기준이 활성화되지 않아서 당황스러웠는데요. loading에 영향을 받는 점과, 공식 문서의 정적 유지라는 말을 보고 처음 값이 그대로 유지된다는 결론을 내릴 수 있었습니다.

만약 서비스에 유저 정보를 변경하는 기능이 있고, 그 유저의 정보가 user_id, 사용자 속성 매개변수로 전달이 된다면 정보 변경 후 reload를 해주는 것이 좋습니다.

7. GTM / GA4 콘솔 세팅

코드 삽입과 더불어 GTM / GA4 콘솔도 세팅을 해줘야 합니다. 해야 할 일은 총 4가지입니다.

  • GTM : 변수 등록하기
  • GTM / GA4 구성 태그 만들기
  • GTM : GA4 이벤트 태그에서 구성 태그 참조하기
  • GA4 : 맞춤 측정 기준 등록하기

GTM : 변수 등록하기
구글 태그 매니저 콘솔에 들어가서 dataLayer의 매개변수들을 등록해야 합니다. 앞서 user_id, user_grade, lastLoggedIn을 전송하는 코드를 작성했는데요. GTM 콘솔에서도 이러한 이름의 매개변수들이 데이터 영역에 들어올 것이라고 등록을 해줘야 합니다.

google tag manager variables

GTM : GA4 구성 태그 만들기
모든 GA4 이벤트의 구성(config)이 되는 구성 태그를 만들어야 합니다. 이벤트 태그가 구성 태그를 참조하게 되면, 이벤트가 발생했을 때 user_id와 사용자 속성이 함께 전달되게 됩니다. 즉, 모든 이벤트에서 공통으로 포함할 매개변수를 구성 태그에서 설정하는 것이죠.

google tag manager config tag

GTM : GA4 이벤트 태그에서 구성 태그 참조하기
이벤트 태그를 만들 때, 구성 태그로 앞서 만든 태그를 선택해 주세요. 여기까지 GTM 세팅을 모두 하셨다면 배포를 해주시면 됩니다.

google tag manager event tag

GA4 : 맞춤 측정 기준 등록하기
GA4의 [관리] — [맞춤 정의]로 들어가셔서 맞춤 측정기준에 user_id를 제외한 사용자 속성들을 추가해 주세요.

ga4 custom dimension

참고로 user_id는 예약된 키워드이기 때문에 등록이 불가능합니다. GA4에는 추가하지 마시고, GTM 변수에만 user_id를 변수로 추가해 주세요.

ga4 user id

이렇게 하면 user_id가 GA4로 수집되고 [사용자 ID로 로그인함] 측정 기준이 자동으로 추가됩니다. 많이 복잡하지만 한 번만 잘 세팅해 주면 됩니다!

ga4 image

Next Step

지금까지 React 환경에서 User ID 수집 기능을 개발하는 법에 대해 다뤄보았는데요, 추후 GA의 개발 / 프로덕션 환경을 설정하는 법도 다뤄볼 예정입니다. 읽어주셔서 감사합니다 :)

참고 자료

--

--