GA4 빅쿼리 어트리뷰션: 가상 데이터로 배우는 3가지 배분 모델
가상 구매 3건으로 퍼스트터치, 마지막 접점, 선형 배분을 SQL로 비교합니다. 전환별 시각과 관찰 기간을 지키고, GA4 원시 데이터에서 세션과 유입 출처를 준비할 때의 주의점을 설명합니다.

목차
세 줄로 먼저 읽기
이번 방문에서 한 편은 바로 볼 수 있습니다.
같은 구매에 서로 다른 점수를 배분하는 이유
한 이용자가 구글 검색, 소셜 광고, 뉴스레터를 차례로 거쳐 구매했다고 가정해 보겠습니다. 구매 1건을 어느 경로의 성과로 볼까요?
어트리뷰션(attribution)은 구매 같은 중요한 행동의 성과를 접점에 배분하는 방법입니다. 접점은 이 글에서 ‘사이트를 방문한 세션 한 번’으로 정의합니다. 세션은 일정 시간 이어지는 이용 활동의 묶음입니다. 광고 노출이나 클릭 전체를 뜻하는 것은 아닙니다.
| 이 글의 배분 규칙 | 구글 검색 | 소셜 광고 | 뉴스레터 |
|---|---|---|---|
| 퍼스트터치: 경로의 첫 접점에 전부 배분 | 1 | 0 | 0 |
| 마지막 접점: 경로의 마지막 접점에 전부 배분 | 0 | 0 | 1 |
| 선형: 접점마다 똑같이 배분 | 1/3 | 1/3 | 1/3 |
세 결과 모두 합계는 구매 1건입니다. 선형이 균등하다고 해서 실제 영향도 같다는 뜻은 아닙니다. 이 규칙만으로 광고를 하지 않았을 때 구매가 얼마나 줄었을지는 알 수 없습니다.
GA4는 웹사이트와 앱의 이용 현황을 분석하는 도구입니다. 모든 보고서에서 마지막 클릭만 사용하는 것은 아닙니다. 광고의 어트리뷰션 보고서에는 데이터 기반 모델 등이 있고, 세션 범위의 트래픽 획득 보고서와도 구분해야 합니다. 아래 SQL은 학습용 사용자 정의 규칙으로, Google의 데이터 기반 모델이나 마지막 비직접 클릭 모델을 복제하지 않습니다. GA4 어트리뷰션 모델 안내
먼저 가상 자료의 정답을 계산합니다
BigQuery는 데이터를 저장하고 SQL로 조회하는 Google Cloud 서비스입니다. SQL은 필요한 데이터를 고르고 계산하는 언어입니다. 아직 계정이 없다면 아래 표와 예상 결과를 손으로 계산하는 것부터 시작해도 됩니다.
가상 사용자 u1의 세션은 다음과 같습니다. 시각은 모두 국제 기준시인 UTC로 통일했습니다. 한국 시간과는 9시간 차이가 있으며 여기서는 변환하지 않고 표의 시각끼리 비교합니다. 소스는 유입 출처, 매체는 유입 방식으로 google / organic은 구글 자연 검색을 뜻합니다.
| 세션 | 시작 시각 | 소스/매체 |
|---|---|---|
| s1 | 1월 1일 09:00 | google / organic |
| s2 | 1월 5일 09:00 | facebook / cpc |
| s3 | 1월 10일 09:00 | newsletter / email |
| s4 | 1월 11일 09:00 | (direct) / (none) |
u1은 1월 10일 12시와 13시에 서로 다른 주문 두 건을 완료했습니다. 두 구매 모두 그때까지의 s1, s2, s3을 접점으로 사용합니다. 구매 이후인 s4는 들어가지 않습니다.
다른 가상 사용자 u2는 1월 10일에 한 건을 구매했지만, 기록된 세션은 전년도 12월 1일뿐입니다. 이 연습에서는 구매 전 30일 안의 접점만 인정하므로 이 구매는 미배분으로 남깁니다. 30일은 예제의 선택이며 모든 사업의 정답이 아닙니다.
예상 결과
| 소스/매체 | 첫 접점 | 선형 | 마지막 접점 |
|---|---|---|---|
| google / organic | 2 | 약 0.666667 | 0 |
| facebook / cpc | 0 | 약 0.666667 | 0 |
| newsletter / email | 0 | 약 0.666667 | 2 |
| (unattributed) / (unattributed) | 1 | 1 | 1 |
(unattributed)는 이 예제가 만든 ‘연결할 경로 없음’ 표시입니다. GA4의 공식 채널명이 아닙니다. 광고 채널에 배분하지 못한 구매도 이 별도 항목에 1건으로 남겨 총구매 수를 보존합니다. 각 모델의 반올림 전 합계는 3입니다. 선형 결과는 화면의 소수점 반올림 때문에 합계에 아주 작은 차이가 생길 수 있습니다.
가상 자료만 사용하는 SQL 실행하기
아래 코드는 외부 데이터 테이블을 읽거나 저장하지 않습니다. WITH는 이 조회 안에서 사용할 임시 결과에 이름을 붙이는 구문입니다. 별도의 세션 테이블을 먼저 만들 필요가 없습니다.
이미 승인된 BigQuery 작업 환경이 있다면 BigQuery 콘솔의 SQL 편집기에 코드 전체를 붙여 넣습니다. BigQuery의 SQL 문법인 GoogleSQL을 사용하고, 실행 전 편집기의 구문 검사와 예상 처리량을 확인합니다. 문제가 없다면 실행(Run)을 누르고 결과 표를 위의 네 행과 비교합니다. 이 예제에는 회사 프로젝트 이름을 넣지 않습니다. 조직의 작업 권한이나 결제 설정이 필요하면 담당자에게 확인하고, 표를 이용한 연습을 먼저 끝낼 수 있습니다.
-- GoogleSQL: all records below are fictional; no external tables are read.
WITH sessions AS (
SELECT 'u1' AS user_key, 's1' AS session_key,
TIMESTAMP '2026-01-01 09:00:00+00' AS session_start,
'google' AS source, 'organic' AS medium
UNION ALL SELECT 'u1', 's2', TIMESTAMP '2026-01-05 09:00:00+00', 'facebook', 'cpc'
UNION ALL SELECT 'u1', 's3', TIMESTAMP '2026-01-10 09:00:00+00', 'newsletter', 'email'
UNION ALL SELECT 'u1', 's4', TIMESTAMP '2026-01-11 09:00:00+00', '(direct)', '(none)'
UNION ALL SELECT 'u2', 's5', TIMESTAMP '2025-12-01 09:00:00+00', 'google', 'organic'
), conversions AS (
SELECT 'order_a' AS conversion_id, 'u1' AS user_key,
TIMESTAMP '2026-01-10 12:00:00+00' AS conversion_time
UNION ALL SELECT 'order_b', 'u1', TIMESTAMP '2026-01-10 13:00:00+00'
UNION ALL SELECT 'order_c', 'u2', TIMESTAMP '2026-01-10 12:00:00+00'
), paths AS (
SELECT
c.conversion_id,
s.session_key,
s.session_start,
CASE WHEN s.session_key IS NULL THEN '(unattributed)'
ELSE COALESCE(s.source, '(unknown)') END AS source,
CASE WHEN s.session_key IS NULL THEN '(unattributed)'
ELSE COALESCE(s.medium, '(unknown)') END AS medium
FROM conversions c
LEFT JOIN sessions s
ON c.user_key = s.user_key
AND s.session_start <= c.conversion_time
AND s.session_start >= TIMESTAMP_SUB(c.conversion_time, INTERVAL 30 DAY)
), ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY conversion_id ORDER BY session_start, session_key
) AS position,
COUNT(*) OVER (PARTITION BY conversion_id) AS path_length
FROM paths
), credits AS (
SELECT *,
IF(position = 1, 1.0, 0.0) AS first_credit,
1.0 / path_length AS linear_credit,
IF(position = path_length, 1.0, 0.0) AS last_credit
FROM ranked
)
SELECT source, medium,
SUM(first_credit) AS first_touch,
ROUND(SUM(linear_credit), 6) AS linear,
SUM(last_credit) AS last_touch
FROM credits
GROUP BY source, medium
ORDER BY source, medium;
SQL이 하는 일을 다섯 부분으로 읽기
| 이름 | 하는 일 |
|---|---|
| sessions | 가상 세션 5개를 준비함 |
| conversions | 주문 ID가 서로 다른 구매 3건을 준비함 |
| paths | 각 구매보다 늦지 않고 30일 이내인 세션을 연결함 |
| ranked | 구매별로 접점 순서와 개수를 붙임 |
| credits | 첫 접점, 균등, 마지막 접점 점수를 계산함 |
LEFT JOIN은 연결할 세션이 없어도 구매 행을 남깁니다. ROW_NUMBER는 구매별 순서를 매기고 COUNT는 그 구매의 경로 행 수를 계산합니다. 연결할 세션이 없는 구매에는 미배분 행 하나를 남겨 전체 건수에서 빠지지 않도록 했습니다.
정렬 기준은 시작 시각과 세션 키입니다. 시작 시각이 같을 때도 결과가 매번 달라지지 않도록 키를 추가했지만, 키의 정렬 순서가 실제 행동 순서를 증명하지는 않습니다. 실제 자료에 같은 시각의 접점이 있다면 순서 기준을 따로 결정해야 합니다.
구문 오류가 나면 코드의 처음 WITH부터 마지막 세미콜론까지 복사했는지, 마크다운의 세 개짜리 역따옴표까지 붙이지 않았는지 확인합니다.
실행 결과는 네 행이어야 하고, 각 모델 합계는 반올림 오차를 제외하면 3이어야 합니다. Direct 행이 나오면 전환 이후 세션이 잘못 포함됐는지 확인합니다. 전체 합계가 2라면 경로 없는 구매를 빠뜨렸는지 봅니다.
실제 GA4 자료로 바꾸기 전에 준비할 두 표
GA4 내보내기는 이벤트 한 건이 한 행인 원시 자료입니다. 원시 자료를 그대로 위 코드의 세션이나 구매 표처럼 취급하면 안 됩니다. 먼저 분석용으로 정리한 표, 즉 데이터마트를 준비해야 합니다.
| 준비할 표 | 한 행의 뜻 | 필요한 기준 |
|---|---|---|
| sessions | 세션 1건 | 사용자 식별자, 세션 키, 시작 시각, 소스와 매체 |
| conversions | 구분 가능한 구매 1건 | 고유 전환 ID, 사용자 식별자, 실제 구매 시각 |
user_pseudo_id는 웹이나 앱 이용 기록의 가명 식별자이며 실제 사람의 영구 고유 번호가 아닙니다. ga_session_id만으로는 사용자 간 세션을 구분할 수 없어 사용자 식별자와 함께 사용합니다. 서로 다른 스트림을 합친다면 스트림 구분도 포함하는 설계를 검토합니다. 값이 없는 기록은 한 사용자로 합치지 말고 별도 집계합니다.
구매는 세션에 ‘구매 있음’이라는 표시 하나만 남기지 않습니다. 그러면 한 세션의 주문 두 건이 한 건으로 줄어듭니다. 실제 주문 식별자인 transaction_id의 품질과 중복 전송을 확인하고, 누락 또는 충돌 건수를 따로 기록하세요. 세션 시작 시각을 구매 시각으로 대신 사용해서도 안 됩니다.
위 SQL은 conversion_id가 전체 구매 표에서 고유하고 세션 표도 같은 세션을 중복으로 갖지 않는다는 전제입니다. 여러 상점의 주문 번호가 겹치면 상점 구분을 포함한 키가 필요합니다. 같은 고객의 두 주문은 서로 다른 전환 ID를 유지합니다.
유입 출처 필드를 섞지 않기
| GA4 내보내기 필드 | 뜻 |
|---|---|
traffic_source | 사용자를 처음 확보한 출처 정보 |
collected_traffic_source | 개별 이벤트에서 수집된 출처 정보 |
session_traffic_source_last_click | 제공되는 범위에서 세션에 귀속된 마지막 클릭 출처 정보 |
첫 사용자 출처를 모든 세션에 복사하면 재방문의 다른 유입 경로가 사라집니다. 세션 출처에는 해당 기간의 내보내기 스키마와 값을 확인해 맞는 필드를 사용해야 합니다. 스키마는 데이터의 열과 자료형 구조를 뜻합니다. 현재 스키마에는 cross_channel_campaign의 source와 medium 등도 있지만 과거 기간에 같은 값이 있다고 가정하지 않습니다. GA4 내보내기 스키마
소스와 매체는 같은 이벤트 또는 같은 출처 묶음에서 한 쌍으로 고릅니다. 각각 다른 행의 첫 번째 빈값 아닌 값을 가져오면 실제로 존재하지 않았던 조합이 만들어질 수 있습니다. 또한 알 수 없는 출처를 전부 (direct) / (none)으로 채우지 않습니다. 위 예제는 연결된 세션의 출처가 비었을 때 (unknown)으로 따로 표시합니다.
Direct를 제외한다면 다시 계산해야 합니다
이 SQL의 마지막 접점 규칙은 기간 안에 Direct가 있으면 그대로 포함합니다. Google의 유료 및 자연 검색 마지막 클릭 모델은 Direct 처리 방식이 다르므로 결과가 같다고 기대하지 않습니다. Google의 마지막 클릭 규칙
Direct를 빼는 규칙으로 바꾸려면 순서와 접점 수를 계산하기 전에 제외 여부를 정해야 합니다. 선형 점수를 계산한 뒤 Direct 행만 지우면 배분 합계가 줄어듭니다. Direct밖에 없는 구매를 Direct에 둘지 미배분으로 둘지도 정하고, 어떤 경우든 전체 구매 건수와 대조합니다.
실무에서 Direct 비중이 높다는 이유만으로 UTM 설정 오류를 확정하지 않습니다. 출처 정보가 제공되지 않는 이유는 여러 가지입니다. Direct 트래픽 확인 방법
비용과 분석 범위 확인하기
실제 테이블을 조회할 때는 먼저 대상 날짜를 제한하고 필요한 열만 읽습니다. LIMIT 20처럼 결과 행만 줄이는 것은 전체 스캔 비용을 제한하는 방법이 아닐 수 있습니다. 실행 전 예상 처리량을 확인하고, 주문형 과금 환경에서는 Maximum bytes billed로 과금 대상 데이터 읽기량의 상한을 설정할 수 있습니다. 금액을 직접 입력하는 기능은 아닙니다. BigQuery 비용 확인과 제한
예를 들어 2월 구매에 30일 경로를 적용하려면 1월 접점도 준비해야 합니다. 구매 집계 기간과 접점을 읽을 기간을 따로 정하세요. 내보내기를 시작하기 전의 원시 이벤트까지 자동으로 생기는 것은 아니므로, 확보한 자료의 시작 날짜도 남깁니다. BigQuery 내보내기 안내
최종 분석 메모에는 다음을 적습니다.
전환의 단위: 중복 제거한 주문 1건
전환 시각: 실제 구매 이벤트 시각
관찰 기간: 구매 전 30일, 구매 시각 포함
접점 단위: 세션 1건
Direct 처리: 포함
알 수 없는 출처: unknown으로 구분
연결할 경로가 없는 구매: unattributed로 유지
검증: 입력 주문 수 = 모델별 반올림 전 배분 합계
별도 집계: 식별자 누락, 주문 ID 중복, 경로 자료 부족GA4 화면과 비교할 때도 기간, 시간대, 전환 정의, 보고서 범위와 식별 방식부터 맞춥니다. 숫자가 다르다는 이유만으로 기본 보고서가 특정 채널을 과소평가한다고 단정하지 않습니다. 첫 접점 값이 크다는 것은 확보한 경로 안에서 먼저 등장한 경우가 많다는 뜻이지, 고객의 생애 최초 접점을 모두 관찰했다는 뜻은 아닙니다.
혼자 한 번 더 바꿔 보기
가상 sessions의 s4 시각을 1월 10일 12시 30분으로 바꾼다면 어떻게 될까요?
12시 주문 A에는 s4가 포함되지 않고, 13시 주문 B에만 포함됩니다. B의 마지막 접점 점수 1은 Direct로 이동하며 선형은 네 접점에 0.25씩 배분됩니다. A는 기존 세 접점에 각각 1/3을 유지합니다. 두 구매를 같은 세션의 ‘구매 있음’ 한 건으로 합쳤다면 이 차이를 표현할 수 없습니다.
수정 후에도 미배분 주문 C를 포함한 각 모델의 합계는 3이어야 합니다. 이 결과를 설명할 수 있다면 구매 시각과 경로 범위를 구분한 것입니다. 실제 데이터마트를 연결하기 전에는 이 작은 예제의 합계부터 확인합니다.
3줄 요약
-
배분 모델은 기록된 경로의 점수를 나누는 규칙이며 광고의 실제 인과적 효과를 증명하지 않습니다.
-
같은 세션의 여러 구매도 전환 ID와 실제 구매 시각으로 각각 계산해야 합니다.
-
경로가 없는 전환을 남겨 두고 각 모델의 전체 배분 합계가 전환 수와 일치하는지 확인합니다.

제대로 이해했는지 한 문제로 확인해 볼까요?
답을 고르면 바로 풀이가 나와요.
구매 3건 중 한 건은 관찰 기간 안에 연결할 세션이 없습니다. 배분 결과를 어떻게 확인할까요?
이 글이 도움이 되었나요?
GA4 화면의 숫자를 모으고 읽고 보여 주는 세 단계를 정리했습니다
코스 전체 보기 →
새 글과 AI 소식을 메일로 받아 보세요
AI가 바꾸는 일과 도구, 측정 실무 이야기를 매주 한 번 보내 드려요.
