Get AdSense Ads to Reload on Route Change in Next JS

Viewed 559

We've implemented Google AdSense on our Next.JS website, but we'd like to have ads reload whenever the route changes.

Here is what I tried:

const AdBlock = props => {
  const { userLoaded, currentUserIsSilverPlus } = useAuth()

  useEffect(() => {
    window.adsbygoogle = window.adsbygoogle || []
    window.adsbygoogle.push({})
  }, [])

  const reloadAds = () => {
    const { googletag } = window
    if (googletag) {
      googletag.cmd.push(function () {
        googletag.pubads().refresh()
      })
    }
  }

  Router.events.on("routeChangeStart", reloadAds)

  if (userLoaded && !currentUserIsSilverPlus) {
    return (
      <ins
        className="adsbygoogle adbanner-customize"
        style={{ display: "block" }}
        data-ad-client="ca-pub-1702181491157560"
        data-ad-slot={props.slot}
        data-ad-format={props.format}
        data-full-width-responsive={props.responsive}
      />
    )
  }
  return ""
}

export default AdBlock

The ads load, however, they never appear to refresh. What am I missing?

2 Answers

try useRouter hook and handling router events inside useEffect:

import { useRouter } from 'next/router'

export default function Page() {
const router = useRouter();
useEffect(() => {
router.events.on('routeChangeError', handleChange)
  }, [])
  return (
    <>
    </>
  )
}

My solution was to observe router event changes, when routeChangeStart ads had to be unmounted, when routeChangeComplete they had to be mounted remounted.

// components/Adsense.tsx

function Ads() {
  const adsRef = useRef<HTMLModElement | null>(null);

  useEffect(() => {
    const executeWindowAds = () => {
      try {
        // @ts-ignore
        (adsbygoogle = window.adsbygoogle || []).push({});
      } catch (error: any) {
        console.error('error ads======>', error.message);
      }
    };

    const insHasChildren = adsRef.current?.childNodes.length;
    if (!insHasChildren) {
      executeWindowAds();
    }
  }, []);

  return (
      <ins
        ref={adsRef}
        className="adsbygoogle"
        style={{ display: 'block' }}
        data-ad-client="ca-pub-xxx"
        data-ad-slot="xxx"
        data-ad-format="auto"
        data-full-width-responsive="true"
      ></ins>
  );
}

export default function Adsense() {
  const router = useRouter();
  const [shouldMount, setShouldMount] = useState(true);

  useEffect(() => {
    const onRouteChangeStart = () => setShouldMount(false);
    const onRouteChangeComplete = () => setShouldMount(true);

    router.events.on('routeChangeStart', onRouteChangeStart);
    router.events.on('routeChangeComplete', onRouteChangeComplete);

    return () => {
      router.events.off('routeChangeStart', onRouteChangeStart);
      router.events.off('routeChangeComplete', onRouteChangeComplete);
    };
  }, [router.events]);

  return shouldMount ? <Ads /> : null;
}

On your layout page, for example a sidebar where each page has the same sidebar:

// components/LayoutBlogPost.tsx

import dynamic from 'next/dynamic';
const Adsense = dynamic(() => import('./Adsense'), { ssr: false });

export default function LayoutBlogPost({children}: {children: any}) {
  return (
    <div>
      {children}
      <Adsense />
    </div>
  );
}

Related