광고 픽셀은 UTM이 사라져도 어떻게 전환을 잡는가

Cookie-based Click Attribution & SPA Pageview Tracking

NetworkBrowsercookieattribution

난이도: ★★★☆☆
연관 노트: 왜 서버는 이전 요청을 기억하지 않는가


핵심 요약

  1. 스크립트는 광고 유입 시에만 실행되는 게 아니라 모든 방문자에게 항상 실행된다.
  2. 광고 클릭 시 URL에 붙어오는 클릭 ID를 스크립트가 감지해 쿠키에 저장하고, 이후 전환 이벤트가 발생하면 그 쿠키값을 매체 서버로 전송한다.
  3. 매체 서버는 클릭 ID를 외래키로 캠페인 정보를 조회해 전환을 카운팅한다.

왜 헷갈렸나

  • UTM이 URL에서 사라지면 전환 추적도 불가능하다고 생각했음 → UTM은 URL 파라미터라 소실되지만, 쿠키는 브라우저에 남는다
  • “광고 유입 시에만 스크립트가 실행된다”고 생각했음 → 스크립트는 항상 실행, 클릭 ID가 있을 때만 쿠키에 저장
  • 매체 서버로 보내는 방식이 POST라고 단정했음 → 이미지 픽셀(구식)은 GET, 현대 JS 픽셀은 navigator.sendBeacon() / fetch()

메커니즘

1. 클릭 ID — 쿠키 저장

[광고 캠페인 클릭]
  URL: mysite.com?gclid=CjwKCAiA9abc123
                  ^
                  광고 매체가 발급한 클릭 ID (영수증 번호)

[픽셀 스크립트 실행 — 모든 방문자]
  URL 쿼리스트링에 gclid가 있는가?
    → Yes: _gcl_au 쿠키에 저장 (만료: 90일)
    → No:  아무 것도 저장 안 함. 스크립트는 계속 실행됨

[이후 UTM 소실해도]
  쿠키: _gcl_au=CjwKCAiA9abc123  ← 브라우저에 잔류

2. 전환 이벤트 → 매체 서버 전송

[전환 이벤트 발생]
  pixel({ event: 'purchase', value: 100 })

[픽셀 내부]
  쿠키에서 _gcl_au 읽기 → CjwKCAiA9abc123
  
  HTTP 요청 전송:
  POST https://google-analytics.com/collect
  Body: { event: 'purchase', gclid: 'CjwKCAiA9abc123', ... }

[매체 서버]
  gclid 'CjwKCAiA9abc123' 조회
  → "이건 캠페인 A, 광고그룹 B, 키워드 C에서 발생한 클릭"
  → 해당 캠페인 전환 +1

클릭 ID는 캠페인 정보를 직접 담지 않는다. 캠페인 정보를 조회하는 외래키다.

3. 매체별 클릭 ID 쿠키

매체클릭 ID 파라미터쿠키명
Google Adsgclid_gcl_au
Metafbclid_fbp, _fbc
Navernclickid (비공개)자체 쿠키
국내 DSP(매체별 상이)자체 쿠키

어트리뷰션 인플레이션

여러 매체를 순서대로 클릭하면, 각 매체가 독립적으로 자기 쿠키를 심는다.

[사용자 행동]
  네이버 광고 클릭 → 쿠키 N 저장
  구글 광고 클릭  → 쿠키 G 저장
  메타 광고 클릭  → 쿠키 M 저장
  오가닉 진입 후 결제

[전환 이벤트 발생 — 모든 픽셀 동시 실행]
  naverPixel({ event: 'join' })  → 쿠키 N 전송 → 네이버: 전환 +1
  googlePixel({ event: 'join' }) → 쿠키 G 전송 → 구글:   전환 +1
  metaPixel('Purchase')          → 쿠키 M 전송 → 메타:   전환 +1

실제 전환: 1건
각 매체 리포트 합산: 3건

각 매체는 자기 쿠키만 본다. 다른 매체가 있었는지 모른다. 그래서 동시에 “내가 기여했다”고 주장한다.

라스트 클릭 문제: 실제로 구글이 마지막 클릭이었어도, 메타는 “내 lookback window(7일) 내에 클릭이 있었다”는 이유로 전환을 가져간다. 각자의 “라스트 클릭”이 겹친다.

→ 해결: 모든 채널을 한 곳에서 보는 서드파티 어트리뷰션 툴 (GA4, Triple Whale 등). 각 매체 리포트를 신뢰하지 않고 자체 기준으로 어트리뷰션.


SPA에서 pageview를 수동 호출해야 하는 이유

일반 웹사이트(MPA)는 페이지 이동 = 실제 페이지 리로드 → 스크립트 재실행 → pageview 자동 전송.

[MPA]
  페이지 이동 → HTML 재요청 → 스크립트 재로드 → pageview 자동 ✓

[SPA (Next.js)]
  페이지 이동 → URL만 바뀜 → 스크립트 재로드 없음 → pageview 안 찍힘 ✗
  
  해결: routeChangeComplete에 수동 연결
// _app.tsx
Router.events.on("routeChangeComplete", () => {
  pixelAPageView();   // 매체 A — 어트리뷰션용
  pixelBPageView();   // 매체 B — 행동 수집용
  // 설치된 모든 매체 픽셀 pageview 호출
});

routeChangeComplete = Next.js Router에서 URL 변경이 완료된 시점. 이때 수동으로 호출해야 각 매체가 사용자 행동을 정상 트래킹한다.


어트리뷰션 픽셀 vs 행동 수집 픽셀

일부 매체는 두 개의 파이프라인을 분리해 제공한다.

어트리뷰션 픽셀행동 수집 픽셀
목적광고 어트리뷰션 측정방문자 행동 수집
용도ROAS 계산, 전환 카운팅리타게팅 오디언스 구축
함수trackConversion({ type })trackPageView()

다음에 이 상황을 만나면

트리거: 새 광고 매체 픽셀 설치 요청이 올 때

  • 픽셀 스크립트를 _app.tsx에 삽입 (모든 페이지에 로드되도록)
  • SPA라면 routeChangeComplete에 pageview 수동 연결
  • 전환 이벤트는 실제 전환 페이지(결제 완료 등)에만 발화
  • Window 타입 선언 추가 (declare global { interface Window { ... } })
  • 스크립트 로드 전 함수 호출 대비 — 큐 패턴 확인
// 큐 패턴: 스크립트 로드 전 호출을 쌓아뒀다가 로드 후 실행
window.pixelSDK =
  window.pixelSDK ||
  function (...args: unknown[]) {
    (window.pixelSDK.q = window.pixelSDK.q || []).push(args);
  };
window.pixelSDK(); // 큐에 쌓임 → SDK 스크립트 로드 후 자동 처리

커넥팅 닷

← 선행 개념 (이걸 알아야 이해된다)

  • 왜 서버는 이전 요청을 기억하지 않는가 — HTTP Stateless이기 때문에 상태(클릭 정보)를 쿠키에 저장하는 구조가 필요함. 쿠키가 상태를 들고 있는 HTTP 레이어 원리와 동일
  • HTTP 쿠키 (Set-Cookie / Cookie 헤더) — 브라우저가 쿠키를 저장하고 이후 요청마다 자동으로 포함하는 원리. 픽셀이 쿠키를 읽어 전송하는 메커니즘의 기반

→ 확장 개념 (여기서 더 나아가면)

  • ITP (Intelligent Tracking Prevention) — Safari의 서드파티 쿠키 제한. 픽셀 추적 정확도를 떨어뜨리는 주요 원인. 매체들이 서버사이드 픽셀(Conversions API)로 전환하는 이유
  • Conversions API (CAPI) — 브라우저 픽셀 대신 서버에서 직접 매체 서버로 전환 이벤트를 보내는 방식. ITP 우회 + 쿠키 의존도 제거
  • Multi-touch Attribution — 라스트 클릭 대신 터치포인트마다 기여도를 나눠주는 모델. Linear, Time-decay, Data-driven 등

↔ 같은 원리가 적용되는 곳


참고