직접 해 본 결과만 적습니다 · 확인하지 못한 것은 그렇게 표시합니다
써 AI 마케팅 적용기 시중에 나온 AI 방법을 실무에 넣어 보고, 쓸만한지 남깁니다
유입 늘리기

구글애널리틱스 GA4 붙이기 — 태그 설치부터 API로 방문자수 읽기까지

계속 쓴다2026-08-07·읽기 11분·글 써봄

구글애널리틱스(GA4)를 사이트에 붙이는 건 15분이면 끝납니다. 속성을 만들고 G- 로 시작하는 태그 한 줄을 <head> 에 넣으면 방문자수가 쌓이기 시작합니다.

문제는 그다음입니다. 화면으로 보는 것 말고 내 프로그램이 숫자를 직접 읽어오게 하려면 준비물이 완전히 다릅니다. 여기서 대부분 막힙니다. 저도 그랬습니다.

앞부분은 태그 설치, 뒷부분은 자동 조회입니다. 화면으로만 보실 거면 앞부분만 보셔도 됩니다.

GA4 속성 만들기 — 4단계

analytics.google.com 에 들어갑니다.

1. 왼쪽 아래 관리 → 계정 만들기 → 계정 이름 입력

2. 속성 만들기 에서 시간대와 통화를 확인합니다. 여기가 첫 번째 함정입니다. 기본값이 미국으로 잡히는 경우가 있는데, 그러면 화면의 "오늘 조회수"가 실제와 하루씩 어긋납니다. 나중에 바꿔도 과거 데이터는 안 고쳐집니다.

3. 데이터 스트림 → 웹 → 사이트 주소 입력 → 스트림 만들기

4. 만들어진 화면 오른쪽 위에 측정 ID G-XXXXXXXXXX 가 나옵니다. 복사해 둡니다.

태그 넣기

Google이 주는 로더를 <head> 안에 넣습니다. </head> 직전이 아니라 가능한 위쪽이 좋습니다. 페이지를 열자마자 실행돼야 이탈한 방문도 잡힙니다.

<script async src="https://www.googletagmanager.com/gtag/js?id=G-측정ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-측정ID');
</script>

정적 사이트를 빌드해서 쓴다면 템플릿의 <head> 에 한 번 넣어 모든 페이지에 자동으로 들어가게 합니다.

이때 설정값을 검증하고 넣어야 합니다. 설정 파일에서 읽은 값을 그대로 <script> 안에 끼우면, 그 값이 잘못됐을 때 스크립트가 주입되는 통로가 됩니다.

_MEASUREMENT_RE = re.compile(r"G-[A-Z0-9]{4,20}")

def ga_snippet(mid: str) -> str:
    """형식이 어긋나면 태그를 아예 넣지 않는다."""
    if not _MEASUREMENT_RE.fullmatch(mid):
        return ""
    return f'<script async src="https://www.googletagmanager.com/gtag/js?id={mid}"></script>…'

넣고 나면 실제로 들어갔는지 확인합니다. 배포했다고 반영된 게 아닙니다.

라이브 페이지에 gtag 스크립트가 실제로 들어갔는지 확인한 터미널 화면

미리보기 빌드에는 태그를 넣지 마세요. 검토하려고 연 화면이 전부 방문으로 잡혀서 통계가 실제 독자와 섞입니다. 빌드 옵션으로 갈라두는 편이 낫습니다.

여기서부터가 진짜입니다 — 숫자를 프로그램으로 읽기

화면으로 보는 것과 API로 읽어오는 것은 완전히 다른 일입니다. 태그를 넣었다고 읽어지지 않습니다.

함정 하나. 측정 ID로는 조회가 안 됩니다

증상 — 태그도 넣었고 화면에는 숫자가 보이는데, 코드로 조회하면 계속 실패합니다.

원인 — 값이 두 개 필요한데 이름이 비슷해서 하나만 챙기게 됩니다. 저는 측정 ID를 넣고 왜 안 되는지 한참 봤습니다.

해결 — 아래 두 값을 처음부터 둘 다 적어둡니다.

값 생김새 어디에 쓰나 어디서 찾나
측정 ID G-XXXXXXXXXX 사이트에 태그 넣을 때 데이터 스트림 화면
속성 ID 987654321 같은 숫자 API 조회할 때 관리 → 속성 세부정보

속성 ID를 빨리 찾는 방법이 있습니다. GA4를 연 상태에서 주소창을 보면 p 뒤에 붙은 숫자가 속성 ID입니다.

analytics.google.com/analytics/web/#/a123456789p987654321/admin
                                              └─ 이 숫자

함정 둘. 서비스 계정과 속성 권한이 둘 다 필요합니다

증상 — 인증은 통과하는데 조회에서 HTTP 403 이 납니다.

원인 — API는 사람 로그인이 아니라 서비스 계정으로 접근하는데, 키를 만든 것과 그 계정에게 이 속성을 볼 권한을 준 것은 별개이기 때문입니다.

해결 — 두 가지를 다 해야 열립니다.

1. 구글 클라우드 콘솔에서 서비스 계정을 만들고 JSON 키를 받습니다. 이 파일은 비밀번호와 같습니다. 권한을 600 으로 두고 저장소에 올리지 않습니다.

2. GA4 → 관리 → 속성 액세스 관리 → + → 서비스 계정 이메일을 뷰어로 추가합니다.

둘 중 하나만 하면 안 됩니다. 권한을 뺀 순간 바로 되돌아갑니다 — 캐시된 값이 남아 있어도 갱신이 안 됩니다.

권한은 속성 단위라, 사이트를 여러 개 운영하면 계정 하나를 여러 속성에 뷰어로 넣어 쓸 수 있습니다. 서로의 데이터는 보이지 않습니다. 저는 이미 쓰던 서비스 계정을 새 속성에 뷰어로 추가하는 것만으로 끝냈습니다. 키를 새로 받지 않아도 됐습니다.

둘 다 갖춰지면 이렇게 읽힙니다.

서비스 계정 권한이 갖춰진 뒤 조회가 성공한 터미널 화면

숫자가 0인 것은 정상입니다. 태그를 심은 당일이라 아직 쌓인 게 없습니다. 중요한 건 조회 자체가 200 으로 열렸다는 점입니다. 저는 여기서 한 번 헷갈렸는데, 0이 나오길래 권한이 덜 붙은 줄 알고 설정을 다시 봤습니다. 연결 실패와 데이터 없음은 화면에서 구분되게 만들어두는 편이 낫습니다.

함정 셋. 요청은 5개까지만 묶입니다

증상 — 코드는 맞는데 HTTP 400 만 돌아옵니다. 인증 문제인 줄 알고 키부터 다시 봅니다.

원인 — 여러 보고서를 한 번에 받으려고 batchRunReports 를 쓰는데, 6개를 보내면 전부 실패합니다. 하나가 잘리는 게 아니라 요청 전체가 거부됩니다.

요청 6개는 HTTP 400, 5개는 200으로 갈리는 것을 확인한 터미널 화면

해결 — 요청을 5개 이하로 줄입니다. 저는 요약·직전기간·일별추이·인기페이지·유입채널·유입출처 여섯 개를 한 번에 보내다 막혔고, 차원을 합쳐서 5개로 만들었습니다.

# 채널과 출처를 한 요청에 담고, 받은 뒤에 각각 합산한다
_req(start, end, ("sessions", "activeUsers"),
     ("sessionDefaultChannelGroup", "sessionSource"), limit=200)

받아온 표를 코드에서 두 번 훑어 채널별·출처별로 각각 더하면 보고서 두 개를 만든 것과 같은 결과가 나옵니다. 요청 하나를 아끼는 대신 코드가 조금 늘어나는 교환입니다.

이 제한은 요청 개수만 세기 때문에, 작은 요청 하나로 먼저 200 을 확인하고 나서 늘리는 순서로 만들면 훨씬 빨리 찾습니다. 저는 여섯 개를 한 번에 만들어 던져놓고 인증부터 의심했습니다.

함정 넷. 검색어는 GA4가 주지 않습니다

블로그를 운영하면 "무슨 검색어로 들어왔나"가 제일 궁금한데, GA4에는 그 데이터가 없습니다. 구글도 네이버도 검색어를 애널리틱스에 넘기지 않습니다.

알고 싶은 것 GA4 어디서 봐야 하나
방문자수·조회수 됩니다 GA4
유입 채널(검색·SNS·직접) 됩니다 GA4
유입 출처(google·naver) 됩니다 GA4
실제 검색어 안 됩니다 서치콘솔·서치어드바이저

검색어까지 보려면 서치콘솔을 따로 붙여야 합니다. GA4에서 찾다가 시간을 쓰지 않으셔도 됩니다.

해결이라기보다 우회입니다. 서치콘솔과 GA4를 연결하면 한 화면에서 같이 보이긴 하는데, 그것도 검색어 데이터를 GA4로 옮겨주는 게 아니라 두 화면을 나란히 놓아주는 수준입니다. 검색어별 방문 흐름을 끝까지 이어보는 방법은 아직 찾지 못했습니다. 두 쪽 데이터를 글 주소 기준으로 직접 맞춰 붙이면 될 것 같은데, 그건 아직 안 해봤습니다.

조회 코드

인증부터 조회까지 최소 형태입니다.

from google.auth.transport.requests import Request
from google.oauth2 import service_account
import json, urllib.request

SCOPE = "https://www.googleapis.com/auth/analytics.readonly"
API = "https://analyticsdata.googleapis.com/v1beta/properties/{}:batchRunReports"

cred = service_account.Credentials.from_service_account_file(KEY_PATH, scopes=[SCOPE])
cred.refresh(Request())

body = {"requests": [{
    "dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
    "metrics": [{"name": "activeUsers"}, {"name": "screenPageViews"}],
}]}
req = urllib.request.Request(API.format(PROPERTY_ID),
        data=json.dumps(body).encode(),
        headers={"Authorization": f"Bearer {cred.token}",
                 "Content-Type": "application/json"})

두 가지를 같이 넣어두면 운영이 편합니다.

  • 캐시 — 화면을 열 때마다 조회하면 한도를 금방 씁니다. 저는 기간별로 15분씩 담아 두고, 새로고침 버튼을 눌렀을 때만 강제로 다시 읽게 했습니다.
  • 폴백 — 조회가 실패하면 예외로 죽이지 말고, 마지막으로 받은 값과 "왜 못 읽었는지"를 화면에 보여줍니다. 권한이 빠졌는지, 네트워크 문제인지, 아직 데이터가 없는 건지가 화면에서 구분돼야 고칠 수 있습니다.

오류 메시지를 만들 때는 키 파일 내용이 섞이지 않게 합니다. 예외를 그대로 문자열로 만들면 인증 정보가 로그에 남을 수 있습니다.

except Exception as exc:
    # private_key 가 예외 문자열에 섞이지 않도록 종류만 알린다
    raise AnalyticsUnavailable(f"인증 실패 ({type(exc).__name__})") from exc

키 파일 권한도 코드에서 확인하게 해두면 좋습니다. 실수로 644 로 풀린 채 서버에 올라가는 일이 생기는데, 조회할 때마다 검사하면 바로 잡힙니다.

붙이고 나면 확인할 것

확인 방법 정상
태그가 들어갔나 페이지 소스에서 googletagmanager 검색 1곳
수집이 시작됐나 GA4 → 보고서 → 실시간 본인 방문이 잡힘
API가 열렸나 조회 코드 실행 HTTP 200
값이 맞나 실시간 화면과 API 결과 비교 비슷한 수치

태그를 심은 날부터 데이터가 쌓입니다. 과거는 소급되지 않습니다. 그래서 사이트를 만들 때 제일 먼저 붙여두는 편이 낫습니다.

흔한 오해 셋

이렇게 알기 쉽다 실제
태그를 넣으면 API도 된다 서비스 계정과 속성 권한이 따로 필요합니다
측정 ID 하나면 된다 조회에는 숫자로 된 속성 ID가 따로 있습니다
GA4에 검색어가 있다 없습니다. 서치콘솔을 봐야 합니다

판정 — 계속 쓴다

무료이고, 태그 설치는 15분이면 끝납니다. 방문자수·유입 채널·인기 글까지 보는 데 다른 선택지를 찾을 이유가 없습니다.

자동 조회는 반나절 잡으시면 됩니다. 위 함정 넷을 미리 알면 훨씬 빠릅니다. 저는 요청 5개 제한을 모르고 한참 헤맸습니다 — 코드는 맞는데 HTTP 400 만 나와서 인증 문제인 줄 알았습니다.

검색어를 기대하고 붙이면 실망합니다. 그건 서치콘솔의 몫입니다.

직접 붙이실 분께

하나. 속성을 만들 때 시간대부터 확인합니다. 나중에 바꿔도 과거 데이터는 안 고쳐집니다.

둘. 측정 ID와 속성 ID를 처음부터 둘 다 적어둡니다. 나중에 찾으려면 화면을 헤매게 됩니다.

셋. 자동 조회를 만들 때는 작은 요청 하나로 먼저 200을 확인하고 나서 보고서를 늘립니다. 여섯 개를 한 번에 만들어 던지면 어디서 틀렸는지 구분이 안 됩니다.

넷. 서비스 계정 키 파일은 저장소에 올리지 않습니다. .gitignore 에 먼저 적어두고 파일을 만드는 순서가 안전합니다.

다음에는 서치콘솔을 붙여서 실제 검색어까지 한 화면에서 보게 만들어보려고 합니다. 되면 이어서 적겠습니다.