더 나은 Core Web Vitals를 위해 Next.js에서 서드파티 스크립트 수정하기
Next.js에서 서드파티 스크립트로 인해 발생하는 Core Web Vitals 문제 해결하기

Next.js에서 서드파티 스크립트 수정하기
서드파티 스크립트는 최적화된 Next.js 사이트에서 Core Web Vitals 실패의 가장 흔한 원인입니다. 이미지 최적화, 정적 생성 구현, 중요한 CSS 인라인 처리 등 모든 것을 올바르게 수행했습니다. 하지만 Interaction to Next Paint는 여전히 실패합니다. 그 원인은 거의 항상 서드파티 JavaScript입니다. 2025 Web Almanac에 따르면 페이지의 92%가 최소 하나의 서드파티 리소스를 로드합니다. 스크립트는 전체 서드파티 요청의 24.8%를 차지하며, 이는 다른 어떤 리소스 유형보다 많은 수치입니다.
최종 검토: 2026년 3월 Arjen Karel

광고, 분석, 소셜 미디어 버튼, 위젯, A/B 테스트 스크립트, 비디오 플레이어 등과 같은 서드파티 스크립트 때문일 수 있습니다.
서드파티 스크립트가 Core Web Vitals에 미치는 영향
서드파티 스크립트는 여러분이 상상하는 것 이상으로 다양한 방식으로 Core Web Vitals를 망칠 수 있습니다. 다음은 라이브 웹사이트에서 제가 마주치는 몇 가지 문제들입니다.
- 네트워크 속도를 늦춥니다. 서드파티 스크립트는 여러 서버에 여러 요청을 보내고, 이미지나 비디오와 같은 크고 최적화되지 않은 파일을 다운로드하며, 프레임워크와 라이브러리를 여러 번 다운로드할 수 있습니다.
- 서드파티 JavaScript는 언제든지(또는 페이지 방문 중 여러 번) DOM을 차단하여 페이지 렌더링 속도를 지연시키고 너무 많은 CPU 시간을 사용하여 사용자 상호 작용을 지연시키고 배터리 소모를 유발할 수 있습니다.
- 렌더링을 차단하는 서드파티 스크립트는 단일 장애점(SPOF)이 될 수 있습니다.
- 서드파티 스크립트는 잘못 구성된 HTTP 캐싱, 서버 압축 부족, 느리거나 오래된 HTTP 프로토콜로 인해 네트워크 문제를 일으킬 수 있습니다.
- 콘텐츠 숨기기, 브라우저 이벤트(예: window 로드 이벤트) 차단, document.write와 같이 오래된 API 사용 등 여러 가지 방식으로 사용자 경험(user experience)을 해칠 수 있습니다.
수치들은 심각성을 보여줍니다. Chrome Aurora 팀의 연구 결과에 따르면 18개의 태그가 있는 Google Tag Manager 컨테이너는 Total Blocking Time을 거의 20배 증가시킵니다. 2025 Web Almanac은 모바일 중간 TBT가 1,916ms라고 보고하며, 이는 모범 사례인 200ms의 거의 10배에 달합니다. 서드파티 스크립트는 이러한 수치에 기여하는 주요 원인입니다.
Next.js에서 서드파티 스크립트 및 Core Web Vitals 수정하기
이상적으로는 서드파티 스크립트가 중요 렌더링 경로에 영향을 미치지 않도록 해야 합니다. 가장 먼저 defer 또는 async 속성을 사용하려고 생각할 수 있습니다. 불행히도 타이밍 관점에서 볼 때 이는 대부분의 Next.js 사이트에 좋은 옵션이 아닙니다. Next.js 사이트는 페이지를 hydrate하기 위해 JavaScript에 크게 의존합니다.
이는 Next.js 번들이 다운로드되는 즉시 브라우저가 해당 JavaScript 실행함을 의미합니다. 이 과정에는 시간과 리소스가 소모됩니다. 브라우저가 서드파티 JavaScript를 컴파일하고 실행하느라 너무 바쁘면 이 프로세스가 느려질 것입니다.
Next.js Script 컴포넌트
Next.js Script 컴포넌트(next/script)를 사용하면 애플리케이션 코드와 관련하여 서드파티 스크립트가 로드되는 시기를 제어할 수 있습니다. 브라우저의 기본 로딩 동작과 씨름하는 대신 스크립트의 중요도에 맞는 전략을 선택할 수 있습니다.
모든 컴포넌트에서 이를 가져옵니다.
import Script from 'next/script'
전략
next/script를 사용하면 strategy 속성을 사용하여 서드파티 스크립트를 로드할 시기를 결정할 수 있습니다. 네 가지 로딩 전략이 있습니다.
- beforeInteractive: 페이지가 상호 작용하기 전에 스크립트 로드
- afterInteractive: 페이지가 상호 작용 가능해진 직후 스크립트 로드
- lazyOnload: 유휴 시간(idle time) 동안 스크립트 로드
- worker: 웹 워커(web worker)에서 스크립트 로드 (실험적 기능, Pages Router 전용)
beforeInteractive 전략
beforeInteractive 전략으로 로드되는 스크립트는 서버에서 제공되는 초기 HTML에 defer 속성이 활성화된 상태로 삽입되며, 자체 번들링된 JavaScript가 실행되기 전에 실행됩니다.
Core Web Vitals 관점에서 볼 때 이는 정확히 우리가 피하고자 하는 유형의 동작입니다! beforeInteractive 전략은 페이지에 절대적으로 중요한 스크립트에만 사용되어야 합니다. 서드파티 스크립트는 결코 중요해서는 안 됩니다!
<Script id="bootstrap-cdn" src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" strategy="beforeInteractive" />
이 경우 bootstrap JavaScript 라이브러리는 Next.js 번들 직전에 생성된 HTML에 defer 속성과 함께 추가됩니다. 즉, 브라우저는 Next.js 번들보다 먼저 bootstrap 라이브러리를 가져와서 실행할 가능성이 높습니다. 이는 Next.js의 hydration을 지연시키고 브라우저가 Next.js 청크(chunks)를 다운로드하고 실행해야 할 때 메인 스레드를 차단할 것입니다. Core Web Vitals의 관점에서 이는 Interaction to Next Paint가 영향을 받을 가능성이 높다는 것을 의미합니다.
afterInteractive 전략
afterInteractive 전략을 사용하는 스크립트는 클라이언트 측에서 삽입되며 Next.js가 페이지를 hydrate한 후에 다운로드됩니다.
Core Web Vitals 관점에서 볼 때 이는 서드파티 스크립트를 삽입하기에 훨씬 더 나은(하지만 아직 완벽하지는 않은) 위치입니다. 이 전략은 가능한 한 빨리 로드될 필요가 없고 페이지가 상호 작용 가능해진 직후에 가져와서 실행할 수 있는 스크립트에 사용되어야 합니다.
<Script
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', 'GTM-XXXXXX');
`,
}}
/>
Google Tag Manager 및 Google Analytics의 경우 이제 더 나은 옵션이 있습니다. 아래의 @next/third-parties 섹션을 참조하세요.
lazyOnload 전략
lazyOnload 전략을 사용하면 마침내 흥미로운 일이 발생합니다! 서드파티 스크립트에 대한 제 생각은 간단합니다. '페이지에 중요해서는 안 된다'는 것입니다. 특정 서드파티 스크립트 없이는 작동할 수 없다면, 애초에 서드파티에 의존하지 말아야 합니다.
lazyOnload 전략을 사용하는 스크립트는 모든 리소스를 가져온 후 유휴 시간(idle time) 동안 늦게 로드됩니다. 이는 서드파티 스크립트가 Next.js 청크(chunks)를 방해하지 않으며 이 스크립트가 Interaction to Next Paint (INP)에 미치는 영향을 최소화함을 의미합니다.
<Script id="some-chat-script" src="https://example.com/chatscript.js" strategy="lazyOnload" />
worker 전략
worker 전략은 Partytown을 사용하여 메인 스레드 대신 웹 워커(web worker)에서 스크립트를 실행하는 실험적 기능입니다. 개념은 흥미롭습니다. Chrome Aurora 팀의 측정 결과 GTM을 웹 워커로 옮겼을 때 TBT가 92% 감소했습니다. 하지만 worker 전략은 Pages Router에서만 작동합니다. App Router를 지원하지 않습니다. 제 조언은 이 프로젝트가 성숙해지거나 웹 워커에서 DOM을 사용할 수 있게 될 때까지는 이 전략을 피하라는 것입니다.
@next/third-parties: 최신 접근 방식
Next.js는 이제 가장 일반적인 서드파티 서비스를 위해 최적화된 컴포넌트를 포함하는 @next/third-parties 패키지를 제공합니다. 이 컴포넌트들은 내부적으로 로딩 전략을 처리하므로 직접 구성할 필요가 없습니다.
다음과 같이 설치합니다.
npm install @next/third-parties
Google Tag Manager의 경우, 루트 레이아웃에 컴포넌트를 추가합니다.
import { GoogleTagManager } from '@next/third-parties/google'
export default function RootLayout({ children }) {
return (
<html>
<GoogleTagManager gtmId="GTM-XXXXXX" />
<body>{children}</body>
</html>
)
}
Google Analytics의 경우:
import { GoogleAnalytics } from '@next/third-parties/google'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<GoogleAnalytics gaId="G-XXXXXX" />
</body>
</html>
)
}
Chrome Aurora 팀은 Next.js 사이트의 66%가 Google Tag Manager를 사용하고 52%가 Google Analytics를 사용한다고 보고합니다. 이 둘 중 하나라도 로드하는 경우 dangerouslySetInnerHTML이 있는 일반적인 Script 컴포넌트 대신 전용 컴포넌트를 사용하세요. GTM의 dataLayer를 사용하는 경우 푸시 이벤트가 상호 작용을 차단하지 않도록 dataLayer INP yield 패턴도 확인하세요.
어떤 스크립트에 어떤 전략을 사용해야 할까요?
- GTM 및 GA: @next/third-parties 컴포넌트를 사용하세요. 이 컴포넌트들이 내부적으로 타이밍을 처리합니다.
- 채팅 위젯 (Intercom, HubSpot, Drift):
lazyOnload를 사용하세요. 채팅 위젯은 첫 번째 상호 작용에 결코 중요하지 않습니다. - A/B 테스트 (Optimizely, VWO): 테스트가 스크롤 없이 볼 수 있는 영역(above-the-fold) 콘텐츠에 영향을 미치는 경우에만
beforeInteractive를 사용하세요. 그렇지 않으면afterInteractive를 사용하세요. - 소셜 임베드 및 비디오 플레이어:
lazyOnload를 사용하세요. - 광고 스크립트:
afterInteractive를 사용하세요. 광고는 수익을 위해 적당히 빨리 로드되어야 하지만 hydration을 차단해서는 안 됩니다.
CoreDash에서 모니터링하는 Next.js 사이트 중 분석 스크립트에 lazyOnload를 사용하는 사이트는 afterInteractive를 사용하는 사이트에 비해 중간 INP가 27ms 개선된 것을 보여줍니다. 이는 INP 임계값 통과와 실패 사이의 차이입니다.
어떤 전략을 선택하든 Real User Monitoring을 통해 결과를 확인하세요. 랩(Lab) 점수는 어떤 일이 일어날지 알려줍니다. 필드(Field) 데이터는 실제로 어떤 일이 일어났는지 알려줍니다. 그리고 때로는 최고의 최적화가 필요하지 않은 스크립트를 제거하는 것입니다.
영향을 측정하는 방법에 대한 자세한 내용은 Next.js에서 Core Web Vitals 측정 가이드를 참조하세요. 만약 Next.js에서 렌더링 차단 CSS 문제도 다루고 있다면, 그것부터 먼저 수정하세요. 브라우저가 무엇을 언제 가져올지 결정하는 방법에 대해 더 폭넓게 알아보려면 리소스 우선순위 가이드를 참조하세요.

