완벽한 Core Web Vitals를 갖춘 채팅 위젯
PageSpeed 저하 없이 채팅 위젯 로드하기

채팅 위젯을 올바르게 로드하는 방법
저는 여러 번 반복해서 말씀드렸습니다. 어떤 스크립트는 다른 스크립트보다 더 중요합니다. 인터넷 역사상 페이지 로드의 처음 500ms(페이지가 아직 비어 있는 시간) 동안 채팅 위젯이 로드되지 않았다고 짜증을 낸 사람은 아무도 없습니다.
페이지의 주요 콘텐츠가 로드되기도 전에 채팅 위젯을 로드하는 것은 말이 안 되겠죠? 가장 중요한 부분(로고, 기본 이미지, 스타일시트, 글꼴, 그리고 네비게이션과 전환을 처리하는 매우 중요한 스크립트 등)을 먼저 로드하는 것이 훨씬 더 타당할 것입니다.
연구에 따르면 세션 중에 채팅 위젯을 실제로 사용하는 방문자는 3~10%에 불과합니다. 채팅 스크립트를 지연시키는 것은 user experience 측면에서 잃는 것이 없지만 페이지 속도 측면에서는 모든 것을 얻을 수 있습니다.
안타깝게도 대부분의 웹사이트는 이런 방식으로 작동하지 않습니다. 저는 매일 (채팅 스크립트와 같은) 중요하지 않은 스크립트가 페이지 로드 시작 시 가장 높은 우선순위로 즉시 로드되는 것을 봅니다.
이 글에서는 채팅 스크립트를 올바르게 로드하는 방법과 이것이 Largest Contentful Paint 및 Interaction to Next Paint와 같은 중요한 메트릭에 어떤 영향을 미치는지 설명하겠습니다.
마지막 검토: Arjen Karel (2026년 2월)
Table of Contents!
배경: 채팅 위젯의 작동 방식
채팅 위젯은 일반적으로 페이지에 작은 스크립트를 로드하여 작동합니다. 이 스크립트는 몇 가지 스타일을 로드하고 페이지에 iframe을 주입합니다. iframe은 웹페이지 내의 작고 고립된 웹페이지입니다. 그리고 이 iframe은 고객과 채팅하는 데 필요한 모든 것을 처리합니다.
채팅 위젯은 Core Web Vitals에 어떤 영향을 미칠까요?
채팅 위젯은 몇 가지 방식으로 Core Web Vitals에 영향을 미칩니다.
1. 초기 네트워크 리소스를 두고 경쟁하여 First Contentful Paint와 Largest Contentful Paint에 영향을 미칩니다.
2. 메인 스레드를 차단하고 때로는 상호작용 후 느리게 업데이트함으로써 Interaction to Next Paint에 영향을 미칩니다.
3. 페이지에서 올바르게 렌더링되지 않으면 layout shifts를 유발할 수 있습니다.
그 영향은 제공업체에 따라 크게 다릅니다. 가장 무거운 채팅 위젯(Zendesk, Tawk.to)은 500~750KB의 JavaScript를 로드합니다. Zoho Desk 및 Crisp와 같은 더 가벼운 대안은 155KB 미만을 유지합니다. 평균적으로 채팅 위젯은 300~600ms의 메인 스레드 차단 시간을 추가합니다. 이는 통과할 수 있었던 INP 점수를 "개선 필요(needs improvement)" 범위로 밀어넣기에 충분한 수치입니다.
채팅 위젯으로 인한 Largest Contentful Paint 문제
채팅 위젯이 네트워크 리소스를 두고 경쟁할 때 Core Web Vitals에 영향을 미칠 수 있습니다. JavaScript 파일은 보통 이미지보다 먼저 다운로드 대기열에 추가됩니다. 이는 최악의 시나리오(채팅 스크립트가 렌더링을 차단하는 경우)에서 브라우저가 다른 작업을 계속하기 전에 채팅 스크립트가 다운로드되고 실행될 때까지 기다려야 함을 의미합니다. 렌더링을 차단하는 채팅 위젯은 First Contentful Paint를 1.0초에서 2.3초 이상으로 두 배까지 늘릴 수 있습니다.
채팅 스크립트가 지연(deferred)되더라도 여전히 몇 가지 방식으로 페인트 메트릭에 영향을 미칠 수 있습니다. 먼저 지연된 스크립트가 무엇을 하는지 설명하겠습니다. 브라우저는 지연된 스크립트를 병렬로 다운로드할 수 있으며 DOMContentLoaded 이벤트가 발생할 때까지 렌더링을 계속할 수 있습니다. 그 이후에 스크립트를 실행합니다. 문제는 재방문자의 경우 DOMContentLoaded 이벤트 시점에 LCP 요소가 아마 로드되지 않은 상태에서 (캐시된) 채팅 스크립트가 실행되어 LCP 메트릭에 지연을 일으킨다는 것입니다.
채팅 위젯으로 인한 Interaction to Next Paint (INP) 문제
채팅 위젯은 2가지 방식으로 Interaction to Next Paint에 영향을 미칠 수 있으며, 실제로 그렇게 됩니다. 첫 번째는 채팅 위젯이 스크립트를 실행하거나 업데이트를 확인하는 동안 짧은 시간 동안 메인 스레드를 차단하는 방식입니다. 이것은 그저 작동 방식일 뿐입니다. 페이지에 추가하는 모든 것은 페이지를 약간 느리게 만듭니다.
INP 문제를 일으키는 두 번째 원인은 잘못된 코딩입니다(장담하건대 엉망으로 코딩된 채팅 위젯들이 시중에 꽤 있습니다). 채팅 위젯에 있어서 "더 인기가 많다"는 것이 "더 잘 코딩되었다"는 의미는 아닙니다. 불량한 코드가 프레젠테이션을 업데이트하는 데 오랜 시간이 걸리면 당연히 INP 문제가 발생합니다. 일부 채팅 제공업체들은 분발할 필요가 있습니다. 안타깝게도 이 부분은 제가 통제할 수 없습니다. 여러분이 코딩이 엉망인 채팅 위젯을 선택했다면 제가 그 코드를 더 낫게 만들 방법은 없습니다.
채팅 위젯으로 인한 레이아웃 시프트 (CLS) 문제
때때로 채팅 위젯은 layout shift를 유발합니다. 제가 채팅 위젯과 관련된 레이아웃 시프트를 확인할 때 주로 살펴보는 3가지 원인이 있습니다.
- 채팅이 로드될 때마다 발생하는 레이아웃 시프트
- 지연된 "채팅 열기" 시 발생하는 레이아웃 시프트
- 채팅 기록이 로드될 때 발생하는 레이아웃 시프트 (채팅 재방문자)
채팅 스크립트로 인한 Core Web Vitals 문제 해결 방법
다행히도 채팅 위젯이 페인트 메트릭(LCP 및 FCP)과 Interaction to Next Paint (INP)의 일부에 미치는 영향을 최소화하는 것은 꽤 쉽습니다. 서두에서 말씀드렸듯이 스크립트에는 각자의 시간과 장소가 있습니다. 그리고 채팅 스크립트의 경우 "무슨 수를 써서라도 즉시"가 아닙니다. 저는 페이지가 사용자 입력에 응답하지 않을 때인 load 이벤트 이후에 채팅 스크립트를 로드하는 것을 선호하며, 네트워크 경쟁을 피하기 위해 프리로드 스캐너를 우회하는 것도 좋아합니다.
그렇다면 어떻게 해야 할까요? 우리는 load 이벤트를 사용합니다. 왜냐하면 load 이벤트가 발생했을 때는 LCP 요소가 페이지에 이미 그려진 상태이기 때문입니다(JavaScript로 지연 로드하지 않은 경우). 브라우저가 사용자 입력에 응답하지 않는 유휴 상태를 기다리기 위해 requestIdleCallback을 사용합니다. 그리고 프리로드 스캐너가 스크립트 src를 즉시 인식하여 조기 다운로드를 유발하지 않도록(이것이 바로 우리가 피하고자 하는 것입니다) JavaScript를 사용하여 채팅 스크립트를 주입합니다. 이는 YouTube 삽입 및 Google Maps에 사용되는 것과 동일한 스크립트 지연 패턴입니다.
<script>
window.addEventListener('load', function(){
requestIdleCallback(function(){
var s = document.createElement('script');
s.src = 'https://your-chat-widget-url.com/chat.js';
document.body.appendChild(s);
})
})
</script>
Safari에서는 requestIdleCallback이 지원되지 않는다는 점에 유의하세요. fallback을 사용하십시오: const idle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1)); 그리고 위 예제에서 requestIdleCallback을 idle로 바꾸면 됩니다.
이 load 이벤트와 requestIdleCallback 패턴을 결합하면 채팅 위젯이 Lighthouse 점수에 미치는 영향이 9~16점에서 0~1점으로 떨어집니다.
대안: 상호작용 기반 로딩
load 이벤트 후에 채팅 위젯을 자동으로 로드하는 대신, 방문자가 실제로 페이지와 상호작용할 때까지 기다릴 수 있습니다. mousemove, scroll 또는 touchstart를 수신하고 첫 번째 이벤트에서 채팅 스크립트를 로드하세요. 이렇게 하면 스크롤이나 상호작용을 전혀 하지 않는 방문자에 대해 모든 Core Web Vitals에 미치는 영향이 0이 됨을 보장합니다.
<script>
function loadChat() {
var s = document.createElement('script');
s.src = 'https://your-chat-widget-url.com/chat.js';
document.body.appendChild(s);
['mousemove','scroll','touchstart'].forEach(function(e){
document.removeEventListener(e, loadChat);
});
}
['mousemove','scroll','touchstart'].forEach(function(e){
document.addEventListener(e, loadChat, {once: true});
});
</script>
채팅 위젯으로 인한 Cumulative Layout Shift 문제 해결
채팅 위젯은 일반적으로 작은 규모의 레이아웃 시프트를 유발합니다. 그것이 큰 문제가 될 필요는 없습니다. 하지만 때때로 채팅 위젯은 렌더링 품질이 떨어질 수 있습니다. 다행히도 위젯 렌더링이 완료될 때까지 그 떨어지는 렌더링을 숨김으로써 이 문제도 (어느 정도) 해결할 수 있습니다.
이를 위해서는 채팅 위젯의 문서를 읽어야 합니다(다양한 채팅 제공업체가 있으며 모두 작동 방식이 조금씩 다릅니다). 문서에서 채팅 렌더링의 다양한 단계에서 호출되는 콜백 함수를 찾으세요. 여러분이 어떤 채팅 위젯을 사용하는지 모르기 때문에, 메커니즘을 설명하기 위해 chat.ready() 함수를 예로 사용하겠습니다.
이제 스마트한 스타일링을 통해 CSS opacity 속성으로 채팅을 숨기거나 나타나게 할 수 있습니다. 먼저 기본적으로 채팅 위젯을 숨기는 몇 가지 클래스를 추가합니다(채팅 위젯에 맞게 선택자를 변경하세요). 그런 다음 chat.ready() 콜백에서 body 클래스 목록에 "showchat"을 추가하여 채팅을 다시 표시하는 두 번째 CSS 줄을 활성화합니다.
<style>
/*hide chat widget by default*/
.chatwidget{opacity:0}
/*show chat widget after .showchat body class*/
body.showchat .chatwidget {opacity:1}
</style>
<script>
chat.ready(function(){
document.documentElement.classList.add('showchat');
})
</script>
이게 전부입니다! 채팅 위젯의 속도를 성공적으로 높이길 바랍니다. 실제 방문자를 대상으로 변경 사항을 확인하려면 Real User Monitoring을 설정하세요. 실험실(Lab) 점수는 디버깅에 유용하지만, Google이 순위를 매기는 데 사용하는 것은 실제 사용자의 현장(Field) 데이터입니다.

