Installing Optimize on Next.js
Next.js routes on the client, so Optimize needs to refresh on each navigation. Setup differs between the App Router and the Pages Router.
Replace yourWebsiteName.js in the examples below with the script URL shown on your ad tag page in the BuySellAds dashboard.
Next.js with App Router
1. Load the scripts from your root layout
Add two <Script> tags to app/layout.js as siblings of <body>. The OptimizeBody import is created in the next step.
import Script from 'next/script'
import OptimizeBody from '@/components/OptimizeBody'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<OptimizeBody />
</body>
<Script id="bsaOptimizeQueue" strategy="beforeInteractive">
{`window.optimize = window.optimize || { queue: [] };`}
</Script>
<Script
id="bsaOptimizeScript"
strategy="afterInteractive"
// Cache-bust rounded to a 10-minute window
src={`https://cdn4.buysellads.net/pub/yourWebsiteName.js?${new Date() - (new Date() % 600000)}`}
/>
</html>
)
}
2. Create the OptimizeBody client component
Calls pushAll() on every route change. Marked 'use client' because usePathname() only runs in the browser.
'use client'
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
const OptimizeBody = () => {
const pathName = usePathname()
useEffect(() => {
window.optimize.queue.push(() => {
window.optimize.pushAll()
})
}, [pathName])
return <div data-optimize="shadow-container"></div>
}
export default OptimizeBody
The shadow-container div is required — Optimize uses it to render hidden ad slots. Queued callbacks run as soon as the loader is ready, so queue.push() is safe to call before the script finishes downloading.
3. Verify
- Network tab shows the Optimize script returning
200. window.optimizeandwindow.optimize.queueare defined in the console.- Ads refresh on each navigation without errors.
Next.js with Pages Router
1. Create the Optimize helper
Add components/Optimize.js. It injects the loader script on first call, then queues a refresh on every call after.
const init = (config = {}) => {
window.optimize = window.optimize || { queue: [] }
if (!config.src) {
throw new Error(
"The script 'src' property must be provided in the configuration."
)
}
window.optimize.src = config.src
}
const loadScript = () => {
const existingScript = document.getElementById('bsaOptimizeScriptID')
if (!existingScript) {
const bsa_optimize = document.createElement('script')
bsa_optimize.id = 'bsaOptimizeScriptID'
bsa_optimize.type = 'text/javascript'
bsa_optimize.async = true
bsa_optimize.src =
window.optimize.src + '?' + (new Date() - (new Date() % 600000))
bsa_optimize.onerror = () => {
console.error(`Failed to load script: ${window.optimize.src}`)
}
;(
document.getElementsByTagName('head')[0] ||
document.getElementsByTagName('body')[0]
).appendChild(bsa_optimize)
}
}
export const pushAll = (config) => {
init(config)
loadScript()
window.optimize.queue.push(() => {
window.optimize.pushAll()
})
}
2. Call it from _app.js
Subscribe to routeChangeComplete. The initial call handles the first page load; the listener covers every navigation after.
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import * as Optimize from '@/components/Optimize'
export default function App({ Component, pageProps }) {
const router = useRouter()
useEffect(() => {
const onRouteChangeComplete = () => {
Optimize.pushAll({ src: 'https://cdn4.buysellads.net/pub/yourWebsite.js' })
}
onRouteChangeComplete()
router.events.on('routeChangeComplete', onRouteChangeComplete)
return () => {
router.events.off('routeChangeComplete', onRouteChangeComplete)
}
}, [router.events])
return <Component {...pageProps} />
}
Queued callbacks run as soon as the loader is ready, so pushAll() is safe to call before the script finishes downloading.
3. Verify
- Network tab shows the Optimize script returning
200. window.optimizeis defined in the console.- Each client-side navigation triggers
onRouteChangeComplete(add a temporaryconsole.logto confirm).