DAY 08작업 8일째

어드민에서 블로그 방문 통계를 정확하게 보이게 했다

Cloudflare Web Analytics 기록을 어드민으로 가져오면서 봇과 내 방문을 빼고, 어림값과 없는 주소 문제를 풀고, 동선과 처음 보는 유입처까지 보이게 했다.

블로그 방문 기록은 Cloudflare Web Analytics가 모으고 있었다. 쿠키 없이 브라우저에서 짧은 스크립트로 세는 방식이라 동의 배너도 필요 없다. 문제는 보는 곳이었다. 숫자를 보려면 매번 Cloudflare 대시보드에 들어가야 했고, 글을 검토하고 발행하는 어드민과는 따로 놀았다. 그래서 어드민에 「방문」 화면을 만들고 같은 기록을 GraphQL API로 읽어 오기로 했다.

읽기만 하는 연결

어드민에 주는 권한은 통계 읽기 하나뿐이다. 이 권한으로는 사이트 설정이나 다른 키를 건드릴 수 없다. 처음에는 Web Analytics 사이트 목록 API로 블로그 사이트를 찾으려 했는데, 그 목록은 다른 권한을 요구했다. 권한을 넓히는 대신 통계 자체에서 찾았다. 최근 기록을 사이트 태그와 접속 호스트로 묶어 받아, 블로그 주소가 잡힌 사이트 태그를 고른다.

이 과정에서 하나를 발견했다. 도메인 하나에 Web Analytics 사이트가 하나로 잡혀 있어서, 같은 도메인 아래 다른 서비스의 하위 도메인 방문까지 한 사이트에 섞여 있었다. 사이트 태그로만 거르면 블로그 통계에 다른 서비스의 방문이 들어간다. 그래서 모든 조회를 블로그 호스트로도 거른다.

사람만, 정확한 수로 센다

기록을 봇 판정과 브라우저별로 나눠 보니 사람이 아닌 방문이 섞여 있었다.

섞인 것거르는 방법
Cloudflare가 봇으로 판정한 방문bot: 0 만 센다
화면 없는 브라우저(캡처 · 자동화 도구)userAgentBrowser 가 headless 인 것을 뺀다
블로그 캡처 도구 자신찍는 동안 통계 스크립트 요청을 막는다
글을 검토하며 연 내 방문「내 방문 빼기」 표시가 있는 브라우저는 스크립트를 부르지 않는다

내 방문 빼기는 블로그 쪽에서 처리한다. 어드민의 버튼이 블로그를 ?notrack=1로 열면 그 브라우저에 표시가 남고, 이후로는 블로그의 main.js가 통계 스크립트를 부르지 않는다. 그러려면 스크립트를 Cloudflare가 자동으로 끼워 넣는 대신 블로그가 직접 불러야 한다. 자동 삽입이 켜져 있는 동안 블로그 코드가 스크립트를 또 부르면 방문을 두 번 센다. 그래서 이미 끼워진 스크립트가 있으면 블로그 코드는 손을 뗀다.

구간마다 별칭을 붙여 한 요청에 담는다. 각 구간은 날짜, 시간, 주소, 들어온 곳, 나라, 기기를 한 줄씩 받아 오고, 합계와 순위, 요일·시간대 지도는 어드민이 그 줄들을 합쳐 계산한다.

for (let span = EXACT_DAYS - 1; end >= start; span = 6) {
  const s = Math.max(start, end - span * DAY);
  out.unshift([day(new Date(s)), day(new Date(end))]);
  end = s - DAY;
}

동선, 없는 주소, 처음 보는 유입처

「방문」 화면은 방문과 페이지 조회를 지난 기간과 견주고, 들어온 곳을 검색·SNS·개발 커뮤니티·직접 방문으로 묶어 비율로 보여 준다. 발행한 날부터 7일 동안의 조회로 글끼리 견주는 표와, 태그별·프로젝트별로 조회를 합친 순위도 있다.

동선은 이전 페이지 주소로 만든다. Cloudflare는 바깥에서 온 링크뿐 아니라 블로그 안에서 옮겨 다닐 때도 이전 페이지 주소를 남긴다. 그래서 이전 페이지가 블로그 안이면 「이 페이지 전에 본 페이지」, 바깥이거나 비어 있으면 그 페이지가 처음 들어온 페이지가 된다. 「다음에 본 페이지」는 반대 방향이라, 이전 페이지 주소가 지금 페이지인 기록을 따로 한 번 더 묻는다. 조회가 많은 글과 사람을 처음 데려오는 글이 다를 수 있어서 처음 들어온 페이지는 따로 순위를 낸다.

블로그에 없는 주소로 들어와 404 페이지를 본 방문도 따로 모은다. 블로그 sitemap에 없는 주소가 대상이다. 내린 글이나 바뀐 주소로 들어오는 링크가 남아 있으면 이어 줄지 정하려는 것이다.

화면은 들어가야 보이니, 두 가지는 먼저 알려 준다. 처음 보는 사이트에서 링크를 타고 들어오면 휴대폰으로 알린다. 누군가 글을 어딘가에 공유했다는 신호다. 30분마다 최근 이틀의 유입처를 보고, 본 적 있는 곳은 서버에 기억해 같은 알림을 다시 보내지 않는다. 처음 켤 때는 지난 30일의 유입처를 알림 없이 기억만 한다. 월요일 아침 9시에는 지난 7일 방문과 가장 많이 읽힌 글, 새 유입처 수를 한 번 보낸다. 둘 다 원래 있던 저장소 지켜보기가 돌 때 같이 돌아서, 스케줄러를 따로 두지 않았다.

감수한 것

8일보다 오래된 날은 정확한 수를 받을 방법이 없어서, 30일 화면에서는 어림값이라고 적어 둔다. 쿠키 없이 세는 방식이라 같은 사람이 다시 왔는지나 한 페이지에 얼마나 머물렀는지는 알 수 없고, 동선도 한 걸음 앞뒤까지만 보인다. 내 방문 빼기는 브라우저마다 한 번씩 눌러야 하고, 자동 삽입이 하던 유럽 방문자 제외는 블로그 코드가 브라우저의 시간대로 가늠해 따라 해서 실제 위치와 다를 수 있다. 유입처는 도메인 단위로 기억해서, 이미 본 사이트의 다른 글에서 온 링크는 새 알림이 되지 않는다.

기록 #06 · 2026.10.05