테라가 광고 클릭률을 30% 높이고 최대 콘텐츠 렌더링 시간을 늘리는 데 프리패치를 사용한 방법

리소스를 미리 가져오면 페이지 로드 시간이 단축되고 비즈니스 측정항목이 개선됩니다.

Guilherme Moser de Souza
Guilherme Moser de Souza

미리 가져오기는 가까운 시일 내에 필요할 가능성이 있는 리소스 또는 전체 페이지를 다운로드하여 페이지 로드 속도를 높이는 데 사용되는 기법입니다. 연구에 따르면 로드 시간이 빨라질수록 전환율이 높아지고 사용자 환경이 개선되는 것으로 나타났습니다.

Terra는 브라질에서 가장 큰 콘텐츠 포털 중 하나로, 엔터테인먼트, 뉴스, 스포츠를 제공하며 월간 순 방문자 수가 6,300만 명이 넘습니다. Google은 Terra의 엔지니어링팀과 협력하여 웹사이트의 특정 섹션에 미리 가져오기 기법을 사용하여 기사 로드 시간을 개선했습니다.

이 케이스 스터디에서는 Terra의 여정 구현을 통해 모바일의 광고 클릭률 (CTR)이 11%, 데스크톱의 광고 CTR이 30% 증가하고 최대 콘텐츠 렌더링 시간 (LCP)이 50% 감소한 사례를 설명합니다.

미리 가져오기 전략

프리페칭은 오래 전부터 사용되어 왔지만, 즉시 필요하지 않은 리소스에 추가 대역폭을 소비하므로 주의해서 사용해야 합니다. 이 기법은 불필요한 데이터 사용을 방지하기 위해 신중하게 적용해야 합니다. Terra의 경우 다음 조건이 충족되면 기사가 미리 로드됩니다.

  • 미리 로드된 기사 링크의 가시성: Terra는 Intersection Observer API를 사용하여 미리 로드하려는 기사가 포함된 섹션의 조회가능성을 감지했습니다.
  • 데이터 사용량 증가에 유리한 조건: 앞에서 언급한 바와 같이 prefetching은 추가 데이터를 소비하는 추측 성능 개선이며 모든 상황에서 바람직한 결과가 아닐 수 있습니다. 대역폭 낭비 가능성을 줄이기 위해 Terra는 Device Memory API와 함께 Network Information API를 사용하여 다음 도움말을 가져올지 결정합니다. Terra는 다음과 같은 경우에만 다음 도움말을 가져옵니다.
    • 연결 속도가 3G 이상이고 기기에 메모리가 4GB 이상 있습니다.
    • 또는 기기가 iOS를 실행하는 경우
  • CPU 유휴 상태: 마지막으로 Terra는 CPU가 유휴 상태이고 추가 작업을 실행할 수 있는지 확인합니다. 이를 위해 requestIdleCallback를 사용합니다. 이 함수는 기본 스레드가 유휴 상태일 때 처리할 콜백을 가져오거나 특정(선택사항) 기한(둘 중 먼저 오는 값)을 사용합니다.

이러한 조건을 준수하면 Terra가 필요한 경우에만 데이터를 가져오므로 대역폭과 배터리 수명이 절약되고 사용되지 않는 미리 가져오기의 영향이 최소화됩니다.

이러한 조건이 충족되면 Terra는 아래 파란색으로 강조 표시된 '관련 콘텐츠' 및 '추천' 섹션에 있는 도움말을 미리 로드합니다.

링크가 미리 로드된 Terra 웹사이트의 두 섹션 스크린샷 왼쪽에는 '관련 콘텐츠' 섹션이 강조 표시되어 있고 오른쪽에는 '추천' 섹션이 강조 표시되어 있습니다.

비즈니스 영향

이 기법의 효과를 측정하기 위해 Terra는 먼저 도움말 페이지의 '관련 콘텐츠' 섹션에 이 기능을 출시했습니다. UTM 코드를 사용하면 비교 목적으로 미리 로드된 기사와 미리 로드되지 않은 기사를 구분할 수 있었습니다. 2주간의 A/B 테스트가 성공적으로 끝난 후 Terra는 '추천' 섹션에 미리 로드 기능을 추가하기로 결정했습니다.

기사를 미리 로드한 결과 광고 측정항목이 전반적으로 증가하고 LCP 및 TTFB (Time To First Byte) 시간이 감소했습니다.

측정항목 모바일 데스크톱
광고 CTR +11% +30%
광고 조회가능성 +10.5% +6%
LCP -51% -73%
TTFB -83% -84%

주의해서 사용하면 페이지 로드 시간이 크게 개선되고 광고 측정항목이 증가하며 LCP 시간이 줄어듭니다.

기술 세부정보

prefetching은 rel=prefetch 또는 rel=preload와 같은 리소스 힌트를 사용하거나 quicklink 또는 Guess.js와 같은 라이브러리를 통해 또는 최신 Speculation Rules API를 사용하여 실행할 수 있습니다. Terra는 Intersection Observer 인스턴스와 함께 낮은 우선순위fetch API를 사용하여 이를 구현하기로 했습니다. Terra는 아직 rel=prefetch 또는 Speculation Rules API와 같은 다른 미리 로드 방법을 지원하지 않는 Safari를 지원할 수 있고 Terra의 요구사항에 모든 기능을 갖춘 JavaScript 라이브러리가 필요하지 않았기 때문에 이 방법을 선택했습니다.

아래 JavaScript는 Terra에서 사용하는 코드와 거의 같습니다.

function prefetch(nodeLists) {
  // Exclude slow ECTs < 3g
  if (navigator.connection &&
    (navigator.connection.effectiveType === 'slow-2g'
      || navigator.connection.effectiveType === '2g')
  ) {
    return;
  }

  // Exclude low end device which is device with memory <= 2GB
  if (navigator.deviceMemory && navigator.deviceMemory <= 2) {
    return;
  }

  const fetchLinkList = {};

  const observer = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      if (entry.isIntersecting) {
        if (!fetchLinkList[entry.target.href]) {
          fetchLinkList[entry.target.href] = true;

          fetch(entry.target, {
            priority: 'low'
          });
        }

        observer.unobserve(entry = entry.target);
      }
    });
  });
}

const idleCallback = window.requestIdleCallback || function (cb) {
  let start = Date.now();

  return setTimeout(function () {
    cb({
      didTimeout: false,
      timeRemaining: function () {
        return Math.max(0, 50 - (Date.now() - start));
      }
    });
  }, 1);
}

idleCallback(function () {
  prefetch(nodeLists)
})
  • prefetch 함수는 먼저 최소 연결 품질과 기기 메모리를 확인한 후 미리 가져오기를 시작합니다.
  • 그런 다음 IntersectionObserver를 사용하여 요소가 표시 영역에 표시되는 시점을 모니터링하고 나서 URL을 목록에 추가하여 미리 로드합니다.
  • prefetch 프로세스는 requestIdleCallback로 예약되며, 기본 스레드가 유휴 상태일 때 prefetch 함수를 실행하는 것을 목표로 합니다.

결론

주의해서 사용하면 미리 로드하면 향후 탐색 요청의 로드 시간이 크게 줄어들어 사용자 여정에서 발생하는 불편을 줄이고 참여도를 높일 수 있습니다. 미리 가져오면 사용되지 않을 수도 있는 추가 바이트가 로드되므로 Terra는 이 정보를 사용할 수 있는 양호한 네트워크 상태와 지원되는 기기에서만 미리 가져오도록 추가 단계를 취했습니다.

이 작업에 도움을 주신 Gilberto Cocchi, Harry Theodoulou, Miguel Carlos Martínez Díaz, Barry Pollard, Jeremy Wagner, Terra 엔지니어링팀의 Leonardo Bellini, Lucca Paradeda에게 감사의 인사를 전합니다.