6단계와 수익화 리포트에서 공개한 트래픽 숫자는 애드센스 화면을 캡처한 게 아니라, 늑구맵이 직접 만들어 붙인 트래킹으로 잰 숫자입니다. 이 페이지는 그 트래킹을 어떻게 만들었는지, 실제 코드 구조 그대로 공개합니다.
왜 애드센스/GA 리포트만으로는 부족했나
애드센스 리포트는 광고 노출·수익 지표에 강하지만, '이 방문자가 디시인사이드에서 왔는지 네이버 검색에서 왔는지'처럼 유입 채널을 세밀하게 나눠 보여주진 않습니다. Google Analytics를 붙이는 방법도 있지만, 이미 Vercel에 배포하고 있다면 Redis(KV) 하나만 추가로 붙여서 필요한 지표만 직접 설계하는 쪽이 더 가볍습니다. 늑구맵은 늑구 사건 보도 직후 커뮤니티발 트래픽이 얼마나 되는지가 가장 궁금했는데, 이건 범용 분석 도구보다 직접 만든 채널 분류가 더 정확했습니다.
늑구맵이 실제로 쓰는 구조
브라우저에서 이벤트가 발생해 대시보드에 뜨기까지, 4단계를 거칩니다.
브라우저: 페이지뷰/클릭 이벤트 발생
페이지 진입 시 visitorId(localStorage에 저장된 UUID)를 만들거나 불러오고, navigator.sendBeacon으로 /api/track에 전송합니다. sendBeacon이 없는 환경에서만 fetch(keepalive)로 대체합니다.
사용자가 페이지를 떠나는 순간(뒤로가기, 탭 닫기)에도 fetch는 요청이 끊길 수 있지만, sendBeacon은 브라우저가 백그라운드로 전송을 보장합니다. 이탈 직전 이벤트를 놓치지 않으려고 이 순서를 지킵니다.
/api/track (Edge Function)
type(pageview/click), path, visitorId, referrer, UTM 파라미터를 받아 최소 검증만 하고 lib/tracking.ts의 recordEvent()에 넘깁니다.
KV(Redis)가 아직 설정 안 됐거나 순간적으로 응답이 늦어도, 트래킹 실패가 실제 방문자의 페이지 이용에 영향을 주면 안 됩니다. 그래서 실패해도 200을 반환하도록 만들었습니다.
Upstash Redis (Vercel KV)
referrer를 naver_search/google_search/dcinside/kakao 등으로 분류(classifyChannel)해 날짜별 카운터에 쌓습니다. 페이지뷰는 INCR, 순방문자는 SADD(집합), 채널/캠페인/경로별 집계는 HINCRBY로 각각 처리합니다.
무료 KV 용량은 한정적입니다. 그래서 모든 키에 120일 만료(EXPIRE)를 걸어 오래된 데이터가 자동으로 정리되게 했습니다. 사이트가 여러 개라 SITE_ID로 네임스페이스를 나눠, 나중에 통합 대시보드를 만들 때도 키 충돌 없이 조회할 수 있게 했습니다.
/api/stats + /dashboard
비밀키(STATS_SECRET)를 쿼리 파라미터로 확인한 요청에만 날짜 범위별 집계(총 페이지뷰, 순방문자, 채널별/경로별 분포)를 JSON으로 돌려주고, /dashboard 페이지가 이걸 그려서 보여줍니다.
이 대시보드는 검색엔진에 노출되면 안 되는 운영자 전용 화면입니다. robots: {'{'}index: false{'}'}로 색인을 막고, 비밀키 없이는 데이터 자체가 응답되지 않게 이중으로 막았습니다.
이 구조의 한계도 같이 밝힙니다
정확한 검색어는 잡지 못합니다
브라우저 정책상 실제 검색어는 리퍼러에 실리지 않습니다. 그래서 이 트래킹은 '네이버 검색에서 왔다'까지는 분류하지만 '무슨 검색어로 왔는지'는 알 수 없습니다. 검색어 단위 데이터가 필요하면 네이버 서치어드바이저·Google Search Console을 별도로 등록해야 합니다. 자체 트래킹이 모든 걸 대체하는 게 아니라, 다른 도구와 역할을 나눠 쓰는 도구라는 걸 분명히 해두고 싶었습니다.
내 프로젝트에도 적용할지 판단하는 체크리스트
늑구맵의 생각
이 트래킹을 만들며 얻은 가장 큰 소득은 정확한 숫자 자체보다, '내가 지금 뭘 모르고 있는지'를 구체적으로 알게 된 것이었습니다. 검색어를 못 잡는다는 한계도 만들어보고 나서야 명확해졌습니다. 범용 분석 도구를 그대로 붙이는 것보다 느리지만, 1단계에서 강조한 원칙과 똑같습니다 - 필요한 것만 최소로 만들어야, 뭐가 부족한지도 빨리 보입니다.