Search
💻

Next.js와 Google analytics + Google optimize 설정하기

생성일
3/7/2022, 1:42:18 AM
태그
Google analytics
Google optimize
Web
Front-end
SEO
next.js
작성자

Next.js를 사용해 구현한 사이트에 Google Analitycs와 Google Optimize를 붙이는 게 어려워?

현재 Ticketplace는 youha.info를 만드는데 Next.js + Typescript를 이용하고 있습니다. SSR 등의 최신 Front-end기술을 효과적으로 쓸 수 있고 Type을 명시하는 코드는 작성 시에 문제점들을 해결해주는 장점들이 있기 때문입니다.
그런데 이렇게 사이트를 만들고 그냥 두면 될까요? 이제 만들어진 사이트에 어떤 고객이 방문하는지, 이들이 어떤 행동을 하는지, 그리고 어떤 기능의 반응이 더 좋은지 등을 확인할 수 있어야 합니다. 이것을 도와주는 게 Google analyticsGoogle optimize입니다. 두 제품에 대한 설명은 해당 제품 사이트를 참조하십시오. 앞으로 Google analytics는 GA, Google optimize는 GO라고 부르겠습니다. (참고로 본 글에서 사용하는 Next.js의 버전은 12.0.10이고 GA는 UA입니다.)
워낙 유명한 서비스들인데 설치하는 것이 뭐 어렵겠습니까. 그런데 Next.js를 사용해 구현한 사이트에 설치하는 데에는 아래와 같은 문제들이 있습니다.
1.
GA, GO 스크립트를 동기로 불러오는 것이 불가능하다.
2.
하이퍼링크를 통해 페이지 이동 시에 GA의 page_view 이벤트가 트리거되지 않는다.
3.
하이퍼링크를 통해 페이지 이동 시에 GO의 대안이 적용이 되지 않는다.
4.
nextjs의 hydration과 GO의 대안 적용이 충돌한다.
5.
CSS module을 사용할 경우, react element의 이름 등이 변경되었을 때 GO의 대안이 적용되지 않는다.

GA, GO 스크립트를 동기로 불러오는 것이 불가능하다.

Next.js에서 동기로 스크립트를 불러오려고 하면 No Sync Scripts가 발생합니다. 스크립트를 동기로 불러오면 첫 화면 렌더링이 그 만큼 늦어지기 때문에 Next.js에서는 이를 막아두었습니다. 따라서 GA와 GO 스크립트를 동기로 불러올 수 없습니다.
이것은 어떻게 해결해야 할까요? GA와 GO 스크립트를 비동기로 불러오도록 하면 해결됩니다. Next.js의 Script 컴포넌트를 사용하여 스크립트를 불러오면 해결됩니다.

하이퍼링크를 통해 페이지 이동 시에 GA의 page_view 이벤트가 트리거되지 않는다.

Next.js의 Link 컴포넌트를 사용하여 구현된 하이퍼링크를 클릭하면 이동한 페이지의 html을 불러와 페이지 전체를 새로 렌더링하는 것이 아니라, js 파일을 받아와 기존 페이지의 element를 이동한 페이지의 것들로 교체합니다. 따라서 페이지가 이동되더라도 GA의 page_view 이벤트가 트리거 되지 않습니다.
이는 페이지 주소가 변경될 때마다 직접 GA의 page_view 이벤트를 트리거해주면 해결됩니다. Next.jsuseRouter 훅을 사용하여 routeChangeComplete 이벤트에 GA의 page_view 이벤트를 트리거 하는 콜백을 설정해주면 됩니다.
const router = useRouter() useEffect(() => { const handleRouteChange = (url: string) => { // @ts-ignore window.gtag("config", GOOGLE_ANALYTICS, {page_path: url}) } router.events.on("routeChangeComplete", handleRouteChange) return () => { router.events.off("routeChangeComplete", handleRouteChange) } }, [router.events])
JavaScript

하이퍼링크를 통해 페이지 이동 시에 GO의 대안이 적용이 되지 않는다.

바로 위의 문제와 같은 이유로 GO의 대안도 적용되지 않습니다.
이는 GO 콘솔에서 환경을 만들 때, 활성화 이벤트를 계속으로 설정해주면 해결됩니다. (아래 이미지 참고)
페이지 로드: 사이트가 url 마다 html을 받아와 렌더링하는 방식으로 구현되어있을 때 사용
계속: 사이트가 클라이언트 라우팅(페이지 이동 시 새로운 html을 받아오지 않고, js를 받아와 기존 페이지의 element를 교체하는 방식)으로 구현되어있을 때 사용

Next.js의 hydration과 GO의 대안 적용이 충돌한다.

GO에서는 사용자나 접속환경, 혹은 매개변수에 따라 서로 다른 화면을 보여주고 이에 행동하는 사용자의 행동을 추적할 수 있습니다. 그런데 만약 GO의 스크립트가 hydration 스크립트보다 먼저 동작하게 될 경우, Next.js에서 React Hydration Error가 발생하며, GO의 대안이 적용되지 않습니다. 이것 때문에 ‘왜 안 되지?’ 하면서 시간을 많이 버렸습니다.
이는 GO의 스크립트가 Next.js의 hydration이 완료된 직후에 동작하도록 타이밍을 맞춰주면 해결됩니다. Next.js의 Script component를 사용하면 기본적으로 hydration이 된 직후에 스크립트를 불러와 실행시킵니다.
하지만 이렇게 hydration이 끝난 뒤에 스크립트를 불러오게 하면 아래의 문제가 발생합니다.

flicker 현상이 발생한다.

사용자가 사이트에 접속하면 처음에는 원본 페이지가 렌더링되고, 잠시 후 GO 스크립트가 실행된 후에 대안이 적용됩니다. 따라서 사용자에게는 잠깐 원본이 뜬 다음 대안이 보이게 됩니다.
이는 anti-flicker snippet을 설정해주면 해결됩니다. 하지만 이렇게 anti-flicker snippet을 설정할 경우 GO 스크립트가 실행되기 전까지는 화면이 공백으로 뜨는 단점이 있습니다. 만약 flicker 현상을 막는 것보다 화면 렌더링을 빠르게 하는 것이 더 중요하다면 anti-flicker snippet을 설정하지 않아도 됩니다. (참고로 저희 youha.info에는 설정하였습니다.)

CSS module을 사용할 경우, react element의 이름 등이 변경되었을 때 GO의 대안이 적용되지 않는다.

CSS module을 사용하면, 태그에 <파일명>_<클래스명>__<해쉬> 형태로 클래스가 지정됩니다(참고). 이 상태에서 GO 콘솔에서 대안을 만들게 되면 selector에 자동으로 클래스가 들어가게 됩니다. 하지만 React element 이름 등을 변경하면 태그에 지정된 클래스가 바뀌어 GO의 selector가 해당 태그를 찾지 못하게 됩니다. 따라서 GO의 대안이 적용되지 않습니다.
이는 GO 콘솔에서 대안을 만들 때 selector에 클래스가 들어갔을 경우, 직접 seletor를 수정하여 클래스 대신 태그 혹은 id 등으로 변경하면 해결됩니다.
before
after

예제 코드

Ticketplace 조직의 레포지토리에 다음은 위 해결책들을 모두 적용한 예제 코드를 올려두었습니다. Github로 공유해놨으니 마음껏 가져다 쓰셔도 됩니다.
nextjs-with-ga-go
youha-info

저자 소개

전현준은 Ticketplace에서 youha.info의 첫 버전을 만들었습니다. 관심분야는 소프트웨어 개발이며, 최근에는 데이터 기반의 의사결정을 내릴 수 있는 서비스 구조와 개발 조직을 만드는데 깊은 관심을 가지고 있습니다.