-
구글 애널리틱스 (GA4) for developersReact.js & Next.js 2023. 7. 16. 21:44
Prerequisites
- typescript
- next
- google analytics default config
- google analytics debugger
References
Unlock the Power of Google Analytics 4 in Just 5 Minutes with Next.js and TypeScript (2023 Edition)
Unlock the Power of Google Analytics 4 in Just 5 Minutes with Next.js and TypeScript (2023 Edition)
If you own a website, you know how important it is to track its performance and make data-driven decisions to improve its user experience…
aaron-janes.medium.com
Repo
https://github.com/dlwnsgml0328/GA4
GitHub - dlwnsgml0328/GA4: Learning GA4
Learning GA4. Contribute to dlwnsgml0328/GA4 development by creating an account on GitHub.
github.com
$ git clone <https://github.com/dlwnsgml0328/GA4.git>
junhee | main
Get started by editing src/pages/index.tsx
ga-4.vercel.app
📦 folder structure
📦 ├─ .eslintrc.json ├─ .gitignore ├─ README.md ├─ next.config.js ├─ package-lock.json ├─ package.json ├─ public │ ├─ favicon.ico │ ├─ next.svg │ └─ vercel.svg ├─ src │ ├─ components │ │ ├─ HeadMeta │ │ │ └─ index.tsx │ │ └─ Header │ │ └─ index.tsx │ ├─ lib │ │ └─ gtag │ │ ├─ index.ts │ │ └─ types.d.ts │ ├─ pages │ │ ├─ _app.tsx │ │ ├─ _document.tsx │ │ ├─ api │ │ │ └─ hello.ts │ │ ├─ index.tsx │ │ ├─ magazine │ │ │ ├─ [id].tsx │ │ │ └─ index.tsx │ │ └─ movie │ │ ├─ [name].tsx │ │ └─ index.tsx │ └─ types │ └─ index.d.ts ├─ tsconfig.json └─ yarn.lock ©generated by [Project Tree Generator](<https://woochanleee.github.io/project-tree-generator>)
components
- HeadMeta: 메터태그 설정을 위한 컴포넌트입니다
- Header: 헤더를 위한 컴포넌트입니다
lib/gtag
- index.ts: google analytics 태깅을 위한 폴더입니다
- **types.d.ts: lib/**gtag 함수들에 들어갈 타입을 정의한 폴더입니다
pages
- magazine: 라우팅 확인을 위한 magazine 페이지입니다
- movie: 라우팅 확인을 위한 movie 페이지입니다
- index.tsx: 메인 페이지입니다
types
- index.ts: 글로벌 선언을 위한 타입 파일입니다.
목차
- 기본 gtag 흐름 이해하기
- _app.tsx에 추적 코드 태깅하기
- 자동 수집 이벤트 발생시키기
- 커스텀 이벤트 발생시키기
- GA4에 이벤트 만들기
- GA4에서 결과 보기
1. 기본 gtag 흐름 이해하기
앞서 소개했지만, 간단하게 짚고 넘어가겠습니다.
이벤트 종류: 자동 이벤트와 수동 이벤트
GA4 이벤트는 자동으로 생성하느냐 분석가가 수동으로 생성하느냐에 따라 자동 이벤트와 수동 이벤트로 분류할 수 있습니다.
또 자동 이벤트는 일반 이벤트인지 향상된 측정 이벤트인지에 따라 자동 수집 이벤트와 향상된 측정 이벤트로 분류할 수 있고, 수동 수집 이벤트는 GA4가 미리 정한 방식으로 생성하느냐 분석가가 완전히 자기만의 방식으로 생성하느냐에 따라 추천 이벤트와 맞춤 이벤트로 분류할 수 있습니다.
자동 수집 이벤트
자동 이벤트는 일반 자동 이벤트인지 ‘향상된 측정’ 옵션을 설정하면 자동 수집되는 이벤트인지에 따라 자동 수집 이벤트(Automatically collected events)와 향상된 측정 이벤트(Enhanced measurement events)로 나뉩니다.
이는 단순히 GA4의 [관리 > 속성 > 데이터 스트림 > 향상된 측정] 옵션을 적용해서 자동 수집되느냐 그렇지 않느냐의 차이입니다. ‘향상된 측정 이벤트’ 옵션은 데이터 스트림을 생성할 때 자동으로 적용됩니다. ‘페이지 조회’ 등 현재 기준 7개의 추가 이벤트가 수집됩니다.
자동 수집 이벤트는 GA4가 미리 정의해 놓은 이벤트이며, 어떤 조건을 만족할 때 GA4가 자동으로 발동시킵니다. 예를 들어 first_visit 이벤트는 사용자가 서비스를 처음으로 방문하거나 실행할 때, page_view 이벤트는 특정 페이지가 로드될 때 발생합니다. 자동 수집 이벤트는 분석가가 따로 이벤트가 발동하도록 태깅(제작)할 필요가 없으며, GA4가 특정 조건에 대해 미리 만들어 놓은 이벤트라고 이해하면 됩니다.
주요한 자동 수집 이벤트의 종류는 다음과 같습니다.
개발자로서 먼저 자동 수집 이벤트를 활성화시키고, 맞춤 이벤트를 추가적으로 만들어 보도록 하겠습니다.
2. _app.tsx에 추적 코드 태깅하기
.env
구글 애널리틱스에서 제공하는 ‘G-’로 시작하는 값을 통해 우리의 웹 서비스와 GA4를 연결합니다.
NEXT_PUBLIC_GA_ID=G-로시작하는태그
pages/_app.tsx
<> <Script strategy='afterInteractive' src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`} /> <Script id='ga4_init' strategy='afterInteractive' dangerouslySetInnerHTML={{ __html: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${gtag.GA_TRACKING_ID}', { page_path: window.location.pathname }); `, }} /> <Header /> <Component {...pageProps} /> </>
- next script를 통해 gtag 코드를 태깅하였습니다
- ‘afterInteractive’라는 전략(startegy) 프로퍼티를 사용해야 Script 태그에서 gtag를 원활하게 사용할 수 있습니다
- afterInteractive: (default) Load the script early but after some hydration on the page occurs.
3. 자동 수집 이벤트 발생시키기
해당 태그 설정 만으로도 자동 수집 이벤트는 활성화됩니다. 해당 내용을 테스트해보고 싶다면, ‘구글 익스텐션인 구글 애널리틱스 디버거’를 사용할 수 있습니다.
어떤 이벤트인지 자세히 다루지는 않지만, 위의 자동 수집 이벤트 테이블에 적어둔 이벤트가 발생하는 것을 알 수 있습니다.
4. 커스텀 이벤트 발생시키기
next.js 는 기본적으로 서버 사이드 환경을 제공하고 있기 때문에, window 이벤트를 참조하는데 제약이 있을 수 있습니다. gtag의 경우, 기본적으로 window 태그에 들어있지 않습니다. 따라서 gtag를 다운로드한 이후에 window 환경에 등록하여 사용할 수 있도록 선언해줘야 합니다.
types/index.d.ts
declare module 'gtag.js';
lib/gtag/types.d.ts
기본적으로 Developer guide를 통해 알 수 있는 gtag 기본 이벤트에 대한 타입이 있습니다.
Dev guide
Measure Google Analytics Events | Universal Analytics for Web (gtag.js) | Google for Developers
Google 애널리틱스 이벤트 측정 | 웹용 유니버설 애널리틱스(gtag.js) | Google for Developers
유니버설 애널리틱스(UA)는 2023년 7월 1일부터 지원이 중단되어 더 이상 데이터를 처리하지 않습니다. 2023년 10월 1일부터 애널리틱스 360 속성이 더 이상 작동하지 않습니다. Google 애널리틱스 4로
developers.google.com
Implement custom event
export interface EventProps { action: string category: string label: string value: string | number }
해당 코드를 바탕으로 커스텀 이벤트를 등록하도록 하겠습니다.
lib/gtag/index.ts
import { EventProps } from './types'; export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID || ''; // <https://developers.google.com/analytics/devguides/collection/gtagjs/pages> export const pageview = (url: string) => { window.gtag('config' as 'config', GA_TRACKING_ID, { page_path: url, }); }; // <https://developers.google.com/analytics/devguides/collection/gtagjs/events> export const event = ({ action, category, label, value }: EventProps) => { try { if (window) { window.gtag('event', action, { event_category: category, event_label: label, value: value, // send_to: GA_TRACKING_ID, }); } } catch (err) { console.log(err); } };
두 가지의 함수를 정의하였습니다.
- pageview
- event
pageview
- When you add gtag.js to your site, the snippet includes a config command that by default sends a pageview.
- config 속성을 바인딩하여 웹 사이트에 gtag를 태깅할 수 있습니다. 다양한 속성이 존재하지만, 우선 page_path만 받도록 하겠습니다.
event
- To send Google Analytics events on a web page where the Google tag has been added, use the gtag.js event command with the following syntax
- google tag를 태깅한 곳에서 gtag.js의 ‘event’ 속성을 통해 웹 페이지의 이벤트를 구글 애널리틱스에 전달할 수 있습니다.
gtag('event', <action>, { 'event_category': <category>, 'event_label': <label>, 'value': <value> });
export interface EventProps { action: string category: string label: string value: string | number } export const event = ({ action, category, label, value }: EventProps) => { try { if (window) { window.gtag('event', action, { event_category: category, event_label: label, value: value, // send_to: GA_TRACKING_ID, }); } } catch (err) { console.log(err); } };
pages/_app.tsx
const router = useRouter(); useEffect(() => { const handleRouteChange = (url: string) => { gtag.pageview(url); }; router.events.on('routeChangeComplete', handleRouteChange); return () => { router.events.off('routeChangeComplete', handleRouteChange); }; }, [router.events]);
pages/magazine
import HeadMeta from '@/components/HeadMeta'; import * as gtag from '@/lib/gtag'; const Magazine = () => { const handleClick = () => { gtag.event({ action: 'click', category: 'button', label: 'click_magazine', value: '1', }); }; return ( <> <HeadMeta description="junhee's magazine" title='junhee | magazine' image='' url='https://ga-4.vercel.app/magazine' /> <div> <h1>Hello Magazine</h1> </div> <button onClick={handleClick}>CLICK MAGAZINE</button> </> ); }; export default Magazine;
- Magazine 페이지의 버튼에 ‘handleClick’이라는 함수를 바인딩하였습니다
- ‘handleClick’은 click이라는 액션 이름을 바탕으로 label 은 ‘click_magazine’, value 값으로 ‘1’을 갖습니다
디버거 뷰에서 볼 수 있듯이 다음과 같은 값을 관측할 수 있었습니다.
- 이벤트 이름 - ‘click’
- 이벤트 라벨 - ‘click_magazine’
- 이벤트 값 - ‘1’
pages/magazine/[id].tsx
const MagazineDetail = () => { const router = useRouter(); const id = Number(router?.query?.id); useEffect(() => { if (!id) return; gtag.event({ action: 'view_item', category: 'routes', label: `magazine_detail-${id}`, value: id, }); }, [id]); return ( <> <HeadMeta description={`junhee's magazine detail ${id}`} title={`junhee | magazine - ${id}`} image='' url={`https://ga-4.vercel.app/magazine/${id}`} /> <div> <h1>Hello Magazine detail - {id || 0}</h1> </div> </> ); };
- useEffect를 통해 해당 페이지가 마운트 됐을 때 해당 event 함수를 실행시킵니다
- 다이나믹 라우팅으로 넘겨받은 id를 캐치하여 view_item이라는 이벤트를 발생시킬 수 있습니다
- 이벤트의 value 값에도 id 를 넘겨주었습니다
5. GA4에 이벤트 만들기
코드 내에 만들었던 event 함수에 action을 바인딩하는 것으로도 이벤트 만들기와 동일한 이벤트를 발생시킬 수 있습니다.
custom *opt
[관리 > 이벤트 > 이벤트 만들기]
- event_name에 우리 코드에 삽입한 action 바인딩하기
custom results
결과 보기 (전체 코드)
import HeadMeta from '@/components/HeadMeta'; import { useRouter } from 'next/router'; import * as gtag from '@/lib/gtag'; import { useEffect } from 'react'; const MagazineDetail = () => { const router = useRouter(); const id = Number(router?.query?.id); const handleClick = (id: number) => { gtag.event({ action: 'click-detail', category: 'button', label: `click_magazine_detail-${id}`, value: id, }); }; useEffect(() => { if (!id) return; gtag.event({ action: 'view_item', category: 'routes', label: `magazine_detail-${id}`, value: id, }); }, [id]); return ( <> <HeadMeta description={`junhee's magazine detail ${id}`} title={`junhee | magazine - ${id}`} image='' url={`https://ga-4.vercel.app/magazine/${id}`} /> <div> <h1>Hello Magazine detail - {id || 0}</h1> </div> <button onClick={() => handleClick(id)}>CLICK MAGAZINE</button> </> ); }; export default MagazineDetail;
6. GA4에서 결과 보기
view_item
gtag 이벤트를 통해 ‘view_item’으로 삽입한 액션이 google-analytics-4에서 감지되고 있습니다.
useEffect(() => { if (!id) return; gtag.event({ action: 'view_item', category: 'routes', label: `magazine_detail-${id}`, value: id, }); }, [id]);
마치며
구글 애널리틱스 4의 코드를 삽입하는 과정을 생각보다 어렵지 않았습니다. 얼마나 고도화할 수 있느냐, 어떤 전략을 짤 수 있느냐는 다른 팀에 달렸을 수도 있습니다. 하지만, 기본적으로 태깅은 프론트 단의 코드에서 진행해야 하는 과정이기 때문에, 알아두면 팀, 회사에 도움이 될 수 있을 것 같습니다.
제가 느끼기에 태깅 보다 더 중요한 것은 이렇게 삽입한 코드를 정량적으로 평가하고, 다음 나아갈 방향을 제시하는 것 인 것 같습니다. 계속 고도화해 가면서 더 공유할 부분이 있다면 글로 남겨보도록 하겠습니다.
감사합니다
'React.js & Next.js' 카테고리의 다른 글
prettier로 import module 순서 통일하기 (0) 2023.10.24 한번에 적용하는 Sentry with Next.js (1) 2023.10.23 리액트에서 다중의 동적 폼 처리하기 (0) 2023.06.15 다양한 파일 확장자 파일 미리보기 지원하기 (0) 2023.04.05 input image 미리보기 구현하기 (0) 2023.03.31