RePlaya: 셀프 호스팅 방식의 실시간 세션 리플레이 도구
RePlaya는 S2를 기반으로 구축된 셀프 호스팅 세션 리플레이 도구입니다. 별도의 데이터베이스나 저장소 없이 S2 스트림 하나만으로 모든 세션을 기록하고 실시간으로 재생할 수 있는 것이 특징입니다. 사용자가 웹사이트를 탐색하는 동안 실시간으로 세션을 모니터링할 수 있어 웹 서비스 분석 및 디버깅에 매우 유용합니다.
RePlaya는 S2 기반으로 구축된 셀프 호스팅 세션 리플레이 도구입니다. 각 세션은 하나의 S2 스트림으로 저장되며, 이 스트림이 백엔드 전체를 담당합니다. 별도의 데이터베이스, 메시지 버스, 객체 저장소 또는 검색 인덱스가 필요하지 않습니다. S2 스트림은 기록 중에도 테일링(tailing)할 수 있으므로, RePlaya는 방문자가 여전히 페이지에 있는 동안에도 세션을 실시간으로 리플레이할 수 있으며, 완료된 세션도 재생할 수 있습니다.
웹사이트에 레코더 스니펫을 추가하면 세션이 스트림으로 저장되어 리플레이, 실시간 테일링, 필터링 및 내보내기가 가능합니다.
데모 새로운 세션이 목록에 나타나고 S2 스트림에서 실시간으로 테일링됩니다. 방문자가 앱을 사용함에 따라 리플레이와 활동 피드가 업데이트됩니다.
빠른 시작
S2 액세스 토큰과 베이슨(basin)이 필요합니다. 이를 .env.local 파일에 설정합니다:
S2_ACCESS_TOKEN=replace-with-an-s2-access-token
S2_BASIN=replaya-your-name
PORT=8787
베이슨은 RePlaya의 스트림 기본값으로 처음 사용 시 생성됩니다. 대시보드의 상태 표시는 베이슨과 유효한 S2 엔드포인트를 보여주어 현재 연결된 대상을 확인할 수 있습니다.
S2 클라우드 대신 s2-lite 또는 다른 호환 배포를 사용하려면 엔드포인트를 명시적으로 설정하세요:
S2_ACCOUNT_ENDPOINT=http://localhost:7070
S2_BASIN_ENDPOINT=http://localhost:7070
그런 다음 종속성을 설치하고 개발 서버를 시작합니다:
pnpm install
pnpm dev
API는 http://localhost:8787에서 실행되고, Vite는 http://localhost:5173에서 대시보드를 제공합니다.
다른 앱을 계측하지 않고 테스트 녹화를 만들려면 http://localhost:8787/recorder-test를 열면 됩니다. 동일한 호스팅된 레코더 스크립트를 통해 녹화됩니다.
프로덕션 스타일의 로컬 실행을 위해서는 빌드하고 Express를 통해 하나의 포트에서 모든 것을 제공합니다:
pnpm build
pnpm start
# http://localhost:8787 열기
드롭인 레코더 캡처를 시작하려면 이 코드를 페이지에 추가하고 RePlaya 호스트를 가리키게 합니다:
<script>
!function(w,d,s,u){w.replaya=w.replaya||function(){(w.replaya.q=w.replaya.q||[]).push(arguments)};var e=d.createElement(s);e.async=1;e.src=u;d.head.appendChild(e)}(window,document,"script","https://replaya.example.com/recorder.js");
replaya("init",{apiHost:"https://replaya.example.com",source:"web-app"});
</script>
로컬 개발에서는 호스트가 http://localhost:8787이며, /recorder-test는 동일한 스크립트를 통해 녹화하는 페이지를 제공합니다.
source는 앱, 사이트, 환경 또는 테넌트별로 캡처를 그룹화하기 위한 선택적 메타데이터입니다. distinctId와 userId를 전달하여 세션에 애플리케이션 ID를 태그할 수 있습니다.
기본적으로 레코더는 모든 input, select, textarea 값을 마스킹하므로(rrweb maskAllInputs), 최종 사용자의 키 입력(비밀번호, 이메일, 모든 타이핑)은 서버로 전송되지 않습니다. 허용되는 페이지(예: 내부 관리 UI)에서 원시 양식 제어 상태를 캡처하려면 replaya("init", ...)에 maskAllInputs: false를 전달하거나 레코더 스크립트 태그에 data-mask-all-inputs="false"를 추가하세요.
마스킹은 입력 값만 포함하며, 페이지가 DOM에 렌더링하는 텍스트는 여전히 기록됩니다. 민감한 영역은 replaya-block 클래스로 감싸서 녹화에서 제외하거나, replaya-ignore를 사용하여 하위 트리의 변경을 건너뛸 수 있습니다.
프로덕션에서는 대시보드와 읽기 API를 비공개로 유지하고 수집기 라우트만 공개적으로 노출하세요.
S2에서의 작동 방식 세션 녹화는 로그입니다. 추가 전용(append-only), 정렬된, 타임스탬프가 있는 이벤트 시퀀스입니다. RePlaya는 각 세션을 하나의 S2 스트림으로 저장하고 동일한 방식으로 다시 읽으므로, 단일 기본 요소로 여러 시스템에 분산되는 기능을 처리할 수 있습니다.
저장소. rrweb 이벤트는 S2 프로듀서 API를 통해 세션 스트림의 끝에 추가됩니다. 이 API는 백프레셔를 통해 배치 처리하고 각 배치가 지속되면 확인 응답을 보냅니다. 스트림 자체가 녹화이며, 별도의 블롭 저장소가 없고 수집과 저장 사이에 서버에서 버퍼링되는 것이 없습니다. 대형 rrweb 이벤트는 여러 S2 레코드에 걸쳐 프레이밍되고 읽을 때 재구성됩니다.
타임라인. 세션 스트림은 timestamping.mode: client-require를 사용하므로 rrweb 캡처 시간이 각 이벤트 레코드의 S2 타임스탬프에 기록되고 다시 읽을 때 타임스탬프로 사용됩니다.