How to add a third-party script to a Next.js app
In the App Router, a script that should load on every route goes in the root layout, through the Script component from next/script. Next.js loads it once and keeps it across client-side navigation. That second part is where most surprises come from.
Before you start
- A Next.js app on the App Router, with a root layout at app/layout.tsx
- The script’s URL and any data attributes your tool asks for
- A way to deploy the app
Steps
- Import Script in the root layoutOpen app/layout.tsx and import the component from next/script. Next.js’s docs name the root layout as the place for a script that all routes need.
import Script from 'next/script'; - Add the Script elementPut it inside the layout’s returned markup. Attributes the component does not recognise, including data-* attributes, are forwarded to the final script element, so a tool’s site id can stay as an attribute.
import Script from 'next/script'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> {children} <Script src="https://example.com/tool.js" data-site="YOUR_SITE_ID" /> </body> </html> ); }app/layout.tsx. Swap in your tool’s URL and attributes. - Leave the strategy at its defaultWith no strategy prop the script uses afterInteractive: it is injected into the HTML client-side and loads after some or all of hydration. That suits analytics, chat and most other tools.beforeInteractive is reserved for critical scripts, and the worker strategy does not work with the App Router.
- DeployShip the change. The script now loads on the first route a visitor opens and stays loaded as they move around.
Check it worked
- Load any route with developer tools open and find the script’s request in the Network tab.
- Inspect the DOM in the Elements panel and confirm the script element carries your data attributes.
- Click through to another route. The Network tab should show no second request for the script.
What goes wrong
- The tool only sees the first page
- Next.js loads the script once, even as a user navigates between pages, so it never re-runs on a route change. A tool that waits for a full page load needs to watch client-side navigation itself. Check its docs for single-page app support.
- The tag is missing from view source
- An afterInteractive script is injected in the browser, so do not rely on the server HTML to confirm the install. Use the Elements panel and the Network tab.
- A script’s change to the page gets undone
- If the script edits elements that React rendered, a later re-render of that component can put the original markup back. Test the pages where the tool changes content, including after interacting with them.
- Someone set strategy="worker"
- That strategy does not work with the App Router. Remove the prop and let the default apply.
Checked on 2026-11-11 against Next.js Docs: How to load and optimize scripts, Next.js Docs: Script component.
Increase conversions on your Next.js site by 20%
Dynamite personalizes the page for every visitor. Dynamite personalizes a Next.js site from one Script element in the root layout, with the site id as a data attribute. It watches client-side route changes itself and asks for a fresh decision on each route.
Dynamite for Next.jsQuestions
Where do I put a script that should load on every page in Next.js?
In the root layout, app/layout.tsx, using the Script component from next/script.
Does next/script reload the script on every navigation?
No. Next.js loads it once, even when a user navigates between multiple pages.
How do I remove the script?
Delete the Script element from the layout and redeploy.