I run a small Next.js site (free browser-based file conversion tools). Yesterday I ran PageSpeed Insights on mobile and got a 69 — "needs improvement," with First Contentful Paint at 4.0s and Largest Contentful Paint at 5.6s under slow-4G throttling. Today it's 96.
The fix took about five minutes once I found the actual cause.
The setup
Like a lot of small sites trying to monetize, I have a Google AdSense script in my root layout. It was added as a plain tag:
<script
async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-xxxxx"
crossOrigin="anonymous"
/>
async looks like it should be enough. It isn't — for what actually matters here.
What PageSpeed was actually flagging
The diagnostics called out "Reduce unused JavaScript — Est. savings of 186 KiB." That's a big number for a lightweight site. The twist: my AdSense account is still pending approval, so the script was loading its full weight and doing nothing — no ads were rendering yet. Pure cost, zero benefit, and it was still competing with my actual page content for parsing priority during initial load.
The fix
Next.js ships a purpose-built <Script> component specifically for this situation, with a strategy prop:
import Script from "next/script";
<Script
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-xxxxx"
strategy="lazyOnload"
crossOrigin="anonymous"
/>
lazyOnload defers loading until the browser is idle, well after your actual content has painted. The script still loads — ads will still work once approved — it just stops competing with your page for the critical early-loading window.
Result
- Performance: 69 → 96
- The 186 KiB "unused JavaScript" flag: gone
- Zero change to how AdSense actually functions
The takeaway
If you're running any third-party script (ads, chat widgets, analytics beyond the basics) as a raw <script> tag in a Next.js app, it's worth auditing. next/script's strategy prop has four options (beforeInteractive, afterInteractive, lazyOnload, worker) and picking the right one for non-critical scripts is close to a free performance win — no functionality lost, no removed features, just better loading priority.
For anything genuinely optional to the initial render — ads, chat bubbles, feedback widgets — lazyOnload is usually the right call.
Top comments (2)
How did you identify the specific script tag causing the issue, was it through PageSpeed's diagnostics or another tool? I've been struggling with similar issues on my own Next.js project.
PageSpeed's diagnostics (pagespeed.web.dev/)