콘텐츠로 이동

웹 페이지 성능 및 사용자 경험 분석


Web RUM SDK는 실제 사용자가 페이지에 접근할 때의 로딩, 렌더링, 상호작용, 레이아웃 변경, 오류, 리소스 및 긴 작업 데이터를 동일한 view_id에 연관시킵니다. 애플리케이션 데이터가 Guance에 업로드되면, 먼저 Core Web Vitals로 전반적인 경험을 평가한 후 페이지, 버전, 브라우저, 기기, 네트워크 등의 차원으로 영향을 받은 범위를 파악하고, 마지막으로 view_id를 따라 오류, 리소스, 긴 작업 및 세션 리플레이로 드릴다운할 수 있습니다.

이 문서의 모든 필드명은 Web RUM SDK가 현재上报하는 데이터 구조를 기반으로 합니다. 전체 필드 목록은 웹 애플리케이션 데이터 수집을 참조하세요.

분석 전 통계 기준 명확히 하기

최초 로딩과 라우트 전환 구분

view_loading_type은 두 가지 유형의 View를 구분하는 데 사용됩니다.

  • initial_load: 브라우저가 페이지를 처음 열거나 새로고침할 때
  • route_change: SPA(단일 페이지 애플리케이션)에서 라우트 전환이 발생할 때

현재 SDK는 initial_load View에서만 first_byte, first_contentful_paint, largest_contentful_paint, first_input_delay 및 탐색 타이밍 필드를 수집합니다. loading_time, interaction_to_next_paint, cumulative_layout_shift 및 View 관련 카운트는 initial_loadroute_change 모두에 적용됩니다.

따라서

  • 첫 화면, 흰 화면 후보, FCP, LCP, TTFB를 분석할 때는 반드시 view_loading_type = "initial_load"로 필터링해야 합니다.
  • SPA 라우트 성능 분석 시에는 loading_time, interaction_to_next_paint, cumulative_layout_shift, 오류, 긴 작업 등의 필드를 우선 사용합니다.
  • route_change에서 FCP 또는 LCP가 누락된 레코드를 이상으로 판단하지 마세요.

평균값이 아닌 P75 사용

Core Web Vitals는 페이지 방문 샘플의 75번째 백분위수(P75)를 사용하여 평가하고, 모바일과 데스크톱을 각각 관찰할 것을 권장합니다. P75가达标하면 최소 75%의 페이지 방문이 목표 범위에 있음을 의미합니다. 평균값은 많은 수의 빠른 샘플에 의해 희석되기 쉬워 느린 사용자의 실제 경험을 대표할 수 없습니다.

다음 항목을 함께 관찰하는 것이 좋습니다.

  • P50: 일반적인 사용자 경험
  • P75: Core Web Vitals 주요 판단 기준
  • P90 또는 P95: 느린 네트워크, 저성능 기기 등 꼬리 사용자 경험
  • 달성률: "양호" 임계값 내에 있는 View 수가 유효 샘플 수에서 차지하는 비율
  • 샘플 수: 소수의 샘플만으로 페이지 또는 버전 품질을 판단하지 않도록 합니다.

지표 정의, 임계값 및 P75 통계 방식은 web.dev: Web Vitals실제 환경 Web Vitals 통계 모범 사례를 참조하세요.

단위 주의

  • cumulative_layout_shift를 제외하고, 이 문서에 나열된 시간 지표는 데이터에 나노초(ns) 단위로 저장됩니다.
  • 1s = 1,000,000,000ns, 1ms = 1,000,000ns
  • cumulative_layout_shift는 단위가 없는 점수이므로 시간 변환을 수행하지 마세요.
  • DQL 임계값은 원래 저장 단위를 사용해야 합니다. 예를 들어 LCP 2.5초는 2500000000으로 작성해야 합니다.

핵심 경험 지표

Core Web Vitals

경험 차원 SDK 필드 유효 View 양호 개선 필요 나쁨 위치 파악 필드
로딩 성능 (LCP) largest_contentful_paint initial_load ≤ 2.5초 > 2.5초 및 ≤ 4초 > 4초 largest_contentful_paint_element_selector
상호작용 응답성 (INP) interaction_to_next_paint initial_load, route_change ≤ 200ms > 200ms 및 ≤ 500ms > 500ms interaction_to_next_paint_target_selector
시각적 안정성 (CLS) cumulative_layout_shift initial_load, route_change ≤ 0.1 > 0.1 및 ≤ 0.25 > 0.25 cumulative_layout_shift_target_selector

LCP, INP, CLS의 임계값은 각각 LCP, INPCLS를 참조하세요.

LCP: 사용자가 주요 콘텐츠를 언제 보는가

largest_contentful_paint는 뷰포트 내에서 가장 큰 이미지, 텍스트 블록 또는 비디오의 페인트가 완료된 시간을 나타냅니다. SDK는 동시에 largest_contentful_paint_element_selector를上报하여 LCP를 발생시키는 페이지 요소를 찾는 데 사용합니다.

LCP가 나쁜 경우 다음 필드를 결합하여 시간 소비가 어느 구간에서 발생했는지 판단합니다.

  1. first_byte가 높은 경우: 서버 응답, 리디렉션, CDN, 지역 및 네트워크를 우선 확인합니다.
  2. first_byte는 정상이지만 first_contentful_paint가 높은 경우: 렌더링을 차단하는 CSS, JavaScript 및 클라이언트 초기화를 우선 확인합니다.
  3. first_contentful_paint는 정상이지만 largest_contentful_paint가 높은 경우: LCP 요소에 해당하는 리소스가 너무 늦게 발견되었거나, 다운로드 속도가 느리거나, 렌더링이 지연되는지 우선 확인합니다.
  4. loading_time이 여전히 LCP보다 현저히 높은 경우: 페이지의 주요 콘텐츠는 이미 표시되었지만 네트워크 요청 또는 DOM 변경이 계속 발생하고 있습니다.

INP: 페이지가 작업에 신속하게 응답할 수 있는가

interaction_to_next_paint는 한 번의 상호작용이 입력, 이벤트 처리부터 다음 프레임 페인트까지의 전체 지연 시간을 측정합니다. SDK는 View 내에서 상호작용을 지속적으로 관찰하고 최악의 상호작용에 가까운 값을 보고하며, interaction_to_next_paint_target_selector를 통해 해당 요소를 식별합니다.

INP가 나쁜 경우 다음 사항을 중점적으로 연관시킵니다.

  • view_long_task_count: 페이지에 메인 스레드를 50ms 이상 차단하는 작업이 있는지 여부
  • view_error_count: 상호작용 중 스크립트 오류가 발생했는지 여부
  • frustration_count: 반복 클릭, 무효 클릭 또는 오류 클릭과 같은 좌절 행동이 나타나는지 여부
  • R::long_taskduration, blocking_durationscripts: 차단 시간 및 관련 스크립트 찾기

사용자 상호작용이 없는 View에는 interaction_to_next_paint가 없을 수 있습니다. INP 통계 시에는 해당 필드가 존재하는 샘플만 사용합니다.

CLS: 페이지 콘텐츠가 예기치 않게 이동하는가

cumulative_layout_shift는 페이지의 가시 요소가 예기치 않게 이동하는 정도를 측정하며, cumulative_layout_shift_target_selector는 가장 큰 영향을 미치는 요소를 가리킵니다.

CLS가 나쁜 경우 일반적인 확인 방향은 다음과 같습니다.

  • 이미지, 비디오, 광고 또는 iframe에 너비와 높이가 지정되지 않았습니다.
  • 비동기 콘텐츠가 기존 콘텐츠 위에 삽입됩니다.
  • 웹 폰트 전환으로 인해 텍스트 크기가 변경됩니다.
  • 애니메이션이 레이아웃을 트리거하는 속성을 통해 구현됩니다.

최초 로딩 보조 지표

SDK 필드 의미 권장 용도
first_byte 탐색 시작부터 문서 응답의 첫 번째 바이트를 받을 때까지 서버, 네트워크, 리디렉션 또는 CDN이 후속 렌더링을 지연시키는지 확인
first_contentful_paint 첫 번째 텍스트, 이미지, SVG 또는 흰색이 아닌 Canvas 페인트 시간 사용자가 처음으로 콘텐츠를 보는 시점을 측정하며, 흰 화면 후보 분석의 주요 필드이기도 함
dom_interactive 문서 파서가 파싱을 완료한 시점 HTML 및 동기 스크립트가 DOM 대화형 상태를 지연시키는지 확인
dom_content_loaded DOMContentLoaded 완료 시점 DOM 구축 및 지연 스크립트 완료 시간 확인
dom_complete 페이지 및 하위 리소스 완료 후 시점 전체 문서 수명 주기가 너무 긴지 확인
load_event load 이벤트 완료 시점 종속 리소스가 모두 로드되는 시간 확인
first_paint_time 현재 SDK가 계산한 responseEnd - fetchStart 문서 응답 단계 소요 시간 관찰. FCP와 동일시하지 마세요.
time_to_interactive 현재 SDK가 계산한 domInteractive - fetchStart DOM이 대화형 상태에 도달하는 시간 관찰. 랩 도구의 TTI와 혼동하지 마세요.
dom_ready 현재 SDK가 계산한 domContentLoadedEventEnd - fetchStart DOM Ready 완료 소요 시간 관찰
resource_load_time 현재 SDK가 계산한 loadEventStart - domContentLoadedEventEnd DOM Ready 이후 종속 리소스를 기다리는 소요 시간 관찰
dom 현재 SDK가 계산한 domComplete - domInteractive DOM 대화형 이후 완료까지의 소요 시간 관찰

FCP는 web.dev: FCP를 참조하세요. 양호는 1.8초 이하, 나쁨은 3초 초과입니다. first_byteweb.dev: 첫 번째 바이트까지의 시간을 참조하세요. 0.8초 이내가 일반적으로 양호하며, 1.8초 초과는 일반적으로 나쁩니다. TTFB는 Core Web Vitals가 아니므로 FCP 및 LCP와 결합하여 판단해야 합니다.

페이지 로딩 및 사용 경험 지표

SDK 필드 의미 적합한 질문
loading_time SDK가 load 이벤트, 네트워크 요청 및 DOM 활동을 종합하여 얻은 페이지 안정화 소요 시간 페이지의 주요 로딩 활동이 언제 종료되는지, SPA 라우트 전환이 계속 요청하거나 DOM을 업데이트하는지
time_spent 사용자가 현재 View에 머문 시간 느린 페이지가 빠른 이탈을 유발하는지, 이상이 장시간 사용에 영향을 미치는지
view_error_count 현재 View에 연결된 오류 수 페이지가 스크립트 이상으로 인해 사용할 수 없는지
view_resource_count 현재 View에 연결된 리소스 요청 수 페이지가 너무 많은 요청을 하는지, 리소스 워터폴을 계속 분석해야 하는지
view_long_task_count 현재 View에 연결된 긴 작업 수 메인 스레드가 자주 차단되는지
view_action_count 현재 View에 연결된 사용자 작업 수 페이지가 실제로 사용되는지, INP 샘플 누락이 상호작용 부재 때문인지
frustration_count 현재 View에 연결된 좌절 행동 수 사용자가 응답 없음, 결과 없음 또는 오류로 인해 작업을 반복하는지
is_active View가 여전히 활성 상태인지 아직 종료되지 않았고 지표가 계속 업데이트될 수 있는 View를 필터링
session_has_replay 현재 세션에 관련 세션 리플레이가 있는지 이상 사용자 현장을 직접 재생할 수 있는지

loading_time은 시각적 완료 시간과 동일하지 않습니다. 페이지는 LCP를 먼저 완료할 수 있지만 백그라운드 폴링, API 요청 또는 지속적인 DOM 업데이트로 인해 loading_time이 더 길어질 수 있습니다. 반대로 loading_time이 정상이더라도 페이지의 주요 콘텐츠가 올바르게 표시되었음을 증명하지는 않습니다.

페이지 성능 기준선 수립

1단계: 각 페이지의 P75 확인

아래 쿼리는 대시보드 차트를 대상으로 하므로 DQL에 [24h], [1h] 등의 고정 시간 범위를 의도적으로 작성하지 않습니다. 시간 범위를 생략하면 쿼리가 대시보드 오른쪽 상단의 시간 위젯을 따릅니다. DQL에서 시간 범위를 직접 지정하면 대시보드 시간 위젯보다 우선 순위가 높아져 차트가 해당 시간 범위를 고정적으로 쿼리하게 됩니다. 자세한 내용은 DQL 시간 범위 지정을 참조하세요. <APP_ID>를 애플리케이션 ID로 바꾸면 됩니다.

페이지별 LCP P75 확인:

R::view:(percentile(largest_contentful_paint, 75) AS p75_lcp) {app_id = "<APP_ID>", view_loading_type = "initial_load", largest_contentful_paint = exists()} BY view_path_group SORDER BY p75_lcp DESC SLIMIT 20

페이지별 INP P75 확인:

R::view:(percentile(interaction_to_next_paint, 75) AS p75_inp) {app_id = "<APP_ID>", interaction_to_next_paint = exists()} BY view_path_group SORDER BY p75_inp DESC SLIMIT 20

페이지별 CLS P75 확인:

R::view:(percentile(cumulative_layout_shift, 75) AS p75_cls) {app_id = "<APP_ID>", cumulative_layout_shift = exists()} BY view_path_group SORDER BY p75_cls DESC SLIMIT 20

세 지표를 직접 더하여 하나의 점수로 만들지 마세요. LCP, INP, CLS는 각각 로딩, 응답성 및 안정성을 나타내며, 하나라도 나쁘면 개별적으로 위치를 파악해야 합니다.

2단계: 달성률 관찰

다음 쿼리는 LCP가 2.5초를 초과하지 않는 유효 View의 비율을 계산합니다.

eval(100 * A / B, alias='LCP_good_rate', A="R::view:(count(view_id)) {app_id = '<APP_ID>', view_loading_type = 'initial_load', largest_contentful_paint <= 2500000000}", B="R::view:(count(view_id)) {app_id = '<APP_ID>', view_loading_type = 'initial_load', largest_contentful_paint = exists()}")

같은 방식으로 조건을 다음으로 바꿀 수 있습니다.

  • INP 달성: interaction_to_next_paint <= 200000000
  • CLS 달성: cumulative_layout_shift <= 0.1
  • FCP 달성: first_contentful_paint <= 1800000000

분모는 반드시 지표가 존재하는 유효 샘플만 계산해야 합니다. 그렇지 않으면 해당 지표를 지원하지 않는 브라우저, 상호작용이 없는 View 또는 너무 일찍 이탈한 View가 결과를 왜곡할 수 있습니다.

3단계: 핵심 차원별 분할

다음 SDK 필드를 순서대로 그룹화하거나 필터링하는 것이 좋습니다.

  1. view_path_group: 먼저 영향을 받은 페이지를 찾습니다.
  2. version: 새 버전에서 회귀가 발생했는지 확인합니다.
  3. browser, browser_version_major: 브라우저 호환성 또는 기능 차이를 확인합니다.
  4. device, screen_size: 기기 성능 및 레이아웃 차이를 구분합니다.
  5. network_type: Wi-Fi, 셀룰러 네트워크 및 연결 불가능한 네트워크를 구분합니다.
  6. env, service: 서로 다른 환경 또는 서비스의 데이터 혼합을 방지합니다.

예를 들어, 버전 및 페이지별로 Core Web Vitals를 비교합니다.

R::view:(percentile(largest_contentful_paint, 75) AS p75_lcp, percentile(interaction_to_next_paint, 75) AS p75_inp, percentile(cumulative_layout_shift, 75) AS p75_cls) {app_id = "<APP_ID>"} BY version, view_path_group SORDER BY p75_lcp DESC SLIMIT 50

LCP는 initial_load에만 존재하고 INP는 상호작용이 없으면 누락될 수 있으므로, 프로덕션 대시보드에서는 세 지표에 대해 각각 차트를 생성한 다음 동일한 페이지, 버전 및 기기 필터 조건으로 연결 분석하는 것이 더 좋습니다.

흰 화면 및 장시간 콘텐츠 없음 분석

흰 화면은 SDK의 직접 지표가 아닙니다.

현재 SDK는 white_screen이라는 필드를上报하지 않습니다. 흰 화면은 수집된 지표를 통해서만 후보 집합을 구성한 다음 오류, 리소스, 긴 작업 및 세션 리플레이를 결합하여 확인할 수 있습니다.

후보를 두 단계로 나누는 것이 좋습니다.

  1. 느린 FCP 후보: first_contentful_paint > 3000000000. 사용자가 첫 번째 콘텐츠를 보는 데 3초 이상 걸렸음을 의미하며, 비교적 안정적이고 통계 가능한 흰 화면 경험 근사치입니다.
  2. FCP 누락 후보: 이미 종료된 최초 로딩 View가 3초 이상 머물렀지만 first_contentful_paint가 존재하지 않습니다. 이 규칙은 문제 해결에만 사용할 수 있으며 흰 화면과 직접 동일시할 수 없습니다.

FCP 누락은 다음 상황으로 인해 발생할 수도 있습니다.

  • 현재 브라우저가 SDK에서 사용하는 FCP 수집 기능을 지원하지 않습니다.
  • FCP가 생성되기 전에 페이지가 백그라운드로 전환되거나 숨겨졌습니다.
  • 사용자가 페이지를 미리 닫았습니다.
  • 데이터 샘플링, 네트워크上报 또는 페이지 수명 주기가 조기에 종료되었습니다.
  • route_change를 분석에 잘못 포함했습니다.

따라서 FCP 누락 규칙은 반드시 view_loading_type = "initial_load"로 필터링하고 browser별로 수집覆盖率를 검증해야 합니다. 브라우저 기능 범위는 브라우저 지원을 참조하세요.

느린 FCP 후보 비율 통계

eval(100 * A / B, alias='white_screen_candidate_rate', A="R::view:(count(view_id)) {app_id = '<APP_ID>', view_loading_type = 'initial_load', first_contentful_paint > 3000000000}", B="R::view:(count(view_id)) {app_id = '<APP_ID>', view_loading_type = 'initial_load', first_contentful_paint = exists()}")

이 비율은 "유효 FCP 샘플 중 콘텐츠를 보는 데 3초 이상 걸린 비율"을 나타내며, 시각적으로 확인된 실제 흰 화면 비율을 나타내지 않습니다. view_path_group, version, browsernetwork_type별로 분할하는 것이 좋습니다.

느린 FCP View 찾기

R::view:(view_id, session_id, view_url, first_contentful_paint, first_byte, loading_time, view_error_count, view_resource_count, view_long_task_count, session_has_replay) {app_id = "<APP_ID>", view_loading_type = "initial_load", first_contentful_paint > 3000000000} ORDER BY first_contentful_paint DESC LIMIT 100

결과 해석:

  • first_byte도 동시에 높은 경우: 서버, CDN, 네트워크 및 리디렉션을 우선 확인합니다.
  • first_byte는 정상이지만 FCP가 매우 높은 경우: 렌더링을 차단하는 리소스, 클라이언트 렌더링 및 동기 JavaScript를 우선 확인합니다.
  • view_error_count > 0: 오류 스택을 우선 확인하여 초기화가 중단되었는지 확인합니다.
  • view_long_task_count > 0: 메인 스레드가 첫 번째 페인트 전에 긴 작업에 의해 차단되었는지 확인합니다.
  • session_has_replay = true: session_id 또는 view_id를 사용하여 세션 리플레이를 열고 사용자가 실제로 본 화면을 확인합니다.

FCP 누락 후보 찾기

R::view:(view_id, session_id, view_url, time_spent, view_error_count, view_resource_count, view_long_task_count, session_has_replay) {app_id = "<APP_ID>", view_loading_type = "initial_load", is_active = false, time_spent > 3000000000, first_contentful_paint != exists()} ORDER BY time_spent DESC LIMIT 100

이 결과는 먼저 browser별로 FCP를 지원하지 않는 샘플을 제외한 다음, 세션 리플레이 및 드릴다운 쿼리를 결합하여 확인해야 합니다. FCP 누락만으로 "실제 흰 화면 비율" 알림을 생성할 수 없습니다.

view_id를 따라 근본 원인 드릴다운

후보 결과에서 <VIEW_ID>를 다음 쿼리에 대입합니다.

스크립트 및 런타임 오류 확인:

R::error:(error_type, error_source, error_message, error_stack) {app_id = "<APP_ID>", view_id = "<VIEW_ID>"} ORDER BY time ASC LIMIT 100

실패 또는 느린 리소스 확인:

R::resource:(resource_url, resource_type, resource_status, duration, resource_ttfb, resource_trans) {app_id = "<APP_ID>", view_id = "<VIEW_ID>", resource_status >= 400} ORDER BY duration DESC LIMIT 100

HTTP 오류가 없지만 여전히 리소스가 너무 느리다고 의심되는 경우 resource_status >= 400을 제거하고 duration별로 가장 느린 리소스를 확인할 수 있습니다. resource_ttfb가 높으면 일반적으로 서버 또는 네트워크 대기를 나타내고, resource_trans가 높으면 일반적으로 콘텐츠 전송 시간을 나타냅니다.

긴 작업 확인:

R::long_task:(duration, blocking_duration, scripts) {app_id = "<APP_ID>", view_id = "<VIEW_ID>"} ORDER BY duration DESC LIMIT 100

duration은 긴 작업의 총 시간을 나타내고, blocking_duration은 그중 사용자 입력을 차단하는 시간을 나타내며, scripts는 관련 스크립트를 찾는 데 사용할 수 있습니다.

일반적인 경험 문제 판단 경로

현상 먼저 확인할 필드 추가 연관 일반적인 방향
페이지에 콘텐츠가 나타나지 않음 first_contentful_paint, first_byte view_error_count, view_long_task_count, Resource 서버 느림, 렌더링 차단, 초기화 오류, 긴 작업
주요 콘텐츠 로딩 느림 largest_contentful_paint largest_contentful_paint_element_selector, Resource LCP 리소스 발견 늦음, 다운로드 느림, 렌더링 지연
클릭 후 응답 없음 interaction_to_next_paint interaction_to_next_paint_target_selector, Long Task, Error 메인 스레드 차단, 이벤트 처리 과부하, 스크립트 오류
페이지 콘텐츠 흔들림 cumulative_layout_shift cumulative_layout_shift_target_selector 크기 미지정, 동적 삽입, 폰트 및 애니메이션
페이지가 계속 로딩 중으로 표시됨 loading_time Resource, DOM 활동, Error 요청 미종료, 폴링, 지속적인 DOM 업데이트, 이상 상태 미수렴
사용자가 반복 클릭하거나 클릭 결과 없음 frustration_count Action, INP, Error, 세션 리플레이 시각적 피드백 없음, 무효 클릭, 오류 클릭, 느린 상호작용
새 버전 경험 저하 version + P75 view_path_group, browser, network_type 리소스 크기, 코드 경로, 호환성 또는 릴리스 회귀

대시보드 및 알림 제안

최소한 다음 보기를 설정하는 것이 좋습니다.

  1. LCP, INP, CLS의 P75 추세 및 달성률
  2. FCP, first_byte, loading_time의 P75 추세
  3. view_path_group별로 정렬된 느린 페이지 Top 20
  4. version별로 비교한 릴리스 전후 추세
  5. browser, device, network_type 및 지역별로 분할된 꼬리 경험
  6. view_error_count, view_long_task_count, frustration_count와 성능 지표의 상관 관계 그래프
  7. 느린 FCP 후보 비율 및 재생 가능한 샘플 목록

알림은 P75 또는 달성률을 우선 사용하고 최소 샘플 수와 연속 트리거 조건을 설정하여 소수의 이상 샘플이나 단기 트래픽 변동으로 인한 오탐을 방지해야 합니다. Core Web Vitals의 "나쁨" 임계값부터 시작한 다음 비즈니스 페이지의 중요도, 과거 기준선 및 실제 트래픽에 따라 조정하는 것이 좋습니다.

콘솔에서 분석 완료

  • 실제 사용자 모니터링(RUM) > 분석 대시보드 > 웹에서 개요, 페이지 성능, 리소스 및 오류 분석을 확인합니다.
  • 실제 사용자 모니터링(RUM) > 탐색기에서 view_id, session_id, 페이지, 버전 및 브라우저로 원시 View를 필터링합니다.
  • 개별 View로 이동한 후 Resource, Error, Long Task, Action 및 세션 리플레이를 연결하여 확인합니다.
  • 사용자 지정 통계가 필요한 경우 이 문서의 DQL을 사용하여 대시보드 차트 또는 실제 사용자 모니터링(RUM) 지표 감지를 생성합니다.

콘솔 기능에 대한 자세한 내용은 분석 대시보드, 탐색기실제 사용자 모니터링(RUM) 지표 감지를 참조하세요.

문서 평가

이 페이지가 도움이 되었나요?