doganddev
Accueil Blog Boutique

Intégrer Google AdSense dans une app Next.js (App Router)

DOG&DEV · 25/01/2025

Cloud Licence Logicielle
Intégrer Google AdSense dans une app Next.js (App Router)

Intégrer Google AdSense dans une app Next.js (App Router)

Google AdSense permet d’afficher des annonces sur un site et de monétiser le trafic. Dans Next.js 15 avec App Router, l’intégration repose sur le composant Script de Next, un composant global chargé dans le layout, et des blocs d’annonces (AdUnit) réutilisables. Ce guide décrit une mise en place type : chargement conditionnel en prod, formats (auto, rectangle, horizontal, vertical) et rafraîchissement des annonces lors de la navigation.

Prérequis

  • Projet Next.js 15 (App Router)
  • Compte Google AdSense et site vérifié
  • Identifiant client AdSense (ca-pub-XXXXXXXXXXXXXXXX) et slots (identifiants d’emplacement)

1. Composant global AdSense (Script)

Le script AdSense ne doit en général être chargé qu’en production et une seule fois (dans le layout).

Exemple : components/GoogleAdSense.tsx

import Script from 'next/script';

const isProd = process.env.NODE_ENV === 'production';
const clientId = process.env.NEXT_PUBLIC_ADSENSE_CLIENT_ID;

export function GoogleAdSense() {
  if (!isProd || !clientId) return null;

  return (
    <Script
      async
      src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${clientId}`}
      crossOrigin="anonymous"
      strategy="afterInteractive"
    />
  );
}

Layout (app/layout.tsx) :

import { GoogleAdSense } from '@/components/GoogleAdSense';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="fr">
      <head>
        <GoogleAdSense />
      </head>
      <body>{children}</body>
    </html>
  );
}

Variables d’environnement : NEXT_PUBLIC_ADSENSE_CLIENT_ID=ca-pub-XXXXXXXXXXXXXXXX (préfixe NEXT_PUBLIC_ pour exposition côté client).

2. Composant AdUnit réutilisable

Pour afficher des blocs d’annonces (format auto, rectangle, horizontal, vertical), on crée un composant AdUnit qui rend un <ins class="adsbygoogle"> et déclenche (adsbygoogle = window.adsbygoogle || []).push({}) après le mount et à chaque changement de route (pour recharger les annonces en SPA).

Exemple simplifié : components/AdUnit.tsx

'use client';

import { usePathname } from 'next/navigation';
import { useEffect, useRef } from 'react';

declare global {
  interface Window {
    adsbygoogle: unknown[];
  }
}

const formatStyles: Record<string, React.CSSProperties> = {
  auto: { display: 'block' },
  fluid: { display: 'block' },
  rectangle: { display: 'inline-block', width: 300, height: 250 },
  horizontal: { display: 'inline-block', width: 728, height: 90 },
  vertical: { display: 'inline-block', width: 160, height: 600 },
};

interface AdUnitProps {
  adSlot: string;
  adFormat?: 'auto' | 'fluid' | 'rectangle' | 'horizontal' | 'vertical';
  style?: React.CSSProperties;
}

export function AdUnit({ adSlot, adFormat = 'auto', style = {} }: AdUnitProps) {
  const pathname = usePathname();
  const adRef = useRef<HTMLModElement>(null);

  const pushAd = () => {
    try {
      if (typeof window !== 'undefined' && window.adsbygoogle) {
        window.adsbygoogle.push({});
      }
    } catch (e) {
      if (process.env.NODE_ENV === 'development') console.error('AdSense push error', e);
    }
  };

  useEffect(() => {
    pushAd();
  }, [pathname]); // Re-push à chaque changement de page

  return (
    <div className="ad-container my-4">
      <ins
        ref={adRef}
        className="adsbygoogle"
        style={{ ...formatStyles[adFormat], ...style }}
        data-ad-client={process.env.NEXT_PUBLIC_ADSENSE_CLIENT_ID}
        data-ad-slot={adSlot}
        data-ad-format={adFormat}
        data-full-width-responsive="true"
      />
    </div>
  );
}

Props :

  • adSlot : identifiant du bloc dans AdSense.
  • adFormat : auto (responsive), rectangle (300×250), horizontal (728×90), vertical (160×600).

3. Utilisation dans les pages

Au-dessus du contenu (above the fold) :

import { AdUnit } from '@/components/AdUnit';

export default function MainPage() {
  return (
    <main>
      <AdUnit adSlot="1234567890" adFormat="horizontal" style={{ marginBottom: 20 }} />
      <section>
        <h1>Bienvenue</h1>
        <p>Contenu…</p>
      </section>
    </main>
  );
}

Dans un article :

<article>
  <h2>Titre</h2>
  <p>Paragraphe…</p>
  <AdUnit adSlot="1234567891" adFormat="rectangle" style={{ margin: '20px 0' }} />
  <p>Suite…</p>
</article>

Barre latérale :

<aside>
  <h2>Liens</h2>
  <AdUnit adSlot="1234567892" adFormat="vertical" style={{ marginTop: 20 }} />
</aside>

4. Test et bonnes pratiques

  • Les annonces ne s’affichent en général qu’en production (ou sur un domaine autorisé dans AdSense). Tester après déploiement.
  • Densité : respecter les règles AdSense (nombre de blocs par page, espacement).
  • Performance : strategy="afterInteractive" pour ne pas bloquer le First Contentful Paint ; placer les blocs sans nuire au Core Web Vitals.

Dépannage

Symptôme Piste Correctif
Blocs vides Domaine non approuvé ou script non chargé Vérifier AdSense, NEXT_PUBLIC_ADSENSE_CLIENT_ID, chargement du script en prod
Annonces qui ne se mettent pas à jour en SPA Pas de re-push au changement de route Appeler `(adsbygoogle
Erreurs console (adsbygoogle) Script chargé avant le DOM du bloc ou trop tôt S’assurer que AdUnit est rendu après afterInteractive ; un court délai ou requestAnimationFrame peut aider si besoin

Ressources


Cet article s’inscrit dans notre série de guides technique et développement web. Pour un serveur ou une application sur-mesure, contact.

Commentaires (0)

Laisser un commentaire