ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL - Next.js Google Analytics 코드 적용하기
    개발 2022. 4. 26. 00:20

    일반적인 GA 적용방법

    일반적으로 구글 애널리틱스 추적을 적용하기 위해서 index.html 에 구글 애널리틱스로 발급받은 트랙킹 아이디를 포함한 스크립트 구문을 작성한다.

     

    // index.html
    <script async src="https://www.googletagmanager.com/gtag/js?id=REACT_APP_GA_ID" />

    방문자가 접속한 페이지에 따른 통계를 위해서는 마찬가지로 구글 애널리틱스에서 제공하는 코드를 작성하면 가능한데

    아래와 같다.

     

    // index.html
    <script async src="https://www.googletagmanager.com/gtag/js?id=REACT_APP_GA_ID" />
    
    <script>
        window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'REACT_APP_GA_ID', {
              page_path: window.location.pathname,
        });
    </script>

     


    React 프로젝트에서는

     

    마찬가지로 순수 리액트 프로젝트에서 public 폴더에 존재하는 index.html 파일에 위와 같은 방법으로 적용하는 방법도 가능하며 index.js에서 스크립트를 실행하는 방법으로도 가능하다.

     

    // index.js
    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
    
    const ga_id = REACT_APP_GA_ID
    
    const initGA = () => {
      window.dataLayer = window.dataLayer || []
      gtag('js', new Date())
      gtag('config', ga_id)
    }
    
    initGA();
    
    ReactDOM.render(<App />, document.getElementById('root'))

    하지만 SPA인 리액트에서 첫 페이지 진입 시 모든 페이지 정보를 다운받아 라우팅 하는 방식으로 페이지를 이동하기 때문에 페이지 이동 시에 강제로 페이지를 추적 할 수 있는 코드를 작성해줘야 한다.

     

    // app.js
    
    function App(props) {
      useEffect(() => {
        window.gtag(props.location.pathname);
    
        // change description and rich result for SEO.
      }, [props.location.pathname]);
    
    
      return ( /* ... */ );
    }

     

    패키지 사용없이 위와 같은 방법으로 구글 애널리틱스를 적용하기도 하지만

    많은 개발자들이 react-ga 패키지를 사용해 좀더 쉽고 디테일한 구글 애널리틱스 적용을 사용한다.

     

    나중에 순수 리액트 프로젝트에 적용할 일이 있다면 한번 읽어보는 것도 좋겠다.

     

    https://dev.to/basileleroy/google-analytics-on-react-js-components-4d2a

     

    Google Analytics on React.js Components

    Intro Struggling to use Google Analytics on a React-app? Do you only get data on the land...

    dev.to

     


    index.html 이 없는 Next.js 프로젝트에서는

    우리가 아는 Next.js는 서버사이드 렌더링을 지원하여 html 파일 없다.

    때문에 구글 애널리틱스 추적을 코드를 적용하기 위해서는 _app.js 와 _document.js 파일을 이용해 코드를 적용해야 한다.

     

    _document.js

    meta 정보나 body 의 내용을 커스텀하기 위해 사용하는 _document 파일에서 먼저 초기화 코드를 작성한다.

     

    // _document.js
    
    import Document, { Html, Head, Main, NextScript } from 'next/document';
    import { GA_TRACKING_ID } from '../utils/gtag';
    
    class MyDocument extends Document {
      static async getInitialProps(ctx) {
    @@ -9,7 +10,22 @@ class MyDocument extends Document {
      render() {
        return (
          <Html>
            <Head>
              <script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`} />
              <script
                dangerouslySetInnerHTML={{
                  __html: `
                window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', '${GA_TRACKING_ID}', {
                  page_path: window.location.pathname,
                });
              `,
                }}
              />
            </Head>
            <body>
              <div id={'portalWrap'} />
              <Main />
              // ..생략..

    googletagmanager 스크립트에 GA_TRACKING_ID 를 포함한 정보를 먼저 작성하고

    발급받은 gtag 예시 코드도 마찬가지로 GA_TRACKING_ID 를 포함하여 작성한다.

     

    GA_TRACKING_ID는 별도의 gtag.js 에서 작성하여 import해서 가져왔다.

    gtag.js에 작성된 함수들은 각각 페이지의 접속 정보와 별도의 버튼 인터랙션 이벤트 추적이 필요할때 사용될 코드이다.

     

    더보기

    utils/gtag.js

    export const GA_TRACKING_ID = 'G-4MLBSZWEEH';
    
    // https://developers.google.com/analytics/devguides/collection/gtagjs/pages
    export const pageview = (url) => {
      window.gtag('config', GA_TRACKING_ID, {
        page_path: url,
      });
    };
    
    // https://developers.google.com/analytics/devguides/collection/gtagjs/events
    export const event = ({ action, category, label, value }) => {
      window.gtag('event', action, {
        event_category: category,
        event_label: label,
        value: value,
      });
    };

     

    여기까지 초기화하는 단계는 일반적으로 html 파일에 구글 애널리틱스를 적용하는 방법과 동일하다고 볼 수 있다.

    Next.js는 순수 리액트에서 사용하는 SPA 방식에서 SSR을 더하여 SEO와 같은 CSR 이전의 작업을 할 수 있도록 하는데,

     

    때문에 리액트와 같이 별도의 페이지 추적 동작을 심어주어야 실제로 구글 애널리틱스에서 페이지 정보를 받아 통계 정보를 확인 할 수 있다.

     

    이러한 동작을 수동으로 넣어주기 위해서는 사용자가 매번 페이지를 이동 할 때마다 구글 애널리틱스가 페이지정보를 수집 할 수 있도록해주어야 하는데, 이런 시점에 있는 파일이 바로 _app.js 이다.

     

    _app.js - pageview 추적

    _app.js 는 _document.js의 실행 다음으로 실행되는 파일로 프로젝트 전체(공통)에 적용될 작업들을 작성한다.

    일반적으로 전역 스타일이나 공통 레이아웃을 작성할때 이용하는 파일이다.

     

    Next.js 에서 URL에 접근하여 쿼리파라미터를 받아오는 등의 작업을 위해 사용되는 Hook이 useRouter 이다.

    이 Hook을 사용해 페이지의 이동이 일어났을때 강제적으로 pageview가 바뀌었음을 알려줘야한다.

     

    import 'styles/_global.scss';
    import 'swiper/css/bundle';
    import 'styles/lib_custom/swiper.scss';
    import { useRouter } from 'next/router';
    import { useEffect } from 'react';
    import * as gtag from '../utils/gtag';
    
    const MyApp = ({ Component, pageProps }) => {
      const getLayout = Component.getLayout || ((page) => page);
      const router = useRouter();
      useEffect(() => {
        const handleRouteChange = (url) => {
          gtag.pageview(url);
        };
        router.events.on('routeChangeComplete', handleRouteChange);
        return () => {
          router.events.off('routeChangeComplete', handleRouteChange);
        };
      }, [router.events]);
    
      return getLayout(
        <>
          <Head>

     

    코드를 보면 utils/gtag 파일에서 정의한 pageview 함수를 실행하기 위해 useEffect를 사용하였다.

    또 router.events 에 routeChangeComplete 이벤트를 등록해 페이지 이동이 일어났을때 

    pageview 함수가 실행되는 핸들러를 작성하여 url을 넘겨주고 있다.

    이 이벤트가 매번 실행될수 있도록 dependency array를 router.events로 작성한 코드이다.

     

    routeChangeComplete는 첫번째 매개변수로 url 정보를 제공하기 때문에 작성된 핸들러를 통해 url 정보를 참조 할 수 있다.

     

    https://nextjs.org/docs/api-reference/next/router

     

    next/router | Next.js

    Learn more about the API of the Next.js Router, and access the router instance in your page with the useRouter hook.

    nextjs.org

     

     

    각각의 요소 - event 추적

    만약 페이지 접속 이외에 사용자가 회원가입 버튼이나 이벤트 참여 버튼을 클릭했을때의 정보를 구글 애널리틱스로 추적하고자 할 경우에는 해당 요소에 event를 실행하는 코드를 작성해 추적 할 수도 있다.

     

    pageview 함수 아래에 작성해둔 event 함수가 그 역할을 하는 코드이다.

    원래 구글 애널리틱스에서 제공하는 이벤트은 여러가지가 있다.

     

    // 검색 키워드 수집
    gtag('event', 'search', { 
          search_term: '...' // 검색 키워드 
      })
      
    // 컨텐츠 수집
    gtag('event', 'select_content', { 
          item_id: '...', // 컨텐츠 아이디
          content_type: '...' // 컨텐츠 종류
      })

     

    https://developers.google.com/analytics/devguides/collection/gtagjs/events

     

    Measure Google Analytics Events  |  Universal Analytics for Web (gtag.js)  |  Google Developers

    Measure Google Analytics Events This page explains how to use gtag.js to send Google Analytics Events. Note: This article focuses on a subset of gtag.js events called Google Analytics Events, events that appear in the Google Analytics Event reports. Learn

    developers.google.com

     

     

    페이지 추적코드가 적용된 모습

     

     


    실제 운영환경의 GA만 활성화를 해야한다면..?

    진행하고 있는 프로젝트는 환경변수를 사용하여 "ENV" 라는 변수에 현재 프로젝트의 개발환경의 mode를 정보를 참조 할 수 있도록 되어있다.

     

    나의 경우는 _document.js에서 최초에 초기화 코드가 실제 production 환경일 때에만 실행되도록 하는 방식을 사용했다.

     

    // 초기화 코드
    
    <script
        dangerouslySetInnerHTML={{
          __html: `
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', '${GA_TRACKING_ID}', {
          page_path: window.location.pathname,
        });
      `,
        }}
      />

    해당 코드는 dangerouslySetInnerHTML를 사용해서 innerHTML이 사이트간 악성 스크립팅으로부터 공격을 방지하려하고있다. 

     

    간단히 생각하면 단순히 html를 삽입하는 문구로 조건문을 사용할 수 있다고 생각되어 환경 변수 mode가 production일 경우로 예외 처리 하였다.

     

    // _document.js
    
    const isProduction = process.env.ENV === 'production';
    
    <script
        dangerouslySetInnerHTML={{
          __html: `
          if (${isProduction}) {
                window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', '${GA_TRACKING_ID}', {
                  page_path: window.location.pathname,
                });
            }
      `,
        }}
      />

    _document.js의 실행 시점은 서버사이드에서 실행되기 때문에 process.env로 접근이 가능하다.

     

     

    실제 프로젝트에 예외처리가 적용된 모습이다.

     

     

     

     

     

     

     

     

     

     

    '개발' 카테고리의 다른 글

    TIL - React Table Library #2  (2) 2022.05.03
    TIL - React Table Library #1  (2) 2022.05.02
    TIL - Mac 업로드 파일 한글 깨짐 (자모분리현상)  (0) 2022.04.19
    JS - Map  (0) 2022.04.13
    React - react hook form  (0) 2022.03.31

    댓글

onul-hoi front-end developer limchansoo