Next.js
Use Next.js’s own <Script> component so the pixel loads once and survives client-side
navigation.
App Router
Section titled “App Router”Add it to your root layout, app/layout.tsx:
import Script from 'next/script'
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> {children} <Script src="https://10.vidstats.top/js/p.js?s=YOUR_TAG_KEY" strategy="afterInteractive" /> </body> </html> )}strategy="afterInteractive" is the equivalent of defer: the script runs after hydration
and never blocks your render.
Pages Router
Section titled “Pages Router”Add it to pages/_app.tsx:
import Script from 'next/script'import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) { return ( <> <Component {...pageProps} /> <Script src="https://10.vidstats.top/js/p.js?s=YOUR_TAG_KEY" strategy="afterInteractive" /> </> )}Route changes
Section titled “Route changes”Both routers navigate through history.pushState, which the pixel watches, so route changes
are recorded as pageviews with no extra code.
Add the fallback below only if navigations are missing from your reports.
'use client'import { usePathname, useSearchParams } from 'next/navigation'import { useEffect } from 'react'
export function PageviewTracker() { const pathname = usePathname() const searchParams = useSearchParams()
useEffect(() => { window.webstats && webstats('pageview') }, [pathname, searchParams])
return null}Mount it inside a <Suspense> boundary. useSearchParams opts the component into
client-side rendering, and Next.js will fail the build without one:
import { Suspense } from 'react'import { PageviewTracker } from './_components/PageviewTracker'
export default function RootLayout({ children }) { return ( <html lang="en"> <body> {children} <Suspense> <PageviewTracker /> </Suspense> <Script src="https://10.vidstats.top/js/p.js?s=YOUR_TAG_KEY" strategy="afterInteractive" /> </body> </html> )}Calling webstats() from a component
Section titled “Calling webstats() from a component”afterInteractive can load the pixel after your components first render, so a content call
on mount could miss. If you call webstats() from components, load the pixel with
strategy="beforeInteractive" so window.webstats exists before they render:
<Script src="https://10.vidstats.top/js/p.js?s=YOUR_TAG_KEY" strategy="beforeInteractive"/>Then call it from any client component, no queue stub needed:
'use client'import { useEffect } from 'react'
export function VideoPlayer({ movie }) { useEffect(() => { webstats('content', { type: 'movie', ids: { tmdb: String(movie.tmdbId) }, title: movie.title, }) webstats('video', '#player', { id: `tmdb-${movie.tmdbId}`, title: movie.title }) }, [movie.tmdbId])
return <video id="player" src={movie.streamUrl} />}Verify
Section titled “Verify”Run your app, load a page, then navigate to a second route without reloading. Both should
appear in your dashboard within a few seconds. If only the first one does, add the
PageviewTracker fallback above.