시간 cohort
같은 기간에 시작한 사용자를 비교한다.
예: 2026년 6월 첫째 주 가입자분류: 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주차에도 공동 작업을 했는가”처럼 함께 사용한다.
가장 쉬운 분석은 전체 사용자 수, 전체 클릭 수, 전체 가입 수를 보는 것이다. 하지만 단일 count와 전체 평균은 세 가지 정보를 잃는다.
invite_created 1,000건과 invite_accepted 400건이 있어도 같은 초대가 생성된 뒤 수락된 것인지 알 수 없다.Product analytics가 event-level 사용자 행동을 추적하는 이유는 이 한계를 줄이기 위해서다. Amplitude는 product analytics를 engagement, drop-off, retention driver를 이해하는 활동으로 설명한다. Product Engineer에게 이는 전체 count를 보고 끝내지 않고 행동 흐름, 비교 집단, 관찰 시간을 함께 고정하라는 뜻이다.
핵심 철학은 “좋아 보이는 비율을 찾는 것”이 아니라 같은 질문에 같은 집합이 나오도록 측정 계약을 만드는 것이다. funnel과 cohort는 원인을 확정하지 않지만, 원인을 찾을 수 있는 비교 단위로 문제를 좁힌다.
비율은 보통 분자 / 분모로 쓰지만, 제품 지표에는 최소 다섯 가지 계약이 필요하다.
Denominator(디노미네이터, 분모) 는 지표가 묻는 행동을 할 자격과 기회를 가진 분석 단위의 집합이다. 모든 사용자나 모든 이벤트를 무조건 분모로 두는 값이 아니다.
초대 생성 지표의 분모를 비교해보자.
| 분모 | 실제로 묻는 질문 |
|---|---|
| 모든 로그인 사용자 | 로그인한 사람 중 초대를 만든 비율은 얼마인가 |
| 초대 권한이 있는 workspace admin | 초대할 자격이 있는 admin 중 누가 초대했는가 |
| 초대 모달을 연 unique workspace | 초대 UI를 본 workspace 중 생성에 성공한 비율은 얼마인가 |
| 해당 주에 생성된 unique workspace | 새 workspace 중 7일 안에 협업 상태에 도달한 비율은 얼마인가 |
네 값은 모두 계산 가능하지만 서로 다른 제품 질문이다. 분모는 숫자를 계산하기 전에 “누가 실제 기회를 가졌는가”로 읽는다. 권한이 없는 member를 초대 생성률 분모에 넣으면 UI(User Interface, 사용자 인터페이스) 문제 없이도 비율이 낮아진다.
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의 성공으로 세지 않는다. 과거 초대의 늦은 수락을 새 모달의 성공으로 잘못 붙이는 것을 막기 위해서다.
Identity(아이덴티티, 식별 기준) 는 여러 이벤트가 같은 사용자·workspace·초대·시도에 속한다는 것을 연결하는 키다. Unique unit(고유 집계 단위) 은 최종 비율에서 한 번만 세는 대상을 뜻한다.
user_id가 적합할 수 있다.workspace_id가 더 적합할 수 있다.invite_id가 필요하다.flow_id와 modal_view_id가 필요하다.한 admin이 같은 workspace에서 모달을 세 번 열고 초대 다섯 건을 만들었을 때 unique user는 1, unique workspace는 1, modal view는 3, invitation은 5다. L13 공통 초대 지표는 workspace를 한 번 세지만, 반복 시도 마찰을 진단하는 별도 지표는 modal view를 세어야 한다. “초대율”이라는 이름만으로는 어떤 값인지 알 수 없다.
Deduplication(디듀플리케이션, 중복 제거) 은 같은 논리적 사건이 재시도나 다중 수집 경로 때문에 여러 번 기록되어도 한 번만 세는 규칙이다. 이벤트 row에 단순히 DISTINCT user_id를 적용하는 것과는 다르다.
invite_created와 invite_accepted는 producer가 발급한 필수 domain_event_id로만 ingestion 중복을 제거한다.domain_event_id가 없으면 event_id나 invite_id로 추정하지 않고 quarantine(격리 영역) 으로 보내 원인을 교정할 때까지 지표 입력에서 제외한다.invite_id는 중복 제거 키가 아니라 created와 accepted를 잇는 lifecycle join key이자 unique invitation 집계 단위다.modal_view_id별 한 번으로 센다.네트워크 재시도로 같은 domain_event_id의 invite_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를 섞으면 처리량과 전환을 모두 왜곡한다.
Window(윈도우, 관찰 기간) 는 시작 사건 뒤 성공 사건을 기다리는 시간 범위다. 7일 내라면 시작 시각, 종료 경계 포함 여부, 시간대를 함께 정한다.
이 문서의 7일 지표는 다음처럼 고정한다.
start <= success_timestamp < start + 7 * 24 hourstimestamp 기준: UTC(Coordinated Universal Time, 협정 세계시) event timecohort 표시 기준: 제품의 합의된 business timezone24시간 뒤에도 가치가 생기는 제품에 10분 window를 쓰면 정상 사용자를 이탈로 오해한다. 반대로 5분 안에 끝나야 하는 결제 제출에 30일 window를 쓰면 서로 다른 시도가 연결될 수 있다. window는 보고서 옵션이 아니라 제품의 자연스러운 사용 주기에 대한 가정이다.
초대 사례는 다음 세 이벤트 흐름을 canonical contract로 사용한다.
invite_modal_opened -> invite_created -> invite_acceptedinvite_modal_opened -> invite_modal_closedinvite_modal_closed는 성공 단계를 하나 더 만드는 이벤트가 아니라 생성 window를 관찰하기 위한 lifecycle helper다. 중간의 이메일 입력, 제출 클릭, 실패 이벤트는 진단에는 유용하지만 핵심 세 이벤트의 대체물이 아니다. invite_created와 invite_accepted는 제품 상태의 성공적인 변화를 나타낸다.
| 이벤트 | Trigger(발생 조건) | 연결 identity | ingestion dedup / metric unique 단위 |
|---|---|---|---|
invite_modal_opened | 초대 권한이 있는 사용자의 화면에서 모달이 실제로 보이고 상호작용 가능한 상태가 된 시점 | actor_user_id, workspace_id, 한 번의 진입인 flow_id, 한 노출인 modal_view_id | client 수집 중복은 (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_at | client 수집 중복은 (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_accepted | invitation이 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 실패를 먼저 본다. 이 진단 이벤트는 세 공통 지표의 분모나 성공 조건을 바꾸지 않는다.
같은 세 이벤트를 사용해도 제품 질문에 따라 분모와 unique 단위가 달라진다. 다음 세 지표는 이름을 바꾸어 부를 수 있는 동의어가 아니다.
이 절에서 first qualifying open(분석 대상 최초 모달 노출) 은 분석 기간 [start_at, end_at) 안에서 client event 중복을 제거한 뒤, 권한 있는 actor에게 실제로 표시되었다는 invite_modal_opened 계약을 만족한 해당 workspace의 가장 이른 open이다. 분석 기간 전 open이나 렌더링 실패, 권한 없는 actor의 event는 first open 후보가 아니다. 아래의 “최초 modal open”은 모두 이 시점을 뜻한다.
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 계약이며, 바꿀 때는 이전·이후 값을 같은 정의로 다시 계산한다.
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개라면 다음 두 값이 나온다.
280 / 1,000 = 28%280 / 620 = 45.2%두 번째 값은 funnel의 created -> accepted 단계 전환율이고 첫 번째 값과 분모가 다르다. 둘 다 유용하지만 이름 없이 수락률이라고 부르면 안 된다.
new workspace 7-day activation_rate(새 workspace 7일 활성화율) 는 eligible new workspace 중 생성 후 7일 안에 초대를 만들고 최소 한 명이 수락한 workspace의 비율이다. 정상적인 UI, API, integration 등 어떤 entry point로 시작했든 인정하며 invite_modal_opened나 flow_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 지표로 별도 관찰해야 한다. 초대 수락 자체를 최종 사용자 가치라고 단정하지 않는다.
| 대상 | modal view | created invite | 7일 내 accepted | 세 지표에서의 결과 |
|---|---|---|---|---|
| workspace A | m1, m2 | m1에서 i1 생성 | i1 수락 | creation: A 성공 1회, accepted/modal: A 성공 1회, activation: A 성공 1회 |
| workspace B | m3 | i2, 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_opened | workspace | 1,000 | 100% | - |
invite_created | workspace with at least one created invite | 620 | 62% | 62% |
invite_accepted within 7 days | workspace with at least one accepted invite | 280 | 28% | 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의 반복 사용이 전체 활성 사용자 수를 떠받치고 있는지 분리해야 한다.
다음 이벤트 로그로 signup -> workspace -> first project funnel과 day 7 retention을 계산해보자. 이 예제는 기존의 작은 데이터셋을 유지하되, 분모와 결과까지 명시한다.
user_id | cohort_week | day | eventu1 | 2026-W24 | 0 | signup_completedu1 | 2026-W24 | 0 | workspace_createdu1 | 2026-W24 | 1 | first_project_createdu1 | 2026-W24 | 7 | project_openedu2 | 2026-W24 | 0 | signup_completedu2 | 2026-W24 | 0 | workspace_createdu3 | 2026-W24 | 0 | signup_completedu4 | 2026-W25 | 0 | signup_completedu4 | 2026-W25 | 0 | workspace_createdu4 | 2026-W25 | 0 | first_project_createdu5 | 2026-W25 | 0 | signup_completedu5 | 2026-W25 | 7 | project_opened분석 계약은 다음과 같다.
signup_completed가 발생한 주차다.user_id이며 각 단계는 사용자별 최대 한 번 센다.project_opened다.| cohort | signup 분모 | workspace 도달 | first project 도달 | workspace step 전환 | project step 전환 | exact day 7 retention |
|---|---|---|---|---|---|---|
| 2026-W24 | 3 | 2 | 1 | 2/3 = 66.7% | 1/2 = 50% | 1/3 = 33.3% |
| 2026-W25 | 2 | 1 | 1 | 1/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_created와 first_project_created가 없다. 다음 두 설명이 모두 가능하다.
첫 설명이면 데이터 품질 문제이고, 두 번째면 funnel 모집단 정의가 잘못된 것이다. role, source, tracking QA를 확인하지 않고 “중간 단계를 건너뛴 이상 사용자”로 제거하면 실제 협업 사용자를 분석에서 잃는다.
Cohort의 조건은 분석 전에 고정되어야 한다. 결과를 본 뒤 retention이 높은 사용자의 공통 행동만 골라 cohort를 만들면 선택 편향이 생기기 쉽다.
같은 기간에 시작한 사용자를 비교한다.
예: 2026년 6월 첫째 주 가입자특정 행동을 한 사용자와 하지 않은 사용자를 비교한다.
예: 첫날 팀원을 초대한 사용자 vs 초대하지 않은 사용자role, plan, company size, source 같은 property로 나눈다.
예: admin 사용자와 member 사용자미리 정한 variant 배정 단위로 결과를 비교한다.
예: onboarding_v2 treatment vs control전체 retention이 40%로 같더라도 내부 구성이 다를 수 있다.
| 기간 | 신규 cohort retention | 기존 cohort retention | 전체 retention |
|---|---|---|---|
| 변경 전 | 45% | 35% | 40% |
| 변경 후 | 30% | 50% | 40% |
전체값만 보면 변화가 없다. 하지만 신규 사용자는 악화했고 기존 사용자는 개선했다. 이를 평균의 함정으로만 외우기보다 “비교 가능한 시작점을 섞었기 때문”이라고 이해해야 한다.
첫날 팀원을 초대한 사용자의 4주 retention이 60%, 초대하지 않은 사용자가 25%라고 하자. 이 차이만으로 “초대를 강제하면 retention이 35%p 오른다”고 결론 내릴 수 없다. 원래 협업 의도가 강한 사용자가 초대도 하고 돌아오기도 했을 수 있다.
행동 cohort는 어떤 행동이 장기 가치와 함께 나타나는지 탐색하는 데 적합하다. 그 행동이 원인인지 검증하려면 사전 특성이 비슷한 집단 비교나 실험 설계가 필요하며, 다음 문서의 범위로 이어진다.
enterprise admin cohort의 retention만 떨어졌다면 권한·초대·SSO(Single Sign-On, 통합 로그인) 흐름을 먼저 볼 수 있다. 그러나 회사, role, 기기를 계속 쪼개면 분모가 작아지고 우연한 극값이 늘어난다. 분석에 필요하지 않은 민감한 속성을 수집해 cohort를 만드는 것도 피해야 한다.
Retention은 “다시 왔다”가 아니라 시작 집단이 가치 행동을 다시 했다를 측정한다. 따라서 acquisition event, return action, 시간 bucket 세 가지를 먼저 정한다.
| 제품 유형 | 약한 retention 이벤트 | 강한 retention 이벤트 |
|---|---|---|
| 협업 도구 | page_view | comment_created, document_shared |
| 개발자 도구 | dashboard_opened | api_call_succeeded, deployment_created |
| 분석 도구 | report_viewed | saved_chart_shared, query_run |
| 결제/권한 기능 | billing_page_viewed | premium_feature_used |
약한 이벤트가 항상 쓸모없는 것은 아니다. discovery와 navigation 문제를 진단할 수 있다. 다만 제품의 반복 가치를 주장하는 primary retention event로 쓰기에는 부족하다.
도구마다 rolling과 unbounded라는 이름을 다르게 쓰기도 하므로, 대시보드 이름만 공유하지 말고 event와 window를 적는다.
| 방식 | 분자 조건 | 적합한 질문 |
|---|---|---|
| Exact N-day retention | 시작 후 정확히 N번째 day bucket에 return action | 매일 사용이 자연스러운 제품에서 특정 날짜 복귀를 볼 때 |
| Bounded retention | day N부터 day M 사이에 한 번 이상 return action | 주기 변동을 허용한 7일 구간 복귀를 볼 때 |
| Unbounded/Rolling retention | day N 또는 그 이후에 한 번 이상 return action | 정확한 날짜보다 장기 재방문 여부가 중요할 때 |
| Usage frequency | 기간 안의 활성 day 수나 반복 횟수가 기준 이상 | 주 3회 사용처럼 가치 빈도가 중요한 제품일 때 |
가입 후 day 7에는 오지 않았지만 day 8에 돌아온 사용자는 exact day 7 retention에서는 실패다. day 7~13 bounded retention과 day 7 이후 unbounded retention에서는 성공일 수 있다. 같은 로그가 다른 답을 내는 이유는 계산 오류가 아니라 질문이 다르기 때문이다.
Retention curve(리텐션 곡선) 는 시작 cohort 중 return action을 한 비율을 시간에 따라 그린 값이다.
cohort size: 1,000 usersday 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 구성, 이벤트 누락을 함께 확인해야 한다.
세 지표는 서로 다른 시간축의 질문에 답한다.
| 지표 | 묻는 질문 | 초대 사례의 정확한 예 |
|---|---|---|
| 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를 본다.
퀴즈
힌트: 유입량과 제품 가치 경험은 같은 말이 아니다.
새 유입이 늘었지만 핵심 가치를 경험하지 못하는 사용자가 많아졌을 수 있다. 유입 source별 시간 cohort, activation funnel, week 1 return action의 정의와 이벤트 품질을 분리해서 봐야 한다.
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 지표로 표시하는 것이다.
Selection bias(선택 편향) 는 분석에 포함된 집단을 고르는 과정이 결과와 연관되어 비교가 왜곡되는 현상이다. 행동 cohort는 특히 주의한다.
예를 들어 초대 모달을 연 workspace만 분석하면 초대 기능을 발견하지 못한 eligible workspace는 분모에서 사라진다. 이 분석은 modal UX의 생성 성공률에는 맞지만, 전체 eligible admin workspace의 초대 adoption을 설명하지 못한다. 질문에 따라 분모를 바꿔야지 한 비율을 전체 제품 성과로 확대하면 안 된다.
Survivor bias(생존자 편향) 는 selection bias의 한 형태로, 이미 뒤 단계까지 살아남은 대상만 보고 초기 이탈을 놓치는 문제다. invite_created workspace만 대상으로 수락률을 보면 modal을 열고 생성에 실패한 380개 workspace는 보이지 않는다.
두 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를 각각 판단해야 한다.
| 관찰되는 실패 신호 | 의미할 수 있는 문제 | 먼저 확인할 계약 |
|---|---|---|
| 이벤트 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에 들어갈 수 있다.
분석 루틴은 대시보드 클릭 순서가 아니라 잘못된 결론을 줄이는 검증 순서다.
funnel과 cohort는 제품 상태를 읽는 방법이다. 다음 단계에서는 관찰된 차이가 우연인지, 특정 release나 experiment 때문인지 판단해야 한다.
Experimentation & Feature Flags: cohort 차이와 행동 상관관계를 실험 설계와 rollout 판단으로 연결한다.Frontend Product Quality & RUM: 성능과 접근성 같은 UX 품질이 funnel과 retention에 미치는 영향을 본다.Privacy, Consent & Product Data Governance: cohort와 event property가 개인정보 경계를 넘지 않도록 관리한다.