싱글 페이지 응용프로그램에 구글 애널리틱스 적용

구글 애널리틱스 Google Analytics는 웹 응용프로그램의 사용 데이터를 수집에 많이 사용됩니다.

웹사이트 이용에 대한 추적 데이터를 기반으로 무엇을 어떻게 … 가 시작될 수 있습니다.

구글 애널리틱스에서 기본적으로 제공하는 코드는 웹 응용프로그램 특정 페이지에 요청을 보내면 응답하는 페이지에 코드를 추가해서 처리가 가능합니다.

그런데, 싱글 페이지 응용프로그램이라면 어떻게 클라이언트 경로 이동을 추적할 수 있을지에 대한 내용을 간략하게 작성했습니다.

구글 애널리틱스 속성 추가

구글 애널리틱스에 추적할 웹 응용프로그램에 대한 속성을 추가합니다.

추적 속성을 추가하면 범용 사이트에서 사용가능한 추적코드를 얻을 수 있습니다.

추적코드

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXX-X"></script>

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-XXXXXXXX-X');
</script>

범용 사이트 태그(gtag.js)에 대한 설명에 의하면, 위 코드를 추적할 모든 웹페이지의 <head>에 첫번째 항목으로 붙여넣으면 됩니다.

그런데, SPA 의 경우 실제 페이지는 하나만 존재합니다.

클라이언트 코드에서 경로를 변경한 경우에도 추적코드를 실행해야 구글 애널리틱스에서 유효한 통계자료를 얻을 수 있습니다.

측정: gtag.js

측정 관련 API 는 Google Analytics Measurement gtag.js 페이지에서 찾을 수 있습니다.

클라이언트 측 경로 탐색시 경로 이동 추적을 위한 기능 확인은 Pageviews 관련 API 에서 찾을 수 있습니다.

config 명령으로 경로 탐색에 대한 추적이 가능합니다.

gtag('config', 'GA_MEASUREMENT_ID', { /* pageview parameters */});

Pageview parameters 의 정의는 아래와 같습니다.

interface PageviewParameters {
    page_title?: string;
    page_location?: string;
    page_path?: string;
}

예제

공통

예를 들어 https://blog-service.bbon.me/users/@bbonkr/posts/hello-world 페이지로 이동하면 페이지가 로드된 후 아래 코드가 실행되면 되겠습니다.

gtag('config', 'UA-XXXXXXXX-X', {
        page_title: 'Hello world',
        page_location: 'https://blog-service.bbon.me/users/@bbonkr/posts/hello-world'
        page_path: '/users/@bbonkr/posts/hello-world'
});

페이지 제목은 window.document.title 속성으로 찾을 수 있습니다.

페이지 전체 경로는 window.location.href 속성으로 찾을 수 있습니다.

페이지 경로는 window.location.pathname 속성으로 찾을 수 있습니다.

next.js + React 로 작성된 웹 응용프로그램

편리한 SSR Server-side Rendering , 편리한 클라이언트 경로 처리 등의 이유로 next.js 와 React 로 작성된 웹 응용프로그램의 경우 아래와 같이 처리할 수 있습니다.

_document 를 재작성해서 _gtag.js 파일을 포함하도록 코드를 작성합니다.

ga.ts 파일의 내용

export const gaTraceId: string = 'UA-XXXXXXXX-X';

_document.tsx 파일의 내용

import { gaTraceId } from './ga'

class MyDocument extends Document<IMyDocumentProps> {
    // 생략
    addGoogleAnalyticsScript(){
        return {
            __html: `
              window.dataLayer = window.dataLayer || [];
              function gtag(){dataLayer.push(arguments);}
              gtag('js', new Date());

              gtag('config', '${gaTraceId}');

            `,
        };
    }
    // 생략
    render() {
        const gaTraceId = 'UA-XXXXXXXX-X'
        return (
            <html lang='ko'>

                <Head>
                {/* ... */}
                </Head>
                <body>
                    <Main />
                    <NextScript />
                    <script async src={`https://www.googletagmanager.com/gtag/js?id=${gaTraceId}`}></script>
                                <script
                                    dangerouslySetInnerHTML={this.addGoogleAnalyticsScript()}
                                />
                </body>
            </html>
        );
    }
}

모든 페이지에 포함되는 컴포넌트를 작성합니다.

import React, {
    FunctionComponent,
    useEffect,
} from 'react';
import Router from 'next/router';
import { gaTraceId } from './ga'

export interface AppLayourProps {
    children: React.ReactNode;
};

export const AppLayout: FunctionComponent<AppLayoutProps> = ({children}) => {
    useEffect(() => {
        const handleRouteChangeComplete = (url) => {
            if(typeof window === 'object'){
                const { title } = window.document;
                const { href, pathname } = window.location;

                window.gtag('config', gaTraceId, {
                    page_title: title,
                    page_location: href,
                    page_path: pathname,
                });
            }            
        };

        Router.events.on('routeChangeComplete', handleRouteChangeComplete);

        return () => {
            Router.events.off('routeChangeComplete', handleRouteChangeComplete);
        };
    }, [])

    return (
        <div>
            {children}
        </div>
    );    
};

gtag 함수를 위한 정의파일 작성

@types/global.d.ts 파일의 내용

export declare global {
    interface PageViewParameter {
        page_title: string;
        page_location: string;
        page_path: string;
    }

    interface Window {
        gtag: (action: string, gaId: string, parameter: PageViewParameter) => void;
    }
}

위와 같이 컴포넌트로 분리하면 모든 페이지 컴포넌트에서 Pageviews 측정을 위한 코드를 추가하지 않고 처리할 수 있습니다.

next.js 의 경로 처리 이벤트는 https://github.com/zeit/next.js/#router-events 페이지에서 확인할 수 있습니다.

useEffect 또는 componentDidMount 함수에서 window 객체의 속성값을 참조할 때, 문제가 있는 경우 setTimeout 함수로 조금 후에 실행되도록 조정할 수 있습니다.

이 사이트는 광고를 포함하고 있습니다.
광고로 발생한 수익금은 서버 유지 관리에 사용되고 있습니다.

This site contains advertisements.
Revenue generated by the ad servers are being used for maintenance.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다