Next.js

Ezoic’s standalone script is designed for traditional multi-page sites. Since Next.js uses client-side navigation, we must manually trigger Ezoic to scan the DOM and cleanup placeholders.

Global Types πŸ”—

Create types/ezoic.d.ts to ensure type safety across your components.

declare global {
    interface Window {
        ezstandalone?: {
        cmd: Array<() => void>;
        showAds: (...ids: number[]) => void;
        destroyPlaceholders: (...ids: number[]) => void;
        };
    }
}
export {};

Global Script Initialization πŸ”—

Add the scripts to app/layout.tsx. Initializing the cmd queue here ensures that any subsequent calls to Ezoic are buffered until the library is fully loaded.

import Script from "next/script";
import EzoicRouteHandler from "@/components/EzoicRouteHandler";

export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
        <html lang="en">
            <head>
                <Script
                    id="ezoic-cmp"
                    src="https://cmp.gatekeeperconsent.com/min.js"
                    strategy="beforeInteractive"
                    data-cfasync="false"
                />
                <Script
                    id="ezoic-cmp-2"
                    src="https://the.gatekeeperconsent.com/cmp.min.js"
                    strategy="beforeInteractive"
                    data-cfasync="false"
                />
                
                <Script
                    id="ezoic-sa"
                    src="//www.ezojs.com/ezoic/sa.min.js"
                    strategy="beforeInteractive"
                />
                
                <Script id="ezoic-init" strategy="beforeInteractive">
                    {`
                    window.ezstandalone = window.ezstandalone || {};
                    window.ezstandalone.cmd = window.ezstandalone.cmd || [];
                    `}
                </Script>

                <Script
                    id="ezoic-analytics"
                    src="//ezoicanalytics.com/analytics.js"
                    strategy="beforeInteractive"
                />
            </head>
            <body>
                <EzoicRouteHandler />
                {children}
            </body>
        </html>
    );
}

runEzoic Helper πŸ”—

Create lib/ezoic.ts. This safely pushes functions to the Ezoic command queue, preventing errors if the script hasn't initialized when a component mounts.

export function runEzoic(fn: () => void) {
    if (typeof window === "undefined") return;
    window.ezstandalone = window.ezstandalone || {};
    window.ezstandalone.cmd = window.ezstandalone.cmd || [];
    window.ezstandalone.cmd.push(fn);
}

Ad Placeholder Component πŸ”—

This component manages the lifecycle of a single ad slot. It ensures the ad is displayed on mount and properly destroyed on unmount.

"use client";

import { useEffect, useState } from "react";
import { runEzoic } from "@/lib/ezoic";

export default function EzoicAd({ id }: { id: number }) {
    const [isRendered, setIsRendered] = useState(false);
    useEffect(() => {
    setIsRendered(true);
    runEzoic(() => {
        window.ezstandalone?.showAds(id);
    });
    return () => {
        runEzoic(() => {
            window.ezstandalone?.destroyPlaceholders(id);
        });
    };
  }, [id]);
  return (
    <div 
        className="ezoic-ad-container" 
    >
        {isRendered && <div id={`ezoic-pub-ad-placeholder-${id}`} />}
    </div>
    );
}

Handling SPA Navigation (App Router) πŸ”—

Create components/EzoicRouteHandler.tsx. Since the page doesn't refresh on route changes, we use usePathname to trigger a re-scan of the page for new ads.

"use client";

import { useEffect } from "react";
import { usePathname } from "next/navigation";
import { runEzoic } from "@/lib/ezoic";

export default function EzoicRouteHandler() {
    const pathname = usePathname();
    useEffect(() => {
    runEzoic(() => {
    requestAnimationFrame(() => {
        window.ezstandalone?.showAds();
    });
});
}, [pathname]);

return null;
}

Pages Router Implementation πŸ”—

For the Pages Router, handle the route events inside _app.tsx.

import { useEffect } from "react";
import { useRouter } from "next/router";
import { runEzoic } from "@/lib/ezoic";

export default function App({ Component, pageProps }) {
    const router = useRouter();
    useEffect(() => {
        const handleRoute = () => {
        runEzoic(() => {
        window.ezstandalone?.showAds();
    });
};

router.events.on("routeChangeComplete", handleRoute);
    return () => router.events.off("routeChangeComplete", handleRoute);
}, [router.events]);

return <Component {...pageProps} />;
}