Fix Third Party Scripts in Next.js for Better Core Web Vitals

Fix Core Web Vitals issues caused by third party scripts in Next.js

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-10

Fix third party scripts in Next.js

Third-party scripts are the most common cause of Core Web Vitals failures on otherwise optimized Next.js sites. You have done everything right: optimized images, implemented static generation, inlined critical CSS. But your Interaction to Next Paint still fails. The cause is almost always third-party JavaScript. According to the 2025 Web Almanac, 92% of pages load at least one third-party resource. Scripts make up 24.8% of all third-party requests, more than any other resource type.

Last reviewed by Arjen Karel on March 2026

It might be because of third-party scripts like ads, analytics, social media buttons, widgets, A/B testing scripts, video players and so on.

How third party scripts impact the Core Web Vitals

Third-party scripts can mess up your Core Web Vitals in more ways than you can probably imagine. These are some of the problems I come across on live websites.

  • Slow down the network. Third-party scripts can send multiple requests to multiple servers, download large unoptimized files like images and videos, download frameworks and libraries several times.
  • Third-party JavaScript can block the DOM at any time (or even several times during a page visit), delaying how quickly pages can render and use too much CPU time which can delay user interaction and cause battery drain.
  • Render blocking third-party scripts can be a single point of failure (SPOF).
  • Third-party scripts can cause network issues due to poorly configured HTTP caching, lack of sufficient server compression and slow or outdated HTTP protocols.
  • Harm user experience in many other ways like hiding content, blocking browser events (like the window load event) or using outdated APIs like document.write.

The numbers are sobering. The Chrome Aurora team found that a Google Tag Manager container with 18 tags increases Total Blocking Time nearly 20x. The 2025 Web Almanac reports a mobile median TBT of 1,916 ms, nearly 10x the 200 ms best practice. Third-party scripts are a major contributor to that number.

Fix third-party scripts and Core Web Vitals in Next.js

Ideally, you want to ensure no third-party script impacts the critical rendering path. Your first instinct would be to use the defer or async attribute. Unfortunately, from a timing perspective, this is not a good option for most Next.js sites. A Next.js site relies heavily on JavaScript to hydrate the page.

This means that as soon as the Next.js bundles have downloaded the browser will run that JavaScript. This takes up time and resources. This process will slow down when the browser is too busy compiling and running third-party JavaScript.

The Next.js Script component

The Next.js Script component (next/script) gives you control over when third-party scripts load relative to your application code. Instead of fighting the browser's default loading behavior, you pick a strategy that matches the script's importance.

Import it in any component:

import Script from 'next/script'

Strategy

With next/script, you decide when to load your third-party script by using the strategy property. There are four loading strategies:

  • beforeInteractive: Load a script before the page is interactive
  • afterInteractive: Load a script immediately after the page becomes interactive
  • lazyOnload: Load a script during idle time
  • worker: Load a script in a web worker (experimental, Pages Router only)

beforeInteractive Strategy

Scripts that load with the beforeInteractive strategy are injected into the initial HTML from the server with the defer attribute enabled and run before self-bundled JavaScript is executed.

From a Core Web Vitals perspective this is exactly the type of behavior we would like to avoid! The beforeInteractive strategy should only be used on scripts that are absolutely critical to the page. Third-party scripts are not ever supposed to be critical!

<Script
  id="bootstrap-cdn"
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
  strategy="beforeInteractive"
 />

In this case the bootstrap JavaScript library is added to the generated HTML with the defer attribute just before the Next.js bundles. This means the browser will probably fetch and execute the bootstrap library before the Next.js bundle. This will delay the Next.js hydration and probably block the main thread when the browser should be downloading and running the Next.js chunks. For the Core Web Vitals this means Interaction to Next Paint will probably be affected.

afterInteractive Strategy

Scripts that use the afterInteractive strategy are injected client-side and will download after Next.js hydrates the page.

From a Core Web Vitals perspective this is a much better (but not yet perfect) place to inject third-party scripts. This strategy should be used for scripts that do not need to load as soon as possible and can be fetched and executed immediately after the page is interactive.

<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');
  `,
  }}
/>

For Google Tag Manager and Google Analytics, there is now a better option. See the @next/third-parties section below.

lazyOnload Strategy

With the lazyOnload strategy things are finally becoming interesting! The way I think about third-party scripts is simple: 'they should not be critical to a page'. If you cannot live without a certain third-party script you should probably not rely on a third party.

Scripts that use the lazyOnload strategy are loaded late after all resources have been fetched and during idle time. This means that the third-party script will not interfere with the Next.js chunks and will minimize the impact this script has on Interaction to Next Paint (INP).

<Script
  id="some-chat-script"
  src="https://example.com/chatscript.js"
  strategy="lazyOnload"
 />

worker Strategy

The worker strategy is an experimental feature that uses Partytown to run scripts in a web worker instead of the main thread. The concept is interesting: the Chrome Aurora team measured a 92% TBT reduction when moving GTM to a web worker. But the worker strategy only works with the Pages Router. It does not support the App Router. My advice: stay away from this until either the project matures or the DOM becomes available to web workers.

@next/third-parties: the modern approach

Next.js now provides the @next/third-parties package with optimized components for the most common third-party services. These components handle the loading strategy internally, so you do not need to configure it yourself.

Install it:

npm install @next/third-parties

For Google Tag Manager, add the component to your root layout:

import { GoogleTagManager } from '@next/third-parties/google'

export default function RootLayout({ children }) {
  return (
    <html>
      <GoogleTagManager gtmId="GTM-XXXXXX" />
      <body>{children}</body>
    </html>
  )
}

For Google Analytics:

import { GoogleAnalytics } from '@next/third-parties/google'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <GoogleAnalytics gaId="G-XXXXXX" />
      </body>
    </html>
  )
}

The Chrome Aurora team reports that 66% of Next.js sites use Google Tag Manager and 52% use Google Analytics. If you are loading either of these, use the dedicated components instead of the generic Script component with dangerouslySetInnerHTML. If you use GTM's dataLayer, also see the dataLayer INP yield pattern to prevent push events from blocking interactions.

Which strategy for which script?

  • GTM and GA: Use @next/third-parties components. They handle timing internally.
  • Chat widgets (Intercom, HubSpot, Drift): Use lazyOnload. A chat widget is never critical to the first interaction.
  • A/B testing (Optimizely, VWO): Use beforeInteractive only if the test affects above-the-fold content. Otherwise use afterInteractive.
  • Social embeds and video players: Use lazyOnload.
  • Ad scripts: Use afterInteractive. Ads need to load reasonably quickly for revenue but should not block hydration.

Across Next.js sites monitored by CoreDash, those using lazyOnload for analytics scripts show a median INP improvement of 27ms compared to afterInteractive. That is the difference between passing and failing the INP threshold.

Whichever strategy you choose, verify the results with Real User Monitoring. Lab scores tell you what might happen. Field data tells you what actually happened. And sometimes the best optimization is removing scripts you do not need.

For more on measuring the impact, see the guide on measuring Core Web Vitals in Next.js. If you are also dealing with render blocking CSS in Next.js, fix that first. For a broader look at how the browser decides what to fetch and when, see the resource prioritization guide.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Pinpoint the route, device, and connection that fails.

CoreDash segments every metric by route, device class, browser, and connection type. Real time data. Not the 28 day average Google gives you.

Explore Segmentation
Fix Third Party Scripts in Next.js for Better Core Web VitalsCore Web Vitals Fix Third Party Scripts in Next.js for Better Core Web Vitals