콘텐츠로 이동

Funnel, Cohort & Retention Metrics

분류: Layer 13 - Product Engineering & Growth Systems

tracking plan이 “무엇을 기록할 것인가”를 정한다면, funnel·cohort·retention은 “그 기록을 어떤 비교 단위로 읽을 것인가”를 정한다. Product Engineer는 이벤트 수집에서 멈추지 않고 다음 질문에 재현 가능한 답을 붙여야 한다.

  • 사용자는 목표 행동까지 가는 어느 단계에서 이탈하는가?
  • 서로 다른 시점과 조건에서 시작한 사용자군의 결과는 어떻게 다른가?
  • 시간이 지난 뒤에도 사용자가 제품의 핵심 가치를 반복해서 얻는가?
  • 지표 변화가 제품 변화인지, 분모·윈도우·이벤트 품질이 만든 착시인지 어떻게 구분하는가?

Funnel(퍼널) 은 사용자가 목표 행동까지 가는 순서 있는 단계를 놓고, 각 단계에 도달한 분석 단위의 비율을 계산하는 방법이다. “몇 건 발생했는가”보다 “어디에서 다음 단계로 넘어가지 못했는가”를 찾기 위해 등장했다.

Cohort(코호트) 는 같은 시작 시점이나 조건을 공유하는 분석 대상의 집합이다. 전체 평균에 서로 다른 사용자군이 섞여 원인을 숨기는 문제를 줄인다. 가입 주차가 같은 사용자, 같은 주에 생성된 workspace, 특정 기능을 처음 사용한 account가 각각 cohort가 될 수 있다.

Retention(리텐션, 유지율) 은 cohort가 시간이 지난 뒤에도 제품 가치와 연결된 행동을 다시 수행하는 비율이다. 단순 방문 횟수가 아니라 “누가 시작했고, 언제 돌아왔으며, 어떤 행동을 돌아옴으로 인정하는가”를 고정해야 한다.

세 개념은 경쟁 관계가 아니다. funnel은 한 흐름 안의 단계 차이를 보고, cohort는 비교할 집단을 고정하며, retention은 그 집단을 시간축으로 추적한다. 실제 분석에서는 “2026-W24에 생성된 신규 workspace cohort가 초대 funnel을 통과한 뒤 2주차에도 공동 작업을 했는가”처럼 함께 사용한다.

2. 선행 방식의 한계 - 왜 Funnel과 Cohort가 필요한가

섹션 제목: “2. 선행 방식의 한계 - 왜 Funnel과 Cohort가 필요한가”

가장 쉬운 분석은 전체 사용자 수, 전체 클릭 수, 전체 가입 수를 보는 것이다. 하지만 단일 count와 전체 평균은 세 가지 정보를 잃는다.

  1. 순서: invite_created 1,000건과 invite_accepted 400건이 있어도 같은 초대가 생성된 뒤 수락된 것인지 알 수 없다.
  2. 구성: 신규 사용자의 activation은 떨어졌는데 기존 사용자의 반복 사용이 늘면 전체 평균은 그대로일 수 있다.
  3. 시간: 어제 시작한 cohort와 30일 전에 시작한 cohort를 같은 30일 retention 표에 넣으면 최근 cohort는 아직 결과를 낼 기회가 없다.

Product analytics가 event-level 사용자 행동을 추적하는 이유는 이 한계를 줄이기 위해서다. Amplitude는 product analytics를 engagement, drop-off, retention driver를 이해하는 활동으로 설명한다. Product Engineer에게 이는 전체 count를 보고 끝내지 않고 행동 흐름, 비교 집단, 관찰 시간을 함께 고정하라는 뜻이다.

핵심 철학은 “좋아 보이는 비율을 찾는 것”이 아니라 같은 질문에 같은 집합이 나오도록 측정 계약을 만드는 것이다. funnel과 cohort는 원인을 확정하지 않지만, 원인을 찾을 수 있는 비교 단위로 문제를 좁힌다.

3. 비율을 만드는 다섯 가지 계약

섹션 제목: “3. 비율을 만드는 다섯 가지 계약”

비율은 보통 분자 / 분모로 쓰지만, 제품 지표에는 최소 다섯 가지 계약이 필요하다.

3.1 Denominator - 누가 기회를 가졌는가

섹션 제목: “3.1 Denominator - 누가 기회를 가졌는가”

Denominator(디노미네이터, 분모) 는 지표가 묻는 행동을 할 자격과 기회를 가진 분석 단위의 집합이다. 모든 사용자나 모든 이벤트를 무조건 분모로 두는 값이 아니다.

초대 생성 지표의 분모를 비교해보자.

분모실제로 묻는 질문
모든 로그인 사용자로그인한 사람 중 초대를 만든 비율은 얼마인가
초대 권한이 있는 workspace admin초대할 자격이 있는 admin 중 누가 초대했는가
초대 모달을 연 unique workspace초대 UI를 본 workspace 중 생성에 성공한 비율은 얼마인가
해당 주에 생성된 unique workspace새 workspace 중 7일 안에 협업 상태에 도달한 비율은 얼마인가

네 값은 모두 계산 가능하지만 서로 다른 제품 질문이다. 분모는 숫자를 계산하기 전에 “누가 실제 기회를 가졌는가”로 읽는다. 권한이 없는 member를 초대 생성률 분모에 넣으면 UI(User Interface, 사용자 인터페이스) 문제 없이도 비율이 낮아진다.

3.2 Numerator와 ordered qualification - 무엇을 성공으로 셀 것인가

섹션 제목: “3.2 Numerator와 ordered qualification - 무엇을 성공으로 셀 것인가”

Numerator(뉴머레이터, 분자) 는 분모 집합 중 성공 조건을 충족한 분석 단위다. funnel의 성공은 이벤트 존재만이 아니라 순서와 연결 조건까지 포함한다.

qualifies(unit) =
step_1.timestamp <= step_2.timestamp <= step_3.timestamp
AND 모든 단계의 join identity가 연결됨
AND 마지막 단계가 지정 window 안에 발생함

예를 들어 어떤 workspace에 invite_accepted가 있었더라도 분석 대상 modal에서 생성한 invite_id와 연결되지 않으면 그 modal funnel의 성공으로 세지 않는다. 과거 초대의 늦은 수락을 새 모달의 성공으로 잘못 붙이는 것을 막기 위해서다.

3.3 Identity와 unique unit - 무엇을 한 개로 셀 것인가

섹션 제목: “3.3 Identity와 unique unit - 무엇을 한 개로 셀 것인가”

Identity(아이덴티티, 식별 기준) 는 여러 이벤트가 같은 사용자·workspace·초대·시도에 속한다는 것을 연결하는 키다. Unique unit(고유 집계 단위) 은 최종 비율에서 한 번만 세는 대상을 뜻한다.

  • 사람의 행동을 묻는다면 user_id가 적합할 수 있다.
  • 협업 상태의 변화를 묻는다면 workspace_id가 더 적합할 수 있다.
  • 초대 한 건의 생애를 묻는다면 invite_id가 필요하다.
  • 모달을 열고 제출한 한 번의 시도를 진단한다면 flow_idmodal_view_id가 필요하다.

한 admin이 같은 workspace에서 모달을 세 번 열고 초대 다섯 건을 만들었을 때 unique user는 1, unique workspace는 1, modal view는 3, invitation은 5다. L13 공통 초대 지표는 workspace를 한 번 세지만, 반복 시도 마찰을 진단하는 별도 지표는 modal view를 세어야 한다. “초대율”이라는 이름만으로는 어떤 값인지 알 수 없다.

3.4 Deduplication - 재시도와 중복 전송을 어떻게 제거할 것인가

섹션 제목: “3.4 Deduplication - 재시도와 중복 전송을 어떻게 제거할 것인가”

Deduplication(디듀플리케이션, 중복 제거) 은 같은 논리적 사건이 재시도나 다중 수집 경로 때문에 여러 번 기록되어도 한 번만 세는 규칙이다. 이벤트 row에 단순히 DISTINCT user_id를 적용하는 것과는 다르다.

  • canonical invite_createdinvite_accepted는 producer가 발급한 필수 domain_event_id로만 ingestion 중복을 제거한다.
  • 두 canonical event에 domain_event_id가 없으면 event_idinvite_id로 추정하지 않고 quarantine(격리 영역) 으로 보내 원인을 교정할 때까지 지표 입력에서 제외한다.
  • invite_id는 중복 제거 키가 아니라 created와 accepted를 잇는 lifecycle join key이자 unique invitation 집계 단위다.
  • client의 모달 노출은 새로 열릴 때 발급한 modal_view_id별 한 번으로 센다.

네트워크 재시도로 같은 domain_event_idinvite_created가 3번 도착하면 ingestion에서는 한 사업 사건으로 줄인다. 반대로 domain_event_id가 없는 세 row는 invite_id가 같아 보여도 복구 추정하지 않고 quarantine한다. 정제된 event에서 invite_id로 invitation lifecycle을 연결한 뒤, invite_creation_rate에서는 유효한 초대가 다섯 건이어도 unique workspace 하나로 세는 metric uniqueness(지표 고유성) 를 적용한다. ingestion dedup, invitation join, workspace-level uniqueness를 섞으면 처리량과 전환을 모두 왜곡한다.

3.5 Window - 얼마 동안 성공 기회를 줄 것인가

섹션 제목: “3.5 Window - 얼마 동안 성공 기회를 줄 것인가”

Window(윈도우, 관찰 기간) 는 시작 사건 뒤 성공 사건을 기다리는 시간 범위다. 7일 내라면 시작 시각, 종료 경계 포함 여부, 시간대를 함께 정한다.

이 문서의 7일 지표는 다음처럼 고정한다.

start <= success_timestamp < start + 7 * 24 hours
timestamp 기준: UTC(Coordinated Universal Time, 협정 세계시) event time
cohort 표시 기준: 제품의 합의된 business timezone

24시간 뒤에도 가치가 생기는 제품에 10분 window를 쓰면 정상 사용자를 이탈로 오해한다. 반대로 5분 안에 끝나야 하는 결제 제출에 30일 window를 쓰면 서로 다른 시도가 연결될 수 있다. window는 보고서 옵션이 아니라 제품의 자연스러운 사용 주기에 대한 가정이다.

초대 사례는 다음 세 이벤트 흐름을 canonical contract로 사용한다.

invite_modal_opened -> invite_created -> invite_accepted
invite_modal_opened -> invite_modal_closed

invite_modal_closed는 성공 단계를 하나 더 만드는 이벤트가 아니라 생성 window를 관찰하기 위한 lifecycle helper다. 중간의 이메일 입력, 제출 클릭, 실패 이벤트는 진단에는 유용하지만 핵심 세 이벤트의 대체물이 아니다. invite_createdinvite_accepted는 제품 상태의 성공적인 변화를 나타낸다.

이벤트Trigger(발생 조건)연결 identityingestion dedup / metric unique 단위
invite_modal_opened초대 권한이 있는 사용자의 화면에서 모달이 실제로 보이고 상호작용 가능한 상태가 된 시점actor_user_id, workspace_id, 한 번의 진입인 flow_id, 한 노출인 modal_view_idclient 수집 중복은 (event, modal_view_id)로 제거한다. 공통 지표에서는 cohort 기간의 workspace_id를 한 번 센다
invite_modal_closed열린 모달이 닫기·취소·route 이동·생성 성공 뒤 dismissal로 visible 상태를 끝낸 시점open과 같은 actor_user_id, workspace_id, flow_id, modal_view_id, closed_atclient 수집 중복은 (event, modal_view_id)로 제거한다. close가 유실되면 지표 계산에서 opened_at + 30분을 종료 시각으로 쓴다
invite_created서버 트랜잭션에서 pending invitation이 영속화되고 전달 job/outbox가 같은 성공 경계에 등록된 뒤필수 domain_event_id, invite_id, workspace_id, inviter인 actor_user_id; UI modal 경로에서만 flow_id, modal_view_id가 조건부 필수필수 domain_event_id로만 ingestion dedup한다. 누락 row는 quarantine한다. invite_id는 join·unique invitation 단위이고 공통 지표는 workspace_id를 한 번 센다
invite_acceptedinvitation이 pending -> accepted로 전이되고 해당 workspace membership 생성이 커밋된 뒤domain_event_id, invite_id, workspace_id, membership_id, accepting actor필수 domain_event_id로만 ingestion dedup한다. 누락 row는 quarantine한다. invite_id는 join·unique invitation 단위이고 공통 지표는 workspace_id를 한 번 센다

invite_created를 제출 버튼 클릭 시점에 보내면 validation 실패와 seat limit 차단까지 성공으로 섞인다. invite_accepted를 링크 클릭 시점에 보내면 만료 토큰이나 membership 생성 실패도 수락으로 보인다. 상태 변화 이벤트의 trigger는 UI 의도가 아니라 성공적으로 커밋된 도메인 상태에 둔다.

Canonical funnel은 세 이벤트로 유지하되 원인 진단이 필요하면 invite_email_entered를 선택적으로 추가할 수 있다. 이 이벤트는 해당 flow_id에서 사용자가 초대 이메일 입력을 시작한 최초 시점에 한 번 기록하고, 전송 중복은 (event, flow_id)로 제거한다. opened -> email_entered가 낮으면 초대 대상 이해, copy, trust 문제를 먼저 의심하고, email_entered -> created가 낮으면 validation, permission, seat limit, API 실패를 먼저 본다. 이 진단 이벤트는 세 공통 지표의 분모나 성공 조건을 바꾸지 않는다.

5. 세 초대 지표를 혼동하지 않는다

섹션 제목: “5. 세 초대 지표를 혼동하지 않는다”

같은 세 이벤트를 사용해도 제품 질문에 따라 분모와 unique 단위가 달라진다. 다음 세 지표는 이름을 바꾸어 부를 수 있는 동의어가 아니다.

이 절에서 first qualifying open(분석 대상 최초 모달 노출) 은 분석 기간 [start_at, end_at) 안에서 client event 중복을 제거한 뒤, 권한 있는 actor에게 실제로 표시되었다는 invite_modal_opened 계약을 만족한 해당 workspace의 가장 이른 open이다. 분석 기간 전 open이나 렌더링 실패, 권한 없는 actor의 event는 first open 후보가 아니다. 아래의 “최초 modal open”은 모두 이 시점을 뜻한다.

5.1 invite_creation_rate - 모달 시도가 생성 성공으로 이어졌는가

섹션 제목: “5.1 invite_creation_rate - 모달 시도가 생성 성공으로 이어졌는가”

invite_creation_rate(초대 생성률) 는 초대 모달을 실제로 본 workspace 중 적어도 한 건의 invitation 생성에 성공한 workspace 비율이다. UI 시작 이후 validation, 권한, seat limit, API(Application Programming Interface, 프로그램 간 호출 계약) 성공까지의 마찰을 본다.

cohort:
분석 기간에 first qualifying invite_modal_opened가 발생한 workspace
denominator:
invite_modal_opened가 있는 unique workspace_id 수
numerator:
first qualifying open과 같은 flow_id에서
opened_at <= invite_created.occurred_at < creation_window_end를 만족하고
domain_event_id로 dedup된 invite_created가 1건 이상 발생한
unique workspace_id 수
window:
같은 flow_id의 invite_modal_closed.closed_at가 있으면
creation_window_end = min(closed_at, opened_at + 30분)
close event가 유실되어 closed_at가 없으면
creation_window_end = opened_at + 30분
dedup:
modal open/close는 modal_view_id/flow_id 계약으로 정제하고,
invite_created는 필수 domain_event_id로만 ingestion dedup한다.
denominator와 numerator는 workspace_id별 최대 1회

유효한 closed_at은 first open과 같은 flow_id에 속하고 opened_at <= closed_at을 만족해야 한다. 닫힘 시각이 open보다 빠르거나 다른 flow에 속하면 데이터 품질 실패로 기록하고 유효한 close가 없는 것으로 보아 opened_at + 30분 fallback을 적용한다. close가 정상적으로 8분 뒤 기록되었다면 8분 뒤 생성은 실패이고, close가 유실되었다면 30분까지 기다린다.

예를 들어 modal-open unique workspace가 1,000개이고, 그중 620개에서 각 workspace의 creation_window_end 전에 초대가 하나 이상 생성되었다면 invite_creation_rate = 620 / 1,000 = 62%다. 한 workspace가 모달을 세 번 열고 다섯 명을 초대해도 이 지표의 분자는 1이다. 반복 시도 마찰을 보려면 별도로 successful modal views / unique modal views, 초대 물량을 보려면 created invitations / successful workspace를 계산한다. 30분은 보편 법칙이 아니라 close 유실 시 사용하는 이 예제의 fallback 계약이며, 바꿀 때는 이전·이후 값을 같은 정의로 다시 계산한다.

5.2 7-day accepted-from-modal conversion - 모달 시작이 수락 결과로 이어졌는가

섹션 제목: “5.2 7-day accepted-from-modal conversion - 모달 시작이 수락 결과로 이어졌는가”

7-day accepted-from-modal conversion(7일 모달 시작 대비 초대 수락 전환율) 은 모달을 실제로 본 workspace 중, first qualifying open의 flow에서 생성된 초대가 7일 안에 하나 이상 수락된 workspace 비율이다. 이 문서에서는 모호한 invite_accepted rate 대신 이 이름과 계약을 사용한다.

cohort:
분석 기간에 first qualifying invite_modal_opened가 발생한 workspace
denominator:
invite_modal_opened가 있는 unique workspace_id 수
numerator:
first qualifying open과 같은 flow_id이며 invite_creation_rate의
creation window를 통과한 invite_created가 발생하고,
그 created 시각 이후 같은 invite_id의 invite_accepted가
first qualifying open 후 7일 안에 발생한 unique workspace_id 수
window:
first qualifying open 시점부터 7 * 24시간
dedup:
created/accepted는 각각 필수 domain_event_id로 ingestion dedup하고,
누락 row는 quarantine. modal -> created는 flow_id,
created -> accepted는 invite_id로 join한 뒤 workspace_id별 최대 1회

같은 1,000개 modal-open workspace 중 620개가 초대를 생성하고, 7일 안에 수락까지 이어진 workspace가 280개라면 다음 두 값이 나온다.

  • 전체 modal 시작 대비 수락 outcome: 280 / 1,000 = 28%
  • 생성 성공 이후 수락 단계 전환: 280 / 620 = 45.2%

두 번째 값은 funnel의 created -> accepted 단계 전환율이고 첫 번째 값과 분모가 다르다. 둘 다 유용하지만 이름 없이 수락률이라고 부르면 안 된다.

5.3 new workspace 7-day activation_rate - 새 workspace가 협업 상태에 도달했는가

섹션 제목: “5.3 new workspace 7-day activation_rate - 새 workspace가 협업 상태에 도달했는가”

new workspace 7-day activation_rate(새 workspace 7일 활성화율) 는 eligible new workspace 중 생성 후 7일 안에 초대를 만들고 최소 한 명이 수락한 workspace의 비율이다. 정상적인 UI, API, integration 등 어떤 entry point로 시작했든 인정하며 invite_modal_openedflow_id를 요구하지 않는다. 시작 cohort가 modal-open workspace가 아니라 모든 eligible new workspace이므로 앞의 두 지표와 제품 질문이 다르다.

cohort:
enrollment 기간 [start_at, end_at)에 production에서 최초 workspace_created가
발생했고, 생성자가 admin인 신규 workspace
denominator:
생성 시점에 is_internal = false, is_test = false, is_automated = false인
unique workspace_id 수. 결과를 보기 전에 정한 region·plan 조건이 있다면
같은 시점의 값으로 적용
numerator:
정상 entry point에서 workspace 생성 이후 invite_created가 발생하고,
그 created와 같은 invite_id의 invite_accepted가 workspace 생성 후
7일 안에 발생한 unique workspace_id 수. modal event와 flow_id는 요구하지 않음
window:
workspace_created 시점부터 7 * 24시간
dedup:
created/accepted는 각각 필수 domain_event_id로 ingestion dedup하고 누락은 quarantine.
invite_id로 lifecycle을 join한 뒤 workspace_id별 최대 1회

적격 조건은 outcome을 보기 전에 고정하고 모든 cohort에 동일하게 적용한다. 결과가 나쁜 workspace를 사후에 “테스트 같음”이나 “비정상 사용”으로 제외하면 selection bias가 생긴다. 7일 window가 끝나지 않은 eligible workspace는 실패로 세지 않고 성숙할 때까지 보류한다.

한 주에 신규 eligible workspace가 500개이고, 7일 안에 생성된 초대 중 하나가 수락된 workspace가 90개라면 activation_rate = 90 / 500 = 18%다. 한 workspace가 모달을 네 번 열고 열 명을 초대해도 분자에서는 workspace 1개다.

이 activation은 협업 가치에 가까운 proxy(프록시, 대신 관찰하는 행동 신호) 다. 실제 outcome이 “동료와 첫 공동 프로젝트 완료”라면 그 이벤트는 더 강한 activation 정의나 후속 outcome 지표로 별도 관찰해야 한다. 초대 수락 자체를 최종 사용자 가치라고 단정하지 않는다.

5.4 같은 로그가 세 지표에서 다르게 세어지는 예

섹션 제목: “5.4 같은 로그가 세 지표에서 다르게 세어지는 예”
대상modal viewcreated invite7일 내 accepted세 지표에서의 결과
workspace Am1, m2m1에서 i1 생성i1 수락creation: A 성공 1회, accepted/modal: A 성공 1회, activation: A 성공 1회
workspace Bm3i2, i3 생성둘 다 미수락creation: B 성공 1회, accepted/modal: B 실패, activation: B 실패
workspace C모달 없음, API로 i4 생성i4 생성i4 수락modal 기반 두 지표 분모 밖, activation: C 성공

이 반례는 activation_rate에 modal event를 강제로 요구하면 안 되는 이유도 보여준다. API나 다른 정상 entry point로 초대를 만든 workspace를 제품 활성화 실패로 분류하게 되기 때문이다. 반대로 modal UX의 성과를 볼 때는 모달 없는 API 초대를 분모나 분자에 넣지 않는다.

Funnel은 단계마다 도달률(overall conversion)직전 단계 전환율(step conversion) 을 구분한다.

단계unique 단위도달 수첫 단계 대비 도달률직전 단계 전환율
invite_modal_openedworkspace1,000100%-
invite_createdworkspace with at least one created invite62062%62%
invite_accepted within 7 daysworkspace with at least one accepted invite28028%45.2%

created -> accepted에서 340개 workspace가 줄었다고 해서 원인이 초대 화면이라고 단정할 수는 없다. email delivery, token expiry, 초대받은 사람의 onboarding, 조직 정책처럼 actor와 시스템 경계가 달라진다. Funnel은 “어디가 문제인가”를 좁혀주지만 원인을 확정하지 않는다.

구간먼저 묻는 질문가능한 원인
opened -> created초대 의도를 생성 성공으로 바꾸는가대상 이해 부족, validation, permission, seat limit, API error
created -> accepted상대가 초대를 받고 합류할 수 있는가email delivery, token expiry, trust, onboarding friction

시나리오

가입자는 늘었는데 첫 프로젝트 생성이 줄었다

마케팅 캠페인 이후 signup_completed 이벤트는 증가했지만 project_created 이벤트는 줄었다. 전체 활성 사용자는 아직 큰 변화가 없다.

이 상황에서 어떤 funnel 단계와 cohort를 먼저 분리해서 볼 것인가?

먼저 유입 주차와 source로 cohort를 고정하고, signup_completed -> workspace_created -> first_project_created의 전체 도달률과 단계 전환율을 비교한다. 신규 유입 구성이 달라졌는지, 기존 cohort의 반복 사용이 전체 활성 사용자 수를 떠받치고 있는지 분리해야 한다.

7. Worked example - 작은 이벤트 로그를 손으로 계산한다

섹션 제목: “7. Worked example - 작은 이벤트 로그를 손으로 계산한다”

다음 이벤트 로그로 signup -> workspace -> first project funnel과 day 7 retention을 계산해보자. 이 예제는 기존의 작은 데이터셋을 유지하되, 분모와 결과까지 명시한다.

user_id | cohort_week | day | event
u1 | 2026-W24 | 0 | signup_completed
u1 | 2026-W24 | 0 | workspace_created
u1 | 2026-W24 | 1 | first_project_created
u1 | 2026-W24 | 7 | project_opened
u2 | 2026-W24 | 0 | signup_completed
u2 | 2026-W24 | 0 | workspace_created
u3 | 2026-W24 | 0 | signup_completed
u4 | 2026-W25 | 0 | signup_completed
u4 | 2026-W25 | 0 | workspace_created
u4 | 2026-W25 | 0 | first_project_created
u5 | 2026-W25 | 0 | signup_completed
u5 | 2026-W25 | 7 | project_opened

분석 계약은 다음과 같다.

  1. cohort는 signup_completed가 발생한 주차다.
  2. unique unit은 user_id이며 각 단계는 사용자별 최대 한 번 센다.
  3. funnel은 signup 뒤에 발생한 workspace와 first project만 순서대로 인정한다.
  4. day 7 retention의 return action은 정확히 가입 7일째의 project_opened다.
cohortsignup 분모workspace 도달first project 도달workspace step 전환project step 전환exact day 7 retention
2026-W243212/3 = 66.7%1/2 = 50%1/3 = 33.3%
2026-W252111/2 = 50%1/1 = 100%1/2 = 50%

W25의 project step 전환율 100%만 보면 onboarding이 좋아 보인다. 그러나 표본은 workspace에 도달한 사용자 1명뿐이고, signup 대비 first project 도달률은 50%다. 작은 분모에서 나온 비율은 방향을 탐색하는 신호일 수는 있어도 안정적인 결론은 아니다.

또한 W25의 u5는 day 7에 project를 열었지만 workspace_createdfirst_project_created가 없다. 다음 두 설명이 모두 가능하다.

  • Instrumentation(계측) 누락, 즉 행동을 이벤트로 기록하는 코드가 빠져 중간 이벤트가 남지 않았다.
  • u5는 초대받은 member여서 workspace와 첫 프로젝트를 직접 만들 필요가 없었다.

첫 설명이면 데이터 품질 문제이고, 두 번째면 funnel 모집단 정의가 잘못된 것이다. role, source, tracking QA를 확인하지 않고 “중간 단계를 건너뛴 이상 사용자”로 제거하면 실제 협업 사용자를 분석에서 잃는다.

8. Cohort는 비교 가능한 집단을 만든다

섹션 제목: “8. Cohort는 비교 가능한 집단을 만든다”

Cohort의 조건은 분석 전에 고정되어야 한다. 결과를 본 뒤 retention이 높은 사용자의 공통 행동만 골라 cohort를 만들면 선택 편향이 생기기 쉽다.

Cohort를 나누는 기준

시간 cohort

같은 기간에 시작한 사용자를 비교한다.

예: 2026년 6월 첫째 주 가입자

행동 cohort

특정 행동을 한 사용자와 하지 않은 사용자를 비교한다.

예: 첫날 팀원을 초대한 사용자 vs 초대하지 않은 사용자

속성 cohort

role, plan, company size, source 같은 property로 나눈다.

예: admin 사용자와 member 사용자

실험 cohort

미리 정한 variant 배정 단위로 결과를 비교한다.

예: onboarding_v2 treatment vs control

8.1 시간 cohort는 제품 변화와 유입 변화를 구분한다

섹션 제목: “8.1 시간 cohort는 제품 변화와 유입 변화를 구분한다”

전체 retention이 40%로 같더라도 내부 구성이 다를 수 있다.

기간신규 cohort retention기존 cohort retention전체 retention
변경 전45%35%40%
변경 후30%50%40%

전체값만 보면 변화가 없다. 하지만 신규 사용자는 악화했고 기존 사용자는 개선했다. 이를 평균의 함정으로만 외우기보다 “비교 가능한 시작점을 섞었기 때문”이라고 이해해야 한다.

8.2 행동 cohort는 인과 집단이 아니다

섹션 제목: “8.2 행동 cohort는 인과 집단이 아니다”

첫날 팀원을 초대한 사용자의 4주 retention이 60%, 초대하지 않은 사용자가 25%라고 하자. 이 차이만으로 “초대를 강제하면 retention이 35%p 오른다”고 결론 내릴 수 없다. 원래 협업 의도가 강한 사용자가 초대도 하고 돌아오기도 했을 수 있다.

행동 cohort는 어떤 행동이 장기 가치와 함께 나타나는지 탐색하는 데 적합하다. 그 행동이 원인인지 검증하려면 사전 특성이 비슷한 집단 비교나 실험 설계가 필요하며, 다음 문서의 범위로 이어진다.

8.3 속성 cohort는 작은 분모와 privacy 경계를 확인한다

섹션 제목: “8.3 속성 cohort는 작은 분모와 privacy 경계를 확인한다”

enterprise admin cohort의 retention만 떨어졌다면 권한·초대·SSO(Single Sign-On, 통합 로그인) 흐름을 먼저 볼 수 있다. 그러나 회사, role, 기기를 계속 쪼개면 분모가 작아지고 우연한 극값이 늘어난다. 분석에 필요하지 않은 민감한 속성을 수집해 cohort를 만드는 것도 피해야 한다.

9. Retention은 반복 가치의 신호다

섹션 제목: “9. Retention은 반복 가치의 신호다”

Retention은 “다시 왔다”가 아니라 시작 집단이 가치 행동을 다시 했다를 측정한다. 따라서 acquisition event, return action, 시간 bucket 세 가지를 먼저 정한다.

  • Acquisition event(획득 사건): cohort 시계를 시작하는 사건. 예: signup, workspace 생성, 첫 유료 전환.
  • Return action(복귀 행동): 돌아옴으로 인정할 가치 행동. 예: 공동 문서 편집, 성공한 API 호출.
  • Time bucket(시간 구간): day, week, month처럼 돌아옴을 배치할 시간 단위.
제품 유형약한 retention 이벤트강한 retention 이벤트
협업 도구page_viewcomment_created, document_shared
개발자 도구dashboard_openedapi_call_succeeded, deployment_created
분석 도구report_viewedsaved_chart_shared, query_run
결제/권한 기능billing_page_viewedpremium_feature_used

약한 이벤트가 항상 쓸모없는 것은 아니다. discovery와 navigation 문제를 진단할 수 있다. 다만 제품의 반복 가치를 주장하는 primary retention event로 쓰기에는 부족하다.

9.1 Retention 정의는 이름보다 수식을 우선한다

섹션 제목: “9.1 Retention 정의는 이름보다 수식을 우선한다”

도구마다 rolling과 unbounded라는 이름을 다르게 쓰기도 하므로, 대시보드 이름만 공유하지 말고 event와 window를 적는다.

방식분자 조건적합한 질문
Exact N-day retention시작 후 정확히 N번째 day bucket에 return action매일 사용이 자연스러운 제품에서 특정 날짜 복귀를 볼 때
Bounded retentionday N부터 day M 사이에 한 번 이상 return action주기 변동을 허용한 7일 구간 복귀를 볼 때
Unbounded/Rolling retentionday N 또는 그 이후에 한 번 이상 return action정확한 날짜보다 장기 재방문 여부가 중요할 때
Usage frequency기간 안의 활성 day 수나 반복 횟수가 기준 이상주 3회 사용처럼 가치 빈도가 중요한 제품일 때

가입 후 day 7에는 오지 않았지만 day 8에 돌아온 사용자는 exact day 7 retention에서는 실패다. day 7~13 bounded retention과 day 7 이후 unbounded retention에서는 성공일 수 있다. 같은 로그가 다른 답을 내는 이유는 계산 오류가 아니라 질문이 다르기 때문이다.

9.2 Retention curve는 높이와 모양을 함께 본다

섹션 제목: “9.2 Retention curve는 높이와 모양을 함께 본다”

Retention curve(리텐션 곡선) 는 시작 cohort 중 return action을 한 비율을 시간에 따라 그린 값이다.

cohort size: 1,000 users
day 1 active: 420 -> 42%
day 7 active: 250 -> 25%
day 30 active: 180 -> 18%
day 60 active: 175 -> 17.5%

초기에 급락하면 첫 가치 전달이나 유입 적합성을 의심한다. day 30 이후 18% 부근에서 완만해지면 적어도 일부 집단이 반복 가치를 얻는다는 가설을 세울 수 있다. 곡선이 평평해졌다고 product-market fit을 자동으로 증명하는 것은 아니다. return action의 강도, 유료 상태, cohort 구성, 이벤트 누락을 함께 확인해야 한다.

10. Activation, Conversion, Retention을 분리한다

섹션 제목: “10. Activation, Conversion, Retention을 분리한다”

세 지표는 서로 다른 시간축의 질문에 답한다.

지표묻는 질문초대 사례의 정확한 예
Activation사용자가 초기에 첫 가치 또는 그 proxy에 도달했는가신규 workspace 중 생성 후 7일 안에 초대 생성과 수락을 만든 unique workspace 비율
Conversion대상이 정의된 목표 전환을 완료했는가모달을 연 unique workspace 중 연결된 초대가 7일 안에 수락된 비율
Retention시작 cohort가 시간이 지나도 가치 행동을 반복하는가활성화된 workspace 중 4주차에 공동 편집을 다시 한 unique workspace 비율

Activation이 낮으면 onboarding과 첫 가치 전달을 본다. Conversion이 낮으면 해당 단계의 권한, trust, form UX, 시스템 오류를 본다. Retention이 낮으면 반복 가치, collaboration loop, notification, performance, reliability를 본다.

퀴즈

signup_completed가 증가했는데 week 1 retention이 떨어졌다면 어떤 해석이 가능한가?

힌트: 유입량과 제품 가치 경험은 같은 말이 아니다.

정답 보기

새 유입이 늘었지만 핵심 가치를 경험하지 못하는 사용자가 많아졌을 수 있다. 유입 source별 시간 cohort, activation funnel, week 1 return action의 정의와 이벤트 품질을 분리해서 봐야 한다.

11.1 Censoring - 아직 기다릴 시간이 없었던 cohort

섹션 제목: “11.1 Censoring - 아직 기다릴 시간이 없었던 cohort”

Censoring(센서링, 관찰 중단) 은 관찰 기간이 부족해 최종 결과를 아직 알 수 없는 상태다. 특히 최근 cohort의 오른쪽 시간이 잘리는 right censoring(우측 센서링) 이 자주 발생한다.

7월 14일에 7일 activation을 계산한다고 하자.

workspace 생성일7일 window 종료7월 14일 기준 포함 가능 여부
7월 5일7월 12일완전히 성숙했으므로 포함 가능
7월 10일7월 17일아직 3일이 남아 제외하거나 미성숙 cohort로 표시
7월 14일7월 21일당일 성과만 보고 7일 실패로 세면 안 됨

최근 workspace를 모두 분모에 넣고 아직 발생하지 않은 수락을 실패로 처리하면 activation이 인위적으로 하락한다. 해결은 결과를 낼 시간이 지난 matured cohort(성숙 cohort) 만 비교하거나, 미성숙 값을 별도 provisional 지표로 표시하는 것이다.

11.2 Selection bias - 관찰된 집단이 비교 대상을 대표하지 않는 문제

섹션 제목: “11.2 Selection bias - 관찰된 집단이 비교 대상을 대표하지 않는 문제”

Selection bias(선택 편향) 는 분석에 포함된 집단을 고르는 과정이 결과와 연관되어 비교가 왜곡되는 현상이다. 행동 cohort는 특히 주의한다.

예를 들어 초대 모달을 연 workspace만 분석하면 초대 기능을 발견하지 못한 eligible workspace는 분모에서 사라진다. 이 분석은 modal UX의 생성 성공률에는 맞지만, 전체 eligible admin workspace의 초대 adoption을 설명하지 못한다. 질문에 따라 분모를 바꿔야지 한 비율을 전체 제품 성과로 확대하면 안 된다.

Survivor bias(생존자 편향) 는 selection bias의 한 형태로, 이미 뒤 단계까지 살아남은 대상만 보고 초기 이탈을 놓치는 문제다. invite_created workspace만 대상으로 수락률을 보면 modal을 열고 생성에 실패한 380개 workspace는 보이지 않는다.

11.3 구성 변화 - 전체 평균의 방향이 뒤집히는 반례

섹션 제목: “11.3 구성 변화 - 전체 평균의 방향이 뒤집히는 반례”

두 source 모두 activation이 개선되어도 전체 activation이 떨어질 수 있다.

source변경 전변경 후
추천 유입80/100 = 80%180/200 = 90%
광고 유입20/100 = 20%90/300 = 30%
전체100/200 = 50%270/500 = 54%

위 표에서는 전체도 올랐다. 이제 변경 후 광고 유입이 800명으로 늘었다고 바꾸면 180 + 240 = 420, 분모는 1,000, 전체는 42%가 된다. 각 source 안에서는 80% -> 90%, 20% -> 30%로 개선했지만 저전환 source 비중이 커져 전체값은 50% -> 42%로 하락한다.

이 현상은 Simpson’s paradox(심슨의 역설) 의 전형적인 모양이다. 전체와 세부 cohort 중 하나만 진실인 것이 아니라 구성비가 질문의 일부다. source별 제품 경험과 acquisition mix를 각각 판단해야 한다.

12. 실패 신호에서 원인을 좁힌다

섹션 제목: “12. 실패 신호에서 원인을 좁힌다”
관찰되는 실패 신호의미할 수 있는 문제먼저 확인할 계약
이벤트 row는 늘었는데 unique invitation 수는 그대로다재시도나 이중 수집이 증가했다필수 domain_event_id ingestion dedup과 누락 quarantine
opened -> created가 갑자기 하락했다UI 마찰 또는 서버 생성 실패가 늘었다modal eligibility, 30분 window, error cohort
created -> accepted만 특정 domain에서 하락했다전달·신뢰·토큰 만료 문제가 있을 수 있다invite_id 연결, email domain cohort, expiry
최신 주차 activation만 낮다실제 악화가 아니라 right censoring일 수 있다7일 window가 끝난 matured cohort 여부
전체 retention은 같지만 신규 cohort가 하락한다기존 사용자의 개선이 신규 이탈을 가렸다acquisition week cohort
행동 cohort의 retention 차이가 매우 크다행동이 원인이 아니라 기존 의도 차이일 수 있다selection bias, 사전 특성, 실험 필요성
client opened 수만 특정 브라우저에서 줄었다제품 행동보다 수집 차단·전송 실패일 수 있다client/server event coverage, tracking QA(Quality Assurance, 품질 보증)
accepted가 created보다 먼저 보인다clock, late arrival, join key, 과거 초대 연결 문제다event time, ingestion time, invite_id

Late arrival(지연 도착) 은 실제 사건은 window 안에 일어났지만 분석 저장소에 늦게 들어오는 경우다. event time 기준으로 window를 계산하고, 데이터가 안정되는 지연 허용 기간을 정해야 한다. ingestion time으로만 계산하면 어제 수락한 이벤트가 오늘 도착했을 때 다른 cohort에 들어갈 수 있다.

분석 루틴은 대시보드 클릭 순서가 아니라 잘못된 결론을 줄이는 검증 순서다.

  1. 제품 질문을 activation, conversion, retention 중 하나로 좁힌다.
  2. cohort와 eligibility를 문장으로 쓴다.
  3. denominator, numerator, unique unit, window, dedup을 명세한다.
  4. 이벤트 trigger와 join identity가 tracking plan과 일치하는지 확인한다.
  5. overall conversion과 step conversion을 함께 계산한다.
  6. time, role, plan, source, device, experiment variant 중 원인 가설과 관련된 cohort만 비교한다.
  7. censoring, selection bias, 작은 분모, late arrival로 설명되는 변화인지 확인한다.
  8. error rate, performance, support ticket 같은 guardrail과 정성 증거를 함께 본다.
  9. 결과를 다음 UX Flow, 시스템 병목, tracking 수정, 실험 가설 중 하나로 연결한다.

Funnel/Cohort/Retention 해석 체크

  • 분석 질문이 activation, conversion, retention 중 무엇인지 구분했다
  • cohort, denominator, numerator, window를 한 문장으로 재현할 수 있다
  • funnel 단계마다 trigger와 join identity가 명확하다
  • event row가 아니라 질문에 맞는 user, workspace, invite, modal view 단위로 중복을 제거했다
  • return action이 단순 방문이 아니라 제품 가치 행동이다
  • 최근 cohort가 결과를 낼 시간을 모두 가졌는지 확인했다
  • 행동 cohort의 상관관계를 인과 효과로 해석하지 않았다
  • 평균 지표 뒤에 숨어 있는 특정 cohort 악화를 확인했다
  • 지표 변화에서 바로 결론을 내리지 않고 다음 UX/시스템 가설로 연결했다

funnel과 cohort는 제품 상태를 읽는 방법이다. 다음 단계에서는 관찰된 차이가 우연인지, 특정 release나 experiment 때문인지 판단해야 한다.

  • Experimentation & Feature Flags: cohort 차이와 행동 상관관계를 실험 설계와 rollout 판단으로 연결한다.
  • Frontend Product Quality & RUM: 성능과 접근성 같은 UX 품질이 funnel과 retention에 미치는 영향을 본다.
  • Privacy, Consent & Product Data Governance: cohort와 event property가 개인정보 경계를 넘지 않도록 관리한다.
  • Funnel analysis
  • Cohort analysis
  • Activation metric
  • Conversion rate
  • Retention curve
  • Return action
  • Denominator and eligibility
  • Observation window
  • Right censoring
  • Selection bias
  • Survivor bias
  • Simpson’s paradox
  • Vanity metric
  • Guardrail metric
  • Event quality