Back to Blog
Lesson 44 of the Next.js: Build Full-Stack Apps with the App Router course
Next.jsAugust 31, 20264 min read

Integrating Third-Party Scripts in Next.js

Learn how to use next/script to integrate analytics and trackers into your Next.js project without harming your site performance or Core Web Vitals.

Next.jsperformanceweb-vitalsanalyticsscripts

Previously in this course, we built an RSS feed for our blog. Now that our content is discoverable, it's time to understand how users interact with it. In this lesson, we’ll explore how to safely add third-party analytics and trackers to our Next.js application.

Why Standard HTML Scripts Fail

In standard web development, adding a <script> tag is straightforward: you drop it into the <head> or before the closing </body> tag. However, this is dangerous for performance.

Third-party scripts (analytics, chat widgets, ad trackers) are often heavy and execute on the main thread. If you load them improperly, they block the browser from parsing your HTML, rendering your CSS, or responding to user clicks. This often leads to poor Core Web Vitals, specifically impacting your LCP (Largest Contentful Paint) and INP (Interaction to Next Paint). As discussed in our deep dives on Core Web Vitals and INP optimization, we must control when and how these scripts load.

Introducing next/script

Next.js provides the next/script component, which acts as a wrapper around the native HTML <script> tag. It gives us fine-grained control over the loading priority, ensuring that critical content renders before the third-party noise begins.

Strategies for Loading

The strategy prop is the most important part of next/script. It dictates when the script executes:

StrategyDescriptionBest For
beforeInteractiveLoads before the page becomes interactive.Essential bots/cookies.
afterInteractive(Default) Loads as soon as possible after the page is interactive.Analytics and tag managers.
lazyOnloadLoads during idle time.Non-critical widgets (e.g., chat, social feeds).
workerOffloads execution to a Web Worker (experimental).Complex, heavy scripts.

Worked Example: Adding Google Analytics

Let’s add a common analytics script to our blog. We'll place this in our root layout so it tracks every page view.

TSX
// app/layout.tsx
import Script from CE9178">'next/script';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        {/* Analytics Script */}
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"
          strategy="afterInteractive"
        />
        <Script id="google-analytics" strategy="afterInteractive">
          {CE9178">`
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'G-XXXXXXXXXX');
          `}
        </Script>
      </body>
    </html>
  );
}

In this example, we use afterInteractive. This ensures the script doesn't block the initial render of our blog posts, but still fires early enough to capture user data. Notice the use of an inline script block (the second Script component) to initialize the configuration—this is a standard pattern for many marketing tools.

Hands-on Exercise

  1. Identify a third-party service you want to use (e.g., Google Analytics, Plausible, or a simple custom tracking pixel).
  2. Open your app/layout.tsx file.
  3. Import Script from next/script.
  4. Add your script using strategy="afterInteractive". If it's a non-critical widget like a "Buy Me a Coffee" button, try strategy="lazyOnload" to keep your site snappy.
  5. Verify it's working by checking the "Network" tab in your browser's DevTools; you should see the script file loading after the page content.

Common Pitfalls

  • Overloading the site: Just because you can add a script doesn't mean you should. Every script adds latency. Audit your tracking needs periodically.
  • Forgetting the id: When using inline scripts (as shown in the example), Next.js requires an id prop so it can track and optimize the execution of that specific block.
  • Blocking critical renders: Never use beforeInteractive unless the script is absolutely required to render the page (e.g., a bot-detection script or critical security header). For almost everything else, afterInteractive or lazyOnload is safer.

FAQ

Q: Can I use next/script in a Client Component? Yes, but it is best practice to keep tracking scripts in the root layout.js so they aren't re-initialized every time the user navigates.

Q: How do I handle third-party performance issues? If a specific script is still causing issues, check out our guide on third-party script optimization using Partytown to offload execution to a background web worker.

Recap

We’ve learned that third-party scripts are a major source of performance degradation. By using next/script, we can defer non-essential code, protect our main thread, and ensure our blog remains fast. Always prioritize your user's experience over data collection.

Up next: We will learn how to handle multi-language support with Internationalization (i18n).

Similar Posts