블로그 방문 통계를 에이전트가 확인하면 매번 제가 보고서를 열어 보지 않아도 되겠다 싶었어요. 그런데 GA4를 확인하던 자동화 Edge의 로그인이 Google의 거부 화면에서 막혔어요.

자동화 Edge와 평소 쓰던 Chrome

GA4는 Google Analytics 4, 사이트에 들어온 방문자의 활동을 보고서로 확인하는 도구예요. 저는 이 블로그의 통계를 자동화에서도 확인하려고 했고, 에이전트가 제어하는 Edge에서 Google 로그인 거부 화면을 발견했어요. 평소 쓰던 Chrome에서는 같은 블로그의 GA4 보고서를 열 수 있었어요. 웹 화면을 여는 길이 막힌 상황에서, 프로그램이 데이터를 요청하는 공식 통로인 API로 읽기 전용 조회를 연결했어요. 여기서 필요한 것은 브라우저의 로그인 표시와 실제 보고서 조회 결과를 각각 확인하는 일이었어요.

Chrome에서는 보고서가 열렸어요

제가 자동화 Edge의 거부 화면을 알렸을 때, 에이전트는 기존 Chrome에서 동일한 GA4 속성의 보고서 접근을 확인했어요. 속성은 GA4에서 사이트나 앱의 데이터를 모아 관리하는 단위예요. 브라우저 하나에서는 열리고 다른 쪽에서는 막혔으니, 우선 두 환경의 차이를 볼 수 있었어요.

다만 Chrome에서 열렸다는 사실만으로 “Edge를 Chrome으로 바꾸면 끝”이라고 판단하지는 않았어요. Google의 지원 브라우저 안내는 Chrome과 Edge를 모두 지원 목록에 두면서도, 사람이 아닌 소프트웨어가 제어하거나 다른 앱에 내장된 브라우저의 로그인을 거부할 수 있다고 설명해요. 브라우저 이름과 그 브라우저를 어떻게 제어하는지는 따로 살펴볼 조건이었어요.

이 안내는 자동화 로그인에 걸리는 제한을 이해하는 데 도움이 됐어요. 이번 거부를 일으킨 Google 내부 판정 조건까지 특정한 것은 아니에요. 확인한 장면은 자동화 Edge에서 거부가 보였고, 기존 Chrome에서는 같은 보고서에 접근했다는 차이였어요. 그래서 브라우저의 보안 설정을 풀기보다 공식 API로 필요한 읽기 작업을 연결하는 쪽으로 갔어요.

저는 공식 API 연결, 이 PC에서 쓸 OAuth 클라이언트, 읽기 전용 권한과 갱신 인증 보관을 승인했어요. OAuth는 비밀번호를 프로그램에 건네는 대신, 사용자가 동의한 범위의 접근 권한을 주는 방식이에요. 클라이언트는 그 권한을 요청하는 프로그램을 식별하는 등록 정보고요. 이번 연결은 기존 프로젝트 안에 PC 전용 클라이언트를 따로 만들었어요.

성공을 가르는 줄은 보고서 조회였어요

2026년 10월 9일 01:27:54 KST에 변경을 저장한 Git 커밋이 남았어요. Git 커밋은 코드와 문서의 변경을 한 묶음으로 기록하는 것이고, KST는 한국 표준시예요.

5b2e4c40934f19295260d63c6a4dc491620730e1
GA4 자동 조회를 읽기 전용 OAuth API로 연결하고 로그인 거부를 구분

메시지의 두 동작이 모두 중요했어요. 보고서를 읽는 통로를 추가하면서, 기존 웹 로그인의 거부 상태도 따로 남겼거든요. API가 정상이라고 웹 로그인까지 정상으로 바꾸면, 다음에 웹 화면을 쓰는 작업은 여전히 막혀 있는데 연결 화면만 초록색이 될 수 있어요.

요청 권한에는 다음 값이 들어갔어요.

https://www.googleapis.com/auth/analytics.readonly

readonly는 Analytics 데이터를 읽는 범위예요. 함께 요청한 것은 계정을 식별하기 위한 OpenID와 이메일 확인 권한이었어요. 방문 이벤트를 새로 보내거나 운영 데이터를 쓰는 기능은 이번 연결 범위에서 빠져 있었어요. Google의 Analytics API 시작 안내도 인증 준비와 GA4 속성 접근 권한 부여, API 활성화를 마친 뒤 runReport로 활성 사용자 보고서를 실제로 요청해 보는 흐름이에요. 그 안내는 gcloud 기본 인증을 쓰고, 이번 연결은 PC 전용 OAuth 클라이언트를 썼다는 점은 달라요.

코드에서 성공을 가르는 부분은 다음 한 줄이었어요. 사용자가 동의해서 받은 접근 권한으로 지정한 보고서를 실제로 읽어요.

const report = await readReport({ property: c.property, account: c.account, token: granted.access_token });

property는 조회할 GA4 속성, account는 확인할 계정, token은 요청에 붙이는 접근 인증이에요. await는 이 조회가 끝나기를 기다린다는 뜻이에요. 이 줄이 성공한 다음에 인증 저장 코드가 이어져요.

그 순서 덕분에 동의 화면을 지나왔다는 사실만으로 연결 완료가 되지는 않았어요. 먼저 이메일이 지정 계정과 맞는지 확인하고, 지정 속성에서 보고서를 요청했어요. 응답에 기대한 지표가 있는지, 값이 정수로 읽히는지까지 검사했어요. 다른 계정에 동의했거나 응답이 예상과 다르면 저장 단계에 도착하기 전에 멈추는 구조였어요.

이번 조회 코드는 전날의 activeUsers 지표를 요청했어요. 이 이름은 GA4의 활성 사용자 수를 가리켜요. 여기서는 방문 성과를 발표하려고 숫자를 꺼낸 게 아니라, 지정한 보고서를 실제로 읽을 권한이 있는지 확인하는 데 썼어요.

동의를 마쳤는데 브라우저에는 오류가 떴어요

OAuth 연결에는 인증 요청과 응답을 확인하는 장치도 들어갔어요. PKCE는 요청을 시작한 프로그램이 인증 코드를 교환하는 프로그램과 같은지 확인하도록 돕는 방식이에요. state는 돌아온 응답이 이번에 시작한 동의 요청에 대응하는지 대조하는 임의 값이고요. 인증 코드가 돌아오는 콜백은 같은 PC에서 받도록 했어요. 콜백은 동의 뒤 결과를 전달받는 주소를 뜻해요.

Google에 요청하는 목적지도 코드에 정해 뒀어요. 인증, 계정 확인, 보고서 조회를 각각 고정한 공식 엔드포인트로 보냈어요. 엔드포인트는 프로그램이 요청을 보내는 서비스 주소예요. 응답이 임의의 다른 주소로 돌려보내려 하면 오류로 처리하고, 받은 데이터의 형식도 검사했어요.

그런데 실제 동의 과정에서는 Google의 미인증 앱 경고가 나왔어요. 앱의 게시 상태는 프로덕션으로 확인했지만, 새로운 민감한 권한에 대한 경고는 별도로 표시됐어요. 여기서는 제가 경고를 직접 확인하고 동의했어요. 에이전트가 경고를 자동으로 넘겨서 연결한 과정은 아니에요.

동의 뒤에는 브라우저에 이런 오류가 나타났어요.

ERR_BLOCKED_BY_CLIENT

화면은 차단 오류였는데, 연결 프로세스는 종료 코드 0으로 끝났어요. 종료 코드는 프로그램이 일을 마친 상태를 숫자로 알리는 값이고, 이 실행의 0은 정상 종료를 나타냈어요. 여기에 실제 보고서 조회 성공과 인증 저장까지 확인됐어요. 오류 화면과 조회 성공이 한 번의 연결 과정 안에 함께 있었던 거예요.

그래서 브라우저 오류만 보고 동의를 처음부터 다시 하지는 않았어요. 반대로 종료 코드 하나만 보고 모든 화면이 정상이라고 정리하지도 않았어요. 실제 조회 결과를 확인한 뒤, 동의가 끝나면 임시 코드 화면 대신 운영 콘솔로 돌아오도록 응답을 고쳤어요. 콘솔은 연결 상태를 모아 보는 운영 화면이에요. 보안 차단을 끄는 대신 연결 뒤의 화면 복귀 동선을 바꾼 셈이에요.

여기서 확인한 범위도 나뉘어요. 새 응답은 문법과 관련 콜백 검사로 확인했어요. 이미 성공한 갱신 인증을 다시 만들지 않으려고 OAuth 동의를 반복하지는 않았어요. 새 동의 뒤 브라우저가 콘솔로 돌아오는 전체 장면은 다음 재동의 때 확인할 항목으로 남았어요. ERR_BLOCKED_BY_CLIENT를 일으킨 구체적인 차단 주체도 이번 결과에서 특정하지 않았어요.

9개와 2개, 그리고 두 번의 실제 조회

흐름을 이어 보면 자동화 Edge 로그인 거부 → 기존 Chrome의 동일 보고서 접근 확인 → 읽기 전용 OAuth 승인 → 사용자 경고 확인·동의 → 콜백 오류 화면과 조회 성공 확인 → 복귀 응답 수정 → 갱신 인증으로 조회와 연결 점검 성공이었어요.

순수 테스트는 9개가 통과했어요. 여기서 순수 테스트는 실제 Google 계정에 연결하는 대신 입력과 응답을 준비해 코드의 판단을 살펴보는 시험이에요.

로그인 탭 보호와 거부 분류 회귀 테스트는 2개가 통과했어요. 회귀 테스트는 변경 뒤에 기존 동작이 깨지지 않았는지 확인하는 시험이에요. 유지 중인 로그인 탭에서 보이는 거부를 단순 인증 만료로 처리하지 않는지 확인했어요. 자동화가 같은 로그인 버튼을 다시 누르는 것보다, 지금 막힌 이유를 제대로 표시하는 일이 먼저였어요.

실제 연결 뒤에는 갱신 인증으로 report와 연결 점검을 각각 실행했고, 둘 다 성공했어요. report는 보고서를 읽는 동작이에요. 갱신 인증은 처음 동의한 권한으로 새 접근 인증을 받아 계속 조회할 때 사용하는 정보예요. 한 번의 동의 직후 성공에서 그치지 않고, 저장한 인증으로 다음 조회도 되는지 확인한 거예요.

콘솔에는 지정 계정의 API 연결이 정상으로 표시됐어요. 인증이 등록되지 않은 상태를 정상으로 표시하지 않는 것도 실제 화면에서 확인했어요. 인증 정보는 저장소 밖의 PC 전용 폴더에 보관했고, 연결 화면에는 상태와 확인 시각처럼 판단에 필요한 정보만 남겼어요.

연결 화면에는 두 상태를 남겼어요

GA4 API가 정상이어도 자동화 Edge의 웹 로그인 거부는 별도 상태로 남겼어요. 같은 Google 계정이라는 이유로 다른 Google 사이트의 인증까지 회복됐다고 표시하지 않았어요.

통계 조회에는 Analytics 읽기 전용 권한과 계정 확인 범위면 충분했어요. 동의 뒤 지정 계정과 속성의 보고서를 읽고 응답 형식을 검증한 다음 인증을 저장했으며, 저장한 갱신 인증의 다음 조회도 성공했어요. Google이 갱신 인증을 폐기하면 사용자 재연결이 필요해요.

남은 일은 다음 재동의 때 브라우저가 콘솔로 돌아오는 장면을 확인하는 것이에요. 오류 화면은 남았지만 에이전트가 맡은 보고서 읽기는 끝났고, 두 결과를 따로 기록했어요.

참고한 자료