Frontend

Next.js proxy를 활용해 Analytics 이벤트를 수집해보자

mechaniccoder 2023. 2. 21. 23:59

이전 포스팅인디자인 패턴(Singleton, Facade)을 사용한 Analytics 코드설계에서 Analytics 코드에 관한 내용을 공유했었습니다. 2주 동안 이벤트를 수집하는 과정에서 한 가지 이슈가 발생했습니다. analytics를 통해 수집한 데이터와 실제 데이터를 비교했더니 25% 정도의 데이터 손실이 있었습니다. 아무래도 client side에서 이벤트를 수집하다보니 ads blocker에 의해 손실이 발생한 것 이었죠. 이를 해결하기 위해 Next.js api route로 proxy 서버를 구축했던 경험과 그 과정에서 겪었던 어려움을 공유해보겠습니다.

이 포스팅을 읽고 난 뒤에는 아래의 내용들을 이해하게 됩니다.

  • Next.js로 proxy 서버 구축하기
  • Client-Side Tracking vs Server-Side Tracking vs Tracking via Proxy

Why Proxy?

이벤트를 수집하는 방법에는 여러가지가 있습니다. client side tracking은 기존에 하던 방법처럼 frontend에서 이벤트를 수집하는 방법입니다. frontend의 상태를 가지고 이벤트를 쉽게 수집할 수 있는 장점이 있는 반면 앞서 언급했듯이 ads blocker의 영향으로 데이터 손실이 될 수 있다는 단점이 있습니다.

server-side tracking은 서버에서 이벤트를 수집하는 방법입니다. https는 stateless하므로 이벤트와 같이 보내야할 상태를 준비하기 힘들다는 단점이 있지만 매우 정확한 데이터를 얻을 수 있는 장점이 있습니다.

그 외에도 proxy 서버를 활용해 이벤트를 수집하는 방법이 있습니다. client-side tracking에서 analytics 서버로 이벤트를 전송하는 대신에 proxy 서버로 전송하기 때문에 ads blocker를 회피할 수 있는 장점이 있습니다. 다만 proxy 서버를 구축해야 한다는 번거로움이 단점일 것 같네요.

위 3가지 이벤트 수집 방법의 장단점과 아래의 판단을 근거로 하여 proxy를 활용해 이벤트 수집을 하기로 결정했습니다.

  • frontend에 붙여놓은 analytics관련 코드를 모두 서버로 옮기기에는 많은 리소스가 든다고 판단 (동일한 metadata를 보내기 위해 서버 코드가 많이 변경되야함)
  • 이미 Next.js로 되어있는 프로젝트이므로 proxy 서버를 구축하기가 매우 쉬움.

How to configure proxy server using Next.js

Next.js을 활용해 proxy 서버를 구축하는 방법은 크게 2가지로 나눌 수 있을 것 같습니다.

  • Next.js rewrite 설정을 활용
  • Api routes와 http-proxy 라이브러리 활용

Next.js rewrite 설정

Next.js에는 rewrite 설정을 할 수 있는 옵션을 제공하고 있습니다. 즉 아래와 같이 source와 destination을 구성하여 next.js server를 proxy 서버로 활용할 수 있습니다.

next.config.js

module.exports = {
  async rewrites() {
    return [
      {
        source: '/analytics/:slug',
        destination: 'https://analytics.com/:slug',
      },
    ]
  },
}

Api routes와 http-proxy 라이브러리 활용

다만 request를 변형하거나 활용해야하는 경우에는 라이브러리를 활용해 직접 proxy 서버를 구축해야 합니다. 아래는 next.js의 api routes와 http-proxy 라이브러리를 활용한 코드입니다.


externalResolver는 http-proxy를 사용하고 있기 때문에 명시적으로 옵션을 줬고, bodyParser의 경우 formData를 전송하는 경우도 있어서 사용하지 않도록 했습니다.

저는 여기서 changeOrigin 옵션을 설정하지 않아서 삽질을 했는데요. 여러분들은 그러지 마세요. origin이 달라지면 저 옵션을 꼭 켜야합니다.

export const config = {
  api: {
    externalResolver: true,
    bodyParser: false,
  },
};

const proxy: httpProxy = httpProxy.createProxy();

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  proxy.web(req, res, {
    changeOrigin: true,
    target: targetUrl,
  });
}

마치며

client-side tracking의 한계를 직접 경험하며 이를 해결하기 위해 Next.js로 proxy 서버를 구축하는 것에 대해서 공유해보았습니다. 현 시점에서는 다시 proxy에서 client-side tracking으로 롤백을 했는데요. Vercel의 서버 비용이 부담이 되더라고요. 아무래도 서버에서 analytics로 직접 이벤트를 직접 콜하다보니 어쩔 수가 없는 것 같습니다.


그래도 이번 기회를 통해 각 이벤트 수집 방법에 대한 장단점도 알게 됐고 나중에 다시 구축할때는 삽질없이 빠르게 개발할 수 있을 것 같네요.