구독 없이 실시간 웹사이트 방문자 추적하기

한 클라이언트가 자신의 웹사이트에 누가 접속해 있는지 실시간으로 확인하고 싶어 했습니다.

그들은 Tidio 위젯을 마음에 들어 했지만, 구독료를 지불하고 싶어 하지 않았습니다.

과제는 두 가지 측면이 있었습니다:

  • 사이트는 서로 다른 호스팅에서 WordPress를 사용하고 있었습니다.
  • WordPress 설정에 Firebase를 직접 추가할 수 없었습니다.

저는 Firebase를 사용하여 외부 트래커를 구축했습니다. 작동 방식은 다음과 같습니다.

해결 방법

WordPress 헤더에 단일 스크립트 태그를 사용했습니다. 이 스크립트는 독립적인 Firebase 프로젝트에 연결됩니다.

실시간 접속 상태(Live Presence): onDisconnect() 함수가 포함된 Firebase Realtime Database를 사용했습니다. 이를 통해 사용자가 탭을 닫거나 연결이 끊어지면 "online" 목록에서 자동으로 제거됩니다. • 방문자 기록(Visitor History): Netlify Function을 사용하여 Firestore에 데이터를 기록했습니다. 이를 통해 서버 측 IP 지오로케이션(IP geolocation)이 가능해집니다. • 보안(Security): 익명 인증(anonymous authentication)을 사용했습니다. 방문자는 자신의 세션 노드에만 데이터를 쓸 수 있으며, 관리자만이 전체 목록을 읽을 수 있습니다.

까다로운 버그들

구축 과정이 순탄치 않았습니다. 세 가지 주요 기술적 난관에 부딪혔습니다.

1. 캐싱의 함정

기록에 세션이 전혀 나타나지 않았습니다. 확인 결과, 트래커 스크립트에 1년의 캐시 정책이 설정되어 있었습니다. 방문자들은 계속해서 이전 버전의 스크립트를 사용하고 있었습니다.

  • 해결책: 트래커 스크립트에 대해 5분 캐시 정책을 설정했습니다.

2. 가짜 CORS 에러

브라우저에서 CORS 에러가 발생했습니다. 처음에는 도메인 화이트리스트 문제라고 생각했습니다. 간단한 curl 테스트를 해보니 서버는 정상적으로 작동했습니다. 실상은 달랐습니다. 서버가 실제로 충돌(crash)하고 있었습니다. Node.js에서 204 상태 코드를 사용할 때, 본문(body)에 빈 문자열을 사용할 수 없습니다. 반드시 null을 사용해야 합니다. 빈 문자열은 CORS 헤더가 전송되기 전에 충돌을 일으켰습니다. 브라우저는 헤더를 받지 못하자 이를 CORS 문제로 간주했습니다.

  • 해결책: 응답 본문을 ''에서 null로 변경했습니다.

3. 누락된 데이터 간극

"오늘" 또는 "최근 7일" 필터를 적용하면 아무것도 반환되지 않았습니다. 일부 사용자는 위치가 "Unknown"으로 표시되었습니다. 이는 페이지가 처음 로드될 때만 타임스탬프와 위치를 계산했기 때문에 발생했습니다. 사용자의 브라우저에 오래된 세션이 남아 있는 경우, 서버는 "start" 이벤트를 놓치게 됩니다.

  • 해결책: 계산 과정을 멱등(idempotent)하게 만들었습니다. 이제 스크립트는 모든 이벤트 발생 시 이 값들을 다시 계산합니다.

핵심 요약

• 브라우저의 CORS 에러가 항상 설정 문제인 것은 아닙니다. 서버 충돌을 숨기고 있을 수도 있습니다. 항상 서버 로그를 확인하세요. • curl POST 테스트는 브라우저를 완벽히 테스트하지 못합니다. 브라우저는 먼저 OPTIONS 프리플라이트(preflight) 요청을 보냅니다. 유효한 테스트를 위해서는 이 요청을 포함해야 합니다. • 204와 같이 "내용 없음"을 의미하는 HTTP 상태 코드에는 null을 사용하세요. 빈 문자열을 사용하지 마세요.

Source: https://dev.to/androve2k/whos-online-on-the-site-without-tidio-live-presence-and-visitor-history-with-firebase-37il