A synchronous third-party script in <head> blocks the browser's HTML parser for the duration of the network request and script execution — stalling everything: layout, rendering, and any other script that follows. A single slow analytics script hosted on an external CDN can delay First Contentful Paint by 500ms–2s if that CDN has any latency. This is entirely under the developer's control: async tells the browser to download the script in parallel and execute it when ready; defer executes after the document is parsed. Neither attribute changes the script's behavior for tracking or analytics purposes.
Medium because each synchronous third-party script adds a hard blocking delay to page rendering, and the delay is entirely controlled by an external CDN with no SLA.
Add async or defer to every external <script> tag. In Next.js, replace manual script tags with the Script component and set strategy="afterInteractive" for analytics or "lazyOnload" for non-critical widgets.
<!-- Before — blocks HTML parsing -->
<script src="https://analytics.example.com/tracker.js"></script>
<!-- After — downloads in parallel, executes after parse -->
<script async src="https://analytics.example.com/tracker.js"></script>
<!-- OR: executes in order after document is parsed -->
<script defer src="https://analytics.example.com/tracker.js"></script>
// Next.js — use Script component in app/layout.tsx
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Script
src="https://analytics.example.com/tracker.js"
strategy="afterInteractive" // loads after page is interactive
/>
</body>
</html>
)
}
ID: performance-load.bundle.third-party-scripts
Severity: medium
What to look for: Count all <script> tags and Next.js Script components that load external URLs (third-party services: analytics, chat widgets, ads, tracking pixels, etc.). For each, classify as: (a) async or defer attribute present, (b) Next.js Script with strategy="afterInteractive" or "lazyOnload", or (c) synchronous (no async/defer, blocking rendering). Enumerate: "X third-party scripts found, Y loaded asynchronously."
Pass criteria: 100% of third-party scripts use async or defer attributes, or Next.js Script component with strategy="afterInteractive" or "lazyOnload". No more than 0 third-party scripts should block rendering. Report: "X of Y third-party scripts load asynchronously."
Fail criteria: 1 or more third-party scripts are loaded synchronously (blocking rendering) without async, defer, or a framework script loading strategy.
Skip (N/A) when: No third-party scripts detected (0 external <script> tags and 0 Script component usages found).
Detail on fail: "1 of 3 third-party scripts blocks rendering — Google Analytics in <head> without async attribute" or "2 of 4 external scripts loaded synchronously — chat widget and tracking pixel in layout.tsx lack defer"
Remediation: Load third-party scripts asynchronously:
<!-- Before — synchronous, blocks rendering -->
<script src="https://analytics.example.com/script.js"></script>
<!-- After — async (recommended) -->
<script async src="https://analytics.example.com/script.js"></script>
For Next.js, use the Script component:
import Script from 'next/script'
export default function Layout() {
return (
<>
<Script
src="https://analytics.example.com/script.js"
strategy="afterInteractive"
/>
</>
)
}