이 글에서는 GA4 API를 활용하여 파이썬으로 데이터를 불러와서 코호트 리텐션 데이터를 구글시트에 자동으로 입력하는 방법에 대해서 알아보겠습니다.
GA4 API와 파이썬 연동하는 방법은 Google Analytics용 Python API(GA4) 사용법(1) 이 글을 참고해 주세요. 연동하는 데에 성공했다면, 이제 이 글을 따라와 주시면 됩니다.
보통 리텐션 차트는 아래와 같은 형태로 되어있습니다. 날짜 형태의 인덱스인 '코호트'는 보통 cohort index라고 부르고, 0~12까지로 되어있는 열은 보통 cohort months, cohort days 등으로 부르죠. 이 글에서는 GA4 API를 활용하여 아래와 같은 형태로 구글 시트에 데이터 입력하는 걸 자동화시키는 과정을 다루겠습니다.
1. CohortSpec 클래스
GA4 API 문서에 CohortSpec이라는 파트가 있습니다. 해당 문서를 살펴보면, 예를 들어 동질 집단의 첫째 주에 획득한 사용자 집단을 cohort 객체에서 지정할 수 있다고 나옵니다. 이 사용자 집단 다음에 이후 6주 동안은 cohortsRange 객체에 지정된다고 합니다.
코호트별 Active Users 수는 cohortActiveUsers 측정항목을 통해 구할 수 있고, 비율은 cohortActiveUsers/cohortTotalUsers 측정항목으로 구할 수 있습니다. 위 이미지에서 모자이크 된 부분에 들어갈 값을 숫자로 넣을 것인지, 비율로 넣을 것인지 정할 수 있는 것이죠.
사용가능한 필드는 cohorts, cohortsRange, cohortReportSettings로 3가지입니다. 하나씩 살펴보겠습니다.
코호트
코호트는 첫째 주에 획득한 사용자 집단을 지정하는 객체로, name, dimension, dateRange를 설정할 수 있습니다. name은 동질 집단에 사용할 이름입니다. cohort index 이름을 어떻게 설정할 것인지를 정하는 것이죠. dimension의 경우, firstSessionDate만 지원합니다.
dateRange는 시작날짜와 마지막날짜 정보가 필요합니다. 이 사이의 날짜의 사용자들이 동질집단으로 묶이게 됩니다. 그래서 dateRange는 필수로 필요한 정보입니다. 시작날짜와 마지막 날짜를 설정하는 기준은 예를 들어, 월 리텐션을 볼거다 하면, 시작 날짜를 해당 월의 첫 번째로 지정해야 하고, 마지막 날짜를 해당 월의 마지막날짜로 지정해야 합니다.
- name: cohort index 이름 커스터마이징
- dimension: firstSessionDate(이외에 다른 선택지 없음)
- dateRange: 동질집단으로 설정할 시작날짜, 마지막날짜 정보
CohortsRange
일별 리텐션을 볼 것인지, 주별 리텐션을 볼것인지, 월별 리텐션을 볼 것인지에 따라서 granularity 정보를 입력할 수 있습니다. granularity는 필수항목입니다.
endOffset을 통해 예를 들어, 몇 월 이후의 리텐션까지 볼 것인지를 정할 수 있습니다. endOffset을 12로 설정하면, 2024년 1월에 처음 세션을 시작한 사용자들이 12월까지 얼마나 남아있는지 볼 수 있습니다. endOffset도 필수항목입니다. startOffset 옵션도 설정할 수 있는데, 일반적으로 0부터 보기 때문에 따로 설정하지 않아도 됩니다.
- granularity
- 일별 리텐션 : DAILY
- 주별 리텐션 : WEEKLY
- 월별 리텐션 : MONTHLY
- endOffset: cohort days 또는 cohort months 등을 몇까지로 설정할 것인지
- startOffset: 필수항목 x. cohort days 또는 cohort months 등을 몇부터 시작할 것인지
cohortReportSettings
동질 집단 보고서의 설정으로, 선택사항입니다. accumulate를 설정할 수 있으며, true를 할 경우에 첫 번째 터치일부터 종료일까지 결과를 누적해 줍니다.
여기까지 GA4 API의 내용이었고, 이제 본격적으로 이 내용을 토대로 코드를 작성해 보겠습니다.
2. 라이브러리 및 Google Analytics API 클라이언트 설정
이 공식 문서를 살펴보면, 데이터 형태가 어떤 식으로 되어야 하는지 나와있습니다. 이 문서를 참고해서 API를 호출해 보겠습니다. 여기서는 예시로 월별 리텐션을 구해보겠습니다.
먼저 Google Analytics Data API 클라이언트를 초기화합니다. 이 클라이언트를 통해 API에 요청을 보내고 데이터를 받을 수 있습니다.
from google.analytics.data_v1beta import BetaAnalyticsDataClient
import os
# os 모듈을 사용하여 환경 변수를 설정할 수 있습니다.
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = 'josn 파일 경로 + 이름'
# Google Analytics 4 속성 ID 설정
property_id = '속성 ID'
# Google Analytics Data API 클라이언트 초기화. 이 클라이언트를 통해 API에 요청을 보내고 데이터를 받을 수 있습니다.
client = BetaAnalyticsDataClient()
코호트 객체의 dateRange를 설정하기 위해, 시작 날짜와 마지막 날짜를 먼저 지정해 주겠습니다. 먼저 이번 달의 첫날을 first_day_of_current_month로 설정하고, 지난 1년간의 월별 범위를 생성합니다. relativedelta() 함수를 사용하면, 일단위뿐만 아니라, 월단위, 연단위까지 더하고 빼는 연산이 가능해집니다.
from datetime import date, datetime, timedelta
from dateutil.relativedelta import relativedelta
import pandas as pd
first_day_of_current_month = today.replace(day=1)
months = pd.date_range(f'{first_day_of_current_month - timedelta(days=365)}', first_day_of_current_month, freq='MS')
end_dates = [(month - timedelta(days=1)).strftime("%Y-%m-%d") for month in months]
start_dates = [(month - relativedelta(months=1)).strftime("%Y-%m-%d") for month in months]
months 결과
DatetimeIndex(['2023-11-01', '2023-12-01', '2024-01-01', '2024-02-01',
'2024-03-01', '2024-04-01', '2024-05-01', '2024-06-01',
'2024-07-01', '2024-08-01', '2024-09-01', '2024-10-01'],
dtype='datetime64[ns]', freq='MS')
end_dates 결과
['2023-10-31',
'2023-11-30',
'2023-12-31',
'2024-01-31',
'2024-02-29',
'2024-03-31',
'2024-04-30',
'2024-05-31',
'2024-06-30',
'2024-07-31',
'2024-08-31',
'2024-09-30']
start_dates 결과
['2023-10-01',
'2023-11-01',
'2023-12-01',
'2024-01-01',
'2024-02-01',
'2024-03-01',
'2024-04-01',
'2024-05-01',
'2024-06-01',
'2024-07-01',
'2024-08-01',
'2024-09-01']
이렇게 매월 기준으로 시작날짜와 마지막 날짜를 담은 리스트를 만들었습니다.
3. 코호트(Cohort) 정의 및 Google Analytics 데이터 요청
먼저 Google Analytics Data API와 관련된 라이브러리와 모듈을 불러와야 합니다. Cohort와 DateRange는 Google Analytics Data API에서 코호트 분석을 할 때 사용하는 클래스입니다. 이를 사용하기 위해서는 google-analytics-data 라이브러리를 설치하고 관련 모듈을 불러와야 합니다.
pip install google-analytics-data
Cohort는 특정 기간 동안 첫 세션을 가진 사용자 그룹을 의미합니다. 이 코드는 각 달을 기준으로 코호트를 정의하며, DateRange를 사용하여 해당 코호트의 시작일과 종료일을 설정합니다. 리스트 컴프리헨셜을 통해서 name에 코호트 인덱스인 start_dates를 입력해 주고, start_date, end_date 각각 데이터를 넣어주어서 dict 형태로 만들어 줍니다.(자세한 내용은 이 문서를 참고)
from google.analytics.data_v1beta.types import Cohort, DateRange
cohorts = [Cohort(name=start,
dimension='firstSessionDate',
date_range=DateRange(start_date=start, end_date=end))
for start, end in zip(start_dates, end_dates)]
cohorts 결과
[name: "2023-10-01"
dimension: "firstSessionDate"
date_range {
start_date: "2023-10-01"
end_date: "2023-10-31"
},
name: "2023-11-01"
dimension: "firstSessionDate"
date_range {
start_date: "2023-11-01"
end_date: "2023-11-30"
},
name: "2023-12-01"
dimension: "firstSessionDate"
date_range {
start_date: "2023-12-01"
end_date: "2023-12-31"
},
name: "2024-01-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-01-01"
end_date: "2024-01-31"
},
name: "2024-02-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-02-01"
end_date: "2024-02-29"
},
name: "2024-03-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-03-01"
end_date: "2024-03-31"
},
name: "2024-04-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-04-01"
end_date: "2024-04-30"
},
name: "2024-05-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-05-01"
end_date: "2024-05-31"
},
name: "2024-06-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-06-01"
end_date: "2024-06-30"
},
name: "2024-07-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-07-01"
end_date: "2024-07-31"
},
name: "2024-08-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-08-01"
end_date: "2024-08-31"
},
name: "2024-09-01"
dimension: "firstSessionDate"
date_range {
start_date: "2024-09-01"
end_date: "2024-09-30"
}]
이제 RunReportRequest를 만들어 Google Analytics API에 데이터를 요청합니다. 여기서는 측정기준(Dimension)에는 코호트(cohort), 코호트의 몇 번째 달(cohortNthMonth) 그리고 웹과 앱을 구분하기 위해 디바이스 카테고리(platformDeviceCategory)을 기준으로 데이터를 가져오겠습니다.
측정 항목(Metric)에는 엑티브 유저수만 측정해 보기 위해 (cohortActiveUser)를 가져오겠습니다. 측정 기준 및 측정 항목(Metric)에 넣을 값은 이 문서에서 찾을 수 있습니다.
CohortSpec 클래스에는 위에서 미리 만들어놓은 cohorts를 넣어주고, cohort_range에는 granularity와 end_offset을 설정해 줍니다. 여기서는 월별 리텐션을 구할 거기 때문에 granularity는 'MONTHLY'로, 첫 세션 이후 12개월까지의 리텐션만 볼 것이기 때문에 end_offset은 12로 설정해 주었습니다.
from google.analytics.data_v1beta.types import RunReportRequest
from google.analytics.data_v1beta.types import Dimension
from google.analytics.data_v1beta.types import Metric
from google.analytics.data_v1beta.types import CohortSpec
request = RunReportRequest(
property=f"properties/{property_id}",
dimensions=[
Dimension(name="platformDeviceCategory"),
Dimension(name="cohort"),
Dimension(name='cohortNthMonth')
],
metrics=[
Metric(name="cohortActiveUsers")
],
cohort_spec=CohortSpec(
cohorts=cohorts,
cohorts_range=CohortsRange(granularity='MONTHLY', end_offset=12),
)
)
이제 여기서 run_report() 함수로 GA4 데이터를 불러오면 아래와 같은 결과가 나옵니다.
# 요청 실행
response = client.run_report(request)
response
dimension_headers {
name: "platformDeviceCategory"
}
dimension_headers {
name: "cohort"
}
dimension_headers {
name: "cohortNthMonth"
}
metric_headers {
name: "cohortActiveUsers"
type_: TYPE_INTEGER
}
rows {
dimension_values {
value: "web / mobile"
}
dimension_values {
value: "2024-01-01"
}
dimension_values {
value: "0000"
}
metric_values {
value: "100000"
}
}
...
4. 데이터 파싱
먼저, 응답 데이터(response)를 파싱 해야 합니다. 우리는 응답 데이터로부터 총 3가지의 측정기준과 1가지의 측정항목을 얻었습니다. 최종적으로 나와야 하는 데이터 형태를 생각하면, 이 측정기준과 측정항목을 어떻게 사용해야 하는지 짐작할 수 있습니다.
우선 측정 기준부터 살펴보겠습니다. platformDeviceCategory, cohort, cohortNthMonth 이렇게 3가지입니다. platformDeviceCategory별로 필터링을 먼저 진행한 후, cohort를 cohort index로 설정하고, cohortNthMonth를 0부터 12까지의 columns로 설정해야 합니다. 측정항목인 cohortActiveUsers의 값을 value값이 들어갈 위치에 넣어주면 작업은 끝납니다. 이를 코드로 구현해 보겠습니다.
먼저 디바이스를 필터링해서 구분해 줄 딕셔너리를 하나 준비해 줍니다. 그리고 cohort index와 0부터 12까지의 cohort months를 담을 컬럼을 만들어 줍니다.
# DataFrame 준비
columns = ['cohort_date'] + [f'Month {n}' for n in range(12 + 1)] # endOffset + 1
device_category_dfs = {}
columns 결과
['cohort_date',
'Month 0',
'Month 1',
'Month 2',
'Month 3',
'Month 4',
'Month 5',
'Month 6',
'Month 7',
'Month 8',
'Month 9',
'Month 10',
'Month 11',
'Month 12']
response의 row를 하나씩 불러올 것입니다. row.dimension_values[0]을 하면 첫 번째 측정기준만 가져오기 때문에 platformDeviceCategory정보를 하나씩 가져오게 됩니다. 마찬가지로 row.dimension_values[1]는 cohort를, row.dimension_values[2]는 cohortNthMonth를 불러오게 됩니다. cohortNthMonth의 경우 데이터 형태가 0000, 0001 식으로 되어있기 때문에 int로 감싸주면 숫자만 000을 제외하고 숫자만 불러오게 됩니다. row.metric_values[0].value으로 측정항목인 cohortActiveUsers도 불러와 줍니다.
미리 만들어놓은 기기카테고리를 구분해 줄 딕셔너리에 데이터를 파싱 해서 담을 건데, 아래 코드가 어떻게 작동하는지 살펴보겠습니다.
for row in response.rows:
platform_device_category = row.dimension_values[0].value
cohort_date = row.dimension_values[1].value
month_index = int(row.dimension_values[2].value)
active_users = int(row.metric_values[0].value)
if platform_device_category not in device_category_dfs:
device_category_dfs[platform_device_category] = {col: [] for col in columns}
data = device_category_dfs[platform_device_category]
if cohort_date not in data['cohort_date']:
data['cohort_date'].append(cohort_date)
for col in columns[1:]:
data[col].append(0)
data[f'Month {month_index}'][data['cohort_date'].index(cohort_date)] = active_users
예시 데이터
가정해 봅시다. response.rows에는 다음과 같은 데이터가 있다고 합시다:
[
{'dimension_values': [{'value': 'Mobile'}, {'value': '2024-01-01'}, {'value': '0'}], 'metric_values': [{'value': '100'}]},
{'dimension_values': [{'value': 'Mobile'}, {'value': '2024-01-01'}, {'value': '1'}], 'metric_values': [{'value': '80'}]},
{'dimension_values': [{'value': 'Desktop'}, {'value': '2024-01-01'}, {'value': '0'}], 'metric_values': [{'value': '150'}]},
{'dimension_values': [{'value': 'Mobile'}, {'value': '2024-02-01'}, {'value': '0'}], 'metric_values': [{'value': '120'}]},
{'dimension_values': [{'value': 'Desktop'}, {'value': '2024-01-01'}, {'value': '1'}], 'metric_values': [{'value': '90'}]}
]
이 데이터는 다음과 같은 정보를 담고 있습니다:
- 첫 번째 행: 'Mobile' 장치에서 2024년 1월 0개월 차에 100명의 활성 사용자가 있었음.
- 두 번째 행: 'Mobile' 장치에서 2024년 1월 1개월 차에 80명의 활성 사용자가 있었음.
- 세 번째 행: 'Desktop' 장치에서 2024년 1월 0개월 차에 150명의 활성 사용자가 있었음.
- 네 번째 행: 'Mobile' 장치에서 2024년 2월 0개월 차에 120명의 활성 사용자가 있었음.
- 다섯 번째 행: 'Desktop' 장치에서 2024년 1월 1개월 차에 90명의 활성 사용자가 있었음.
코드 동작 과정
이 데이터를 바탕으로 코드가 어떻게 작동하는지 살펴보겠습니다.
- 딕셔너리 초기화:
device_category_dfs = {}
데이터 반복 처리:
- 첫 번째 데이터 행 ('Mobile', '2024-01-01', 0, 100):
- 'Mobile'이 device_category_dfs에 없으므로 초기화.
- data 변수는 현재 'Mobile'의 데이터.
- '2024-01-01'이 cohort_date에 없으므로 추가하고 다른 월 초기화.
- data는 현재 다음과 같이 업데이트
{
'cohort_date': ['2024-01-01'],
'Month 0': [100],
'Month 1': [0],
...
}
- 두 번째 데이터 행 ('Mobile', '2024-01-01', 1, 80):
- 'Mobile'의 데이터에서 '2024-01-01'은 이미 존재하므로, 그 인덱스를 찾아서 월 1에 80을 업데이트.
- 현재 data는
{
'cohort_date': ['2024-01-01'],
'Month 0': [100],
'Month 1': [80],
...
}
최종 결과
이 과정을 통해 device_category_dfs에는 다음과 같은 구조가 저장됩니다:
{
'Mobile': {
'cohort_date': ['2024-01-01', '2024-02-01'],
'Month 0': [100, 120],
'Month 1': [80, 0],
...
},
'Desktop': {
'cohort_date': ['2024-01-01'],
'Month 0': [150],
'Month 1': [90],
...
}
}
5. DataFrame 생성
이렇게 파싱 한 데이터를 디바이스 카테고리별로 데이터 프레임으로 만들어줍니다.
# 각 디바이스 카테고리별로 DataFrame 생성
for category, data in device_category_dfs.items():
df = pd.DataFrame(data)
df = df.set_index('cohort_date').sort_index()
device_category_dfs[category] = df
데이터 프레임을 출력해 보면 아래와 같은 형태로 데이터가 잘 저장된 걸 볼 수 있습니다.
# 예시 데이터
device_category_dfs['Mobile']
6. 데이터 구글 시트에 업데이트
마지막 단계는 구글 시트에 데이터를 입력하는 부분입니다. 각 디바이스 카테고리별로 병합된 데이터를 리스트 형태로 변환한 후, worksheet_u_retain_m 객체를 통해 구글 시트의 해당 셀에 데이터를 업데이트합니다.
아래와 같이 row_num_month를 설정해 줌으로써 코드를 돌리면 자동으로 날짜가 계산되어서 시트의 올바른 위치에 입력시켜 줍니다. GA4는 최대 데이터 적재 기간이 14개월이기 때문에 365일 이전까지의 데이터만 불러온 후, 아래와 같은 방식을 사용하여 자동화시킬 수 있습니다.
파이썬과 구글 시트를 연결시키기 위해서는 구글 클라우드 플랫폼에서 몇 가지 해야 할 작업들이 있습니다. 해당 작업은 이 글을 참고해 주세요.
import gspread
from oauth2client.service_account import ServiceAccountCredentials
# 입력할 행 계산
row_num_month = (int(str(today.year)[-2:]) - 20 - 4) * 12 + today.month
# 구글 시트에 데이터를 입력할 수 있는 형태로 변경
data_mobile = device_category_dfs['Mobile'].reset_index(drop=True).values.tolist()
# 구글 시트 연결
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'파일 경로 + 파일이름', scope)
gc = gspread.authorize(credentials)
worksheet = gc.open('시트 제목').worksheet('시트 이름')
worksheet.update(f'A{1 + row_num_month}', data_mobile)
int(str(today.year)[-2:]) 부분은 2024년이면 숫자타입의 24가 됩니다. 여기에 24를 빼주면 0이 되겠죠? 지금이 24년 10월이니 row_num_month는 10이 되고, 24년 11월이면 11이 되고, 25년 1월이면 13이 됩니다.
전체 코드
from dateutil.relativedelta import relativedelta
from google.analytics.data_v1beta.types import CohortSpec, CohortsRange, Cohort
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
RunReportRequest,
Dimension,
Metric,
OrderBy,
DateRange,
FilterExpression,
Filter,
FilterExpressionList
)
import os
from datetime import date, timedelta, datetime
import pandas as pd
import gspread
from oauth2client.service_account import ServiceAccountCredentials
# 구글 시트에 데이터를 입력할 수 있는 형태로 변경
data_mobile = device_category_dfs['Mobile'].reset_index(drop=True).values.tolist()
# 구글 시트 연결
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'파일 경로 + 파일이름', scope)
gc = gspread.authorize(credentials)
worksheet = gc.open('시트 제목').worksheet('시트 이름')
# os 모듈을 사용하여 환경 변수를 설정할 수 있습니다.
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = 'josn 파일 경로 + 이름'
# Google Analytics 4 속성 ID 설정
property_id = '속성 ID'
client = BetaAnalyticsDataClient()
today = date.today()
end_offset = 12 # end_offset 변수 정의
# 월 단위로 날짜 범위 설정
first_day_of_current_month = today.replace(day=1)
months = pd.date_range(f'{first_day_of_current_month - timedelta(days=365)}', first_day_of_current_month, freq='MS')
end_dates = [(month - timedelta(days=1)).strftime("%Y-%m-%d") for month in months]
start_dates = [(month - relativedelta(months=1)).strftime("%Y-%m-%d") for month in months]
cohorts = [Cohort(name=start,
dimension='firstSessionDate',
date_range=DateRange(start_date=start, end_date=end))
for start, end in zip(start_dates, end_dates)]
request = RunReportRequest(
property=f"properties/{property_id}",
dimensions=[
Dimension(name="platformDeviceCategory"),
Dimension(name="cohort"),
Dimension(name='cohortNthMonth')
],
metrics=[
Metric(name="cohortActiveUsers")
],
cohort_spec=CohortSpec(
cohorts=cohorts,
cohorts_range=CohortsRange(granularity='MONTHLY', end_offset=end_offset),
)
)
# 요청 실행
response = client.run_report(request)
# DataFrame 준비
columns = ['cohort_date'] + [f'Month {n}' for n in range(12 + 1)] # endOffset + 1
device_category_dfs = {}
for row in response.rows:
platform_device_category = row.dimension_values[0].value
cohort_date = row.dimension_values[1].value
month_index = int(row.dimension_values[2].value)
active_users = int(row.metric_values[0].value)
if platform_device_category not in device_category_dfs:
device_category_dfs[platform_device_category] = {col: [] for col in columns}
data = device_category_dfs[platform_device_category]
if cohort_date not in data['cohort_date']:
data['cohort_date'].append(cohort_date)
for col in columns[1:]:
data[col].append(0)
data[f'Month {month_index}'][data['cohort_date'].index(cohort_date)] = active_users
# 각 디바이스 카테고리별로 DataFrame 생성
for category, data in device_category_dfs.items():
df = pd.DataFrame(data)
df = df.set_index('cohort_date').sort_index()
device_category_dfs[category] = df
row_num_month = (int(str(today.year)[-2:]) - 20 - 4) * 12 + today.month
worksheet.update(f'A{1 + row_num_month}', data_mobile)
'그로스해킹 > GTM, GA4 API' 카테고리의 다른 글
GA4 API 사용법(3): API 여러번 호출시 함수로 코드 간결화 시키기 (0) | 2024.11.07 |
---|---|
[GTM] id, class 외에 다른 속성 값 매개변수로 수집하기 (0) | 2024.10.29 |
Webview, 하이브리드 앱 GTM 이벤트 설치 및 수집 방법 (2) | 2024.08.13 |
Google Analytics용 Python API(GA4) 사용법(1) (1) | 2024.06.09 |
GA4 데이터로 Carrying Capacity 지표 추적하는 대시보드 만들기 (1) | 2024.03.23 |
댓글