카드는 있었고, 켜는 길이 없었습니다
저는 여러 프로젝트 상태를 한 화면에 모아 보는 작은 파이썬 허브(hub.py)를 씁니다. 여기에 GA4 방문 숫자를 보여 주는 카드를 붙이고 싶었습니다.
처음에는 간단해 보였습니다. GA4 측정 ID는 이미 알고 있었습니다. G-로 시작하는 그 문자열은 배포된 페이지의 gtag 스니펫에 그대로 들어 있으니까요. 이 ID만 넘기면 숫자를 받아 올 수 있을 거라고 생각했습니다.
그런데 GA4에서 리포트 데이터를 읽을 때 쓰는 식별자는 측정 ID가 아니라 숫자로 된 property ID입니다. 제가 쥐고 있던 건 데이터를 보내는 쪽 ID였고, 읽는 쪽이 요구하는 건 다른 ID였습니다.
당신의 대시보드가 외부 분석 도구를 읽는다면, 설정 파일에 적어 둔 그 ID는 "보내는 쪽 ID"인가요, "읽는 쪽 ID"인가요?
필요한 건 두 가지였습니다
카드를 실제로 켜려면 두 가지가 비어 있었습니다.
첫째, 읽기 권한이 있는 크리덴셜입니다. 둘째, 그 크리덴셜로 조회할 숫자 property ID입니다. 둘째는 첫째가 있어야 찾을 수 있습니다. property 목록을 보려면 먼저 인증이 돼 있어야 하니까요.
그리고 이 둘을 다 갖춰도 하나가 더 남아 있었습니다. 허브는 launchd가 plist에 적힌 인터프리터로 띄웁니다. GA4용 파이썬 라이브러리를 어딘가에 설치하는 것만으로는 부족하고, 허브를 실행하는 바로 그 인터프리터가 라이브러리를 볼 수 있어야 했습니다.
당신이라면 property ID를 콘솔에서 한 번 복사해 설정에 붙여 넣고 끝내겠습니까, 아니면 측정 ID에서 거꾸로 찾아가게 만들겠습니까?
한 번 동의하고, ID는 스스로 찾게 했습니다
2026-08-07에 ga4_auth.py라는 95줄짜리 스크립트를 새로 만들었습니다. 하는 일은 이렇습니다.
사용자 OAuth 동의를 한 번 받습니다. 스코프는 analytics.readonly 하나입니다. 그렇게 토큰을 발급받은 뒤, Admin API로 접근 가능한 property들을 훑어 제가 가진 측정 ID와 매칭되는 것을 찾습니다. 찾은 숫자 property ID는 파일로 기록해 둡니다.
즉 저는 콘솔에서 숫자를 복사하지 않았습니다. 이미 확실히 알고 있는 값, 페이지에 박혀 있는 측정 ID를 출발점으로 삼고, 거기서 읽는 쪽 ID를 찾아가도록 했습니다.
hub.py 쪽 변경은 크레덴셜과 ID를 읽는 순서를 정하는 일이었습니다. 크리덴셜은 OAuth 토큰이 있으면 그것을 먼저 쓰고, 없으면 서비스 계정으로 넘어갑니다. property ID는 ga4_auth.py가 기록한 파일을 먼저 읽고, 없으면 환경변수를 봅니다.
마지막으로 라이브러리 문제는 새로 설치하지 않고 풀었습니다. 서치 콘솔 리포트용으로 이미 만들어 둔 가상환경에 GA4 라이브러리가 들어 있었기 때문에, 허브의 plist 인터프리터를 그 가상환경의 파이썬으로 바꿨습니다.
변경 규모는 두 파일, 123줄 추가와 8줄 삭제입니다.
자가진단 체크리스트
- 설정에 적어 둔 분석 도구 ID가 데이터를 보내는 용도인지, API로 읽는 용도인지 구분해 두셨나요?
- 크리덴셜이 여러 종류일 때, 코드가 어떤 순서로 무엇을 먼저 집는지 한 곳에 명시돼 있나요?
- 백그라운드로 도는 프로세스가 실제로 어떤 인터프리터로 실행되는지, 그 인터프리터에 필요한 라이브러리가 있는지 확인해 보셨나요?
솔직한 부분
이 커밋은 카드를 켜는 경로를 만든 것이지, 카드가 그 뒤로 어떤 숫자를 보여 줬는지는 기록에 남아 있지 않습니다. 서비스 계정만으로도 같은 일을 할 수 있었는지도 저는 확인하지 않았습니다. 순서상 OAuth를 앞에 두었을 뿐입니다. 사용자 OAuth 토큰이 얼마나 오래 유지되는지도 이 시점에는 따져 보지 않았습니다. 그리고 다른 프로젝트의 가상환경을 빌려 쓰는 결정은 빠르지만, 그쪽 환경이 바뀌면 허브도 같이 흔들린다는 결합을 하나 더 만든 것이기도 합니다.