【これで解決】Next.js+TypeScriptのサイトでAdsense広告を使用する方法

作成日2025年12月4日 13:23
"サムネイル画像"

Next.js App RouterプロジェクトにGoogle Adsense広告を実装する際、従来のHTMLベースのサイトとは違ったアプローチが必要になります。この記事では、TypeScriptを使用したNext.js App RouterでのAdsense広告実装方法を、実践的なコンポーネント設計とともに解説していきます。

この記事でわかること 

この記事を読むことで、以下のことができるようになります。

  • Next.js App RouterプロジェクトにAdsense広告を正しく実装する方法
  • ページ遷移時も広告が適切に表示される環境の構築方法
  • 開発環境と本番環境で異なる表示を切り替える方法
  • レスポンシブ対応の広告配置方法
  • 複数広告を効果的に配置する方法

前提条件 

実装を始める前に、以下の準備を整えておいてください。

まず、Google Adsenseのアカウントを取得し、サイトの審査が完了している必要があります。審査完了後、Adsense管理画面から広告ユニットを作成して、クライアントIDと広告スロットIDを取得しておきましょう。クライアントIDは「ca-pub-」で始まる文字列、広告スロットIDは数字の文字列です。

Next.jsのバージョンは13.0.0以上(App Router対応版)、Reactは18.0.0以上を使用することをおすすめします。TypeScriptはプロジェクトにすでに設定されている前提で進めていきます。

さらに、この記事ではTailwind CSSを使用したスタイリングを行いますので、プロジェクトにTailwind CSSが導入されていることを確認してください。

Next.jsでAdsense実装が難しい理由 

従来のWebサイトでは、各ページ遷移がフルリロードを伴うため、Adsenseのスクリプトは毎回実行されます。でも、Next.jsではクライアントサイドルーティングが使われるので、内部リンクでのページ遷移時にスクリプトが再実行されないんです。

そのため、最初にアクセスしたページでは広告が表示されても、内部リンクで遷移した先のページでは広告が表示されないという問題が発生します。この問題を解決するには、ページ遷移を検知して広告を再初期化する仕組みが必要になります。

実装手順 

環境変数の設定 

プロジェクトルートに.env.localファイルを作成して、以下の内容を追加してください。

plaintext
NEXT_PUBLIC_ADSENSE_CLIENT_ID=ca-pub-XXXXXXXXXXXXXXXX
NEXT_PUBLIC_ADSENSE_SLOT_ID=1234567890

クライアントIDには「ca-pub-」を含む完全な文字列を、広告スロットIDには広告ユニットの数字を設定します。これらの値はAdsense管理画面から取得できます。

クライアントIDの取得方法

Adsense管理画面にアクセスし、左メニューの「アカウント」→「設定」→「アカウント情報」へ移動します。そこに表示されている「pub-xxxxx」から始まる「パブリッシャー ID 」が「クライアントID」となります。使用する際は、「ca-pub-xxxx」のように記載します。

Adsense管理画面でパブリッシャーIDを確認できるページ

広告スロットIDの取得方法

Adsense管理画面にアクセスし、左メニューの「広告」→「広告ユニットごと」タブをクリックします。そうすると下にこれまでに作成された広告のユニットが表示されます。作成された広告ユニットがまだない場合は、「新しい広告ユニットの作成」のセクションで「ディスプレイ広告」を選んで新規作成してください。

Adsense管理画面で作成済みの広告ユニットリストを確認できるページ

広告ユニットコードを表示し、data-ad-slotの値を取得して完了です。

html
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-xxxxxxxxxxxx"
     crossorigin="anonymous"></script>
<!-- TRANSCRIBER - home -->
<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-xxxxxxxxxxxx"
     data-ad-slot="xxxxxxxxxx"
     data-ad-format="auto"
     data-full-width-responsive="true"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>

プロジェクト構成 

実装するファイルは以下の構成になります。

plaintext
src/
├── components/
│   ├── server/  # サーバーコンポーネント
│   │   └── scripts.tsx
│   └── adsense.tsx
└── app/
    ├── layout.tsx
    └── page.tsx

この構成では、サーバーコンポーネントとクライアントコンポーネントを明確に分離しています。scripts.tsxはサーバーコンポーネントとして、adsense.tsxはクライアントコンポーネントとして動作します。

Adsense広告コンポーネントの作成 

src/components/adsense.tsxファイルを作成して、以下のコードを記述します。このファイルには、基本的な広告コンポーネントと、用途に応じた複数のバリエーションが含まれています。

typescript
'use client';
import { useEffect, Fragment } from 'react';
import { usePathname } from "next/navigation";

declare global {
  interface Window {
    adsbygoogle: { [key: string]: unknown }[]
  }
}

/**
 * Google Adsense広告を表示するコンポーネント
 * 
 * ページ遷移を検知して自動的に広告を再初期化します。
 * 開発環境ではプレースホルダーを表示し、本番環境では実際の広告を表示します。
 * 
 * @param {Object} props - コンポーネントのプロパティ
 * @param {boolean} [props.visible=true] - 広告を表示するかどうか。falseの場合はプレースホルダーを表示
 * 
 * @example
 * // 本番環境でのみ広告を表示
 * const isProduction = process.env.NODE_ENV === 'production';
 * <Adsense visible={isProduction} />
 * 
 * @example
 * // 常に広告を表示
 * <Adsense visible={true} />
 */
export function Adsense({ visible = true }: { visible?: boolean }) {
  let pathname = usePathname();
  pathname = pathname ? pathname : "";
  
  useEffect(() => {
    if (!visible) return;
    try {
      (window.adsbygoogle = window.adsbygoogle || []).push({});
    } catch (err) {
      console.error(err);
    }
  }, [pathname, visible]);
  
  return (
    <Fragment>
      {
        visible ? (
          <Fragment>
            <ins className="adsbygoogle"
              style={{ display: 'block' }}
              data-ad-client={process.env.NEXT_PUBLIC_ADSENSE_CLIENT_ID}
              data-ad-slot={process.env.NEXT_PUBLIC_ADSENSE_SLOT_ID}
              data-ad-format="auto"
              data-full-width-responsive="true"
            ></ins>
          </Fragment>
        ) : (
          <div className='w-full h-[300px] flex flex-row items-center justify-center bg-stone-300 dark:bg-stone-700'>
            <span className='text-3xl font-medium cursor-default'>広告</span>
          </div>
        )
      }
    </Fragment>
  )
}

/**
 * レスポンシブ対応のAdsense広告コンポーネント
 * 
 * 基本的なAdsenseコンポーネントにマージンとカスタムクラスを追加できるラッパーです。
 * デフォルトで上部に24pxのマージンが設定されます。
 * 
 * @param {Object} props - コンポーネントのプロパティ
 * @param {string} [props.className] - 追加のTailwind CSSクラス名
 * @param {boolean} [props.visible] - 広告を表示するかどうか
 * 
 * @example
 * // 基本的な使用方法
 * <AdsenseResponsive visible={isProduction} />
 * 
 * @example
 * // カスタムクラスを追加
 * <AdsenseResponsive visible={isProduction} className="my-8 border-t border-b pt-8 pb-8" />
 */
export function AdsenseResponsive({ className, visible }: {
  className?: string, visible?: boolean
}) {
  return (
    <aside className={`w-full mt-6 ${className || ''}`}>
      <Adsense visible={visible} />
    </aside>
  )
}

/**
 * 2列レイアウトのAdsense広告コンポーネント
 * 
 * 2つの広告を横並びに配置します。
 * 大画面(1024px以上)では2列、小画面では1列で表示されます。
 * 記事の末尾などで効果的に使用できます。
 * 
 * @param {Object} props - コンポーネントのプロパティ
 * @param {string} [props.className] - 追加のTailwind CSSクラス名
 * @param {boolean} [props.visible] - 広告を表示するかどうか
 * 
 * @example
 * // 記事の末尾に2列広告を配置
 * <AdsenseDoubleRectangle visible={isProduction} />
 * 
 * @example
 * // カスタムクラスを追加
 * <AdsenseDoubleRectangle visible={isProduction} className="mb-12" />
 */
export function AdsenseDoubleRectangle({ className, visible }: {
  className?: string, visible?: boolean
}) {
  return (
    <aside className={`w-full mt-6 flex justify-center flex-wrap gap-3 ${className || ''}`}>
      <div className='w-full lg:w-[calc(50%-0.4rem)]'>
        <Adsense visible={visible} />
      </div>
      <div className='w-full lg:w-[calc(50%-0.4rem)]'>
        <Adsense visible={visible} />
      </div>
    </aside>
  )
}

このコンポーネントの設計には、いくつか重要な特徴があります。

まず、usePathnameフックを使ってページ遷移を検知しています。pathnameが変わるたびにuseEffectが実行されて、新しい広告が初期化される仕組みです。これで、Next.jsのクライアントサイドルーティングでも広告が正しく表示されるようになります。

visibleプロパティを使うことで、開発環境と本番環境で違う表示に切り替えられます。visiblefalseの場合、実際の広告の代わりにプレースホルダーが表示されるので、開発中のレイアウト確認が簡単になります。

3つの異なるコンポーネントを用意しました。Adsenseは基本的な広告表示コンポーネント、AdsenseResponsiveはマージンとレスポンシブ対応を含むラッパー、AdsenseDoubleRectangleは2つの広告を横並びに配置する特別なレイアウトです。

Adsenseスクリプトの読み込みコンポーネント 

src/components/server/scripts.tsxファイルを作成して、Adsenseのスクリプトを読み込むためのコンポーネントを記述します。このコンポーネントはサーバーコンポーネントとして動作します。

typescript
import { Fragment } from 'react';
import Script from "next/script";

export async function LoadAdsenseScript({ visible }: { visible?: boolean }) {
  return (
    <Fragment>
      {
        visible && (
          <Fragment>
            <Script 
              async 
              strategy="afterInteractive"
              src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${process.env.NEXT_PUBLIC_ADSENSE_CLIENT_ID}`}
              crossOrigin="anonymous"
              id="adsense-script"
            />
          </Fragment>
        )
      }
    </Fragment>
  )
}

このコンポーネントでは、Next.jsのScriptコンポーネントを使ってAdsenseのスクリプトを読み込んでいます。strategy="afterInteractive"を指定することで、ページがインタラクティブな状態になった後にスクリプトが読み込まれるので、パフォーマンスへの影響を最小限に抑えられます。

visibleプロパティで、本番環境でのみスクリプトを読み込むように制御できます。これで、開発中にAdsenseの広告配信回数を消費せず、不要なネットワークリクエストも発生しません。

レイアウトファイルへの統合 

src/app/layout.tsxファイルを開いて、LoadAdsenseScriptコンポーネントを配置します。

typescript
import type { Metadata } from 'next';
import { LoadAdsenseScript } from '@/components/server/scripts';
import './globals.css';

export const metadata: Metadata = {
  title: 'あなたのサイト名',
  description: 'サイトの説明',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const isProduction = process.env.NODE_ENV === 'production';
  
  return (
    <html lang="ja"suppressHydrationWarning>
      <body>
        <LoadAdsenseScript visible={isProduction} />
        {children}
      </body>
    </html>
  );
}

レイアウトファイルに配置することで、全てのページでAdsenseスクリプトが読み込まれるようになります。isProduction変数を使って環境を判定して、本番環境でのみスクリプトを読み込むように設定しています。

広告の配置方法 

作成したコンポーネントを、広告を表示したい任意のページやコンポーネントで使っていきます。以下は、ブログ記事ページでの使用例です。

typescript
import { AdsenseResponsive, AdsenseDoubleRectangle } from '@/components/adsense';

export default function BlogPost() {
  const isProduction = process.env.NODE_ENV === 'production';
  
  return (
    <article className="max-w-4xl mx-auto px-4">
      <h1 className="text-4xl font-bold mb-4">記事タイトル</h1>
      
      {/* 記事冒頭の広告 */}
      <AdsenseResponsive visible={isProduction} />
      
      <div className="prose prose-lg">
        <p>記事の導入部分...</p>
      </div>
      
      {/* 記事中央の広告 */}
      <AdsenseResponsive visible={isProduction} className="my-8" />
      
      <div className="prose prose-lg">
        <p>記事の本文...</p>
      </div>
      
      {/* 記事末尾の2列広告 */}
      <AdsenseDoubleRectangle visible={isProduction} />
    </article>
  );
}

このコード例では、3つの異なる位置に広告を配置しています。記事の冒頭と中央には単一の広告を、末尾には2つの広告を横並びで配置しています。

visibleプロパティにはisProductionを渡すことで、開発環境ではプレースホルダーが、本番環境では実際の広告が表示されます。

コンポーネントの詳細解説 

”Adsense”コンポーネント 

基本となるAdsenseコンポーネントは、広告表示の核となる機能を提供します。このコンポーネントの重要なポイントは、useEffectフックとusePathnameフックの組み合わせです。

usePathnameはNext.js App Routerで現在のパスを取得するフックで、ページ遷移が発生するたびに新しいパスが返されます。このパスをuseEffectの依存配列に含めることで、ページ遷移時に広告の再初期化が確実に実行されるわけです。

visiblefalseの場合、Tailwind CSSを使ったプレースホルダーが表示されます。このプレースホルダーは高さ300pxで設定していて、実際の広告と同じくらいのスペースを確保します。ダークモード対応も含まれているので、背景色が自動的に切り替わります。

"AdsenseResponsive"コンポーネント 

AdsenseResponsiveは、基本的な広告コンポーネントにマージンとカスタムクラスを追加できるラッパーコンポーネントです。デフォルトで上部に24pxのマージンが設定されていて、コンテンツと広告の間に適切な余白を確保します。

classNameプロパティを使うことで、追加のスタイリングを柔軟に適用できます。例えば、className="my-8 border-t border-b pt-8 pb-8"のように指定すれば、広告の上下にボーダーとパディングを追加できます。クラス名は通常のテンプレートリテラルで結合されるので、追加のライブラリは不要です。

"AdsenseDoubleRectangle"コンポーネント 

AdsenseDoubleRectangleは、2つの広告を横並びに配置する記事内表示用のレイアウトコンポーネントです。レスポンシブデザインになるようになっていて、大きな画面では2列表示、小さな画面では1列表示に自動的に切り替わります。

ブレークポイントはlg(1024px)に設定していて、それ以上の画面幅では各広告が約50%の幅を占めます。広告間には12pxのギャップが設定されていて、適度な間隔を保ちます。

この配置は特に記事の末尾で効果的です。読者が記事を読み終えた後、2つの広告オプションを提示することで、クリック率の向上が期待できます。

開発環境と本番環境の切り替え 

この実装では、visibleプロパティを使って環境ごとの表示を制御しています。この方法にはいくつかメリットがあります。

まず、開発中にAdsenseの広告配信回数を消費しないので、本番環境でのパフォーマンスデータが正確に保たれます。また、開発者コンソールに表示されるAdsense関連の警告やエラーメッセージも回避できます。

さらに、プレースホルダー表示で、実際の広告が表示される位置とサイズを視覚的に確認できるので、レイアウトの調整が簡単になります。ダークモード対応で、サイトのテーマに関わらず、プレースホルダーが適切に表示されます。

環境判定はprocess.env.NODE_ENVを使って行いますが、もっと細かい制御が必要な場合は、カスタム環境変数を使うこともできます。例えば、.env.localNEXT_PUBLIC_SHOW_ADS=trueという変数を追加して、これを使って表示を制御できます。

よくある問題と解決方法 

ページ遷移後に広告が表示されない 

Next.jsのクライアントサイドルーティングでは、ページ遷移時にスクリプトが再実行されないので、広告の初期化処理も実行されません。

この問題は、提供しているコンポーネントのuseEffectpathnameを依存配列に含めることで解決されています。usePathnameフックが返すパスが変わるたびに、広告の初期化処理が実行されるので、内部リンクでのページ遷移後も広告が正しく表示されます。

もし広告が表示されない場合は、useEffectの依存配列にpathnameが正しく含まれているか確認してください。

コンソールにnscript関連の警告が表示される 

ブラウザの開発者ツールで「AdSense head tag doesn't support data-nscript attribute」という警告が表示されることがあります。これはNext.jsのScriptコンポーネントが内部的に追加する属性によるもので、実際の広告配信には影響しません。

この警告はNext.jsとAdsenseの仕様上避けられないものですが、広告の表示や機能に問題はないので、安心してください。Googleも広告配信自体は正常に行われることを確認しています。

もし警告を完全に回避したい場合は、Scriptコンポーネントの代わりにuseEffect内でスクリプトを動的に読み込む方法もありますが、パフォーマンスの観点からは現在の実装を推奨します。

開発環境で実際の広告を確認したい 

場合によっては、開発環境でも実際の広告表示を確認したいことがあります。その場合は、一時的にvisibleプロパティにtrueを直接渡すか、環境変数を使って制御できます。

ただし、開発中に頻繁に広告を読み込むと、Adsenseのポリシー違反となる可能性があるので注意が必要です。テストは必要最小限に留めて、主にプレースホルダーでレイアウトを確認することをおすすめします。

広告ブロッカー対策について 

広告ブロッカーによる影響 

広告ブロッカーは、ブラウザの拡張機能やアプリとして提供されるツールで、Webサイト上の広告を非表示にする機能を持っています。日本では約15~20%の人が利用していると推定されており、特に技術系サイトではITリテラシーの高いユーザーが多いため、利用率がさらに高くなる傾向があります。

広告ブロッカーが有効になっていると、Adsenseの広告スクリプトや広告要素が読み込まれないため、インプレッション数が減少し、結果として収益の損失に繋がります。2024年2月からインプレッション型の収益モデルに変更されたことで、広告が表示されないことによる影響はより直接的になっています。

Adsense公式の広告ブロッカー対策機能 

Googleは「広告ブロックによる損失収益の回復」という公式機能を提供しています。この機能を使うことで、広告ブロッカーを使用しているユーザーに対して、広告の表示を促すモーダルメッセージを表示できます。

設定はAdsense管理画面の「プライバシーとメッセージ」→「広告ブロックによる損失収益の回復」から行えます。メッセージの内容をカスタマイズして、広告ブロッカーの無効化をお願いしたり、サイトを許可リストに追加してもらうよう促すことができます。

設定後、生成されたスクリプトをサイトの<head>タグ内に追加するだけで、自動的に広告ブロッカーを検知してメッセージを表示する仕組みが動作します。この機能により、一部のユーザーは広告ブロックを解除してくれるようになり、収益の回復が期待できます。

Adsenseの広告ブロッカー対策スクリプトの発行ページ

「広告ブロックによる損失収益の回復」と「エラー保護のメッセージ」の両方を設定することをお勧めします。

Next.jsでこの機能を実装する場合は、先ほど作成したsrc/components/server/scripts.tsxに追加のScriptコンポーネントとして組み込むか、src/app/layout.tsxのheadセクションに直接追加することで対応できます。

なお、広告ブロッカー対策を実装する際は、ユーザー体験を損なわないよう、押し付けがましくないメッセージ内容にすることをおすすめします。サイトの運営コストや品質維持のために広告が必要であることを丁寧に説明することで、ユーザーの理解を得やすくなります。

パフォーマンスの最適化 

Adsense広告はサイトのパフォーマンスに影響を与える可能性があります。以下の最適化方法を実装することで、ユーザー体験を損なわずに広告を配信できます。

スクリプトの読み込み戦略 

提供しているコンポーネントでは、strategy="afterInteractive"を使っています。これは、ページがインタラクティブな状態になった後にスクリプトが読み込まれることを意味します。

他の戦略として、strategy="lazyOnload"も選択できます。これは、ブラウザがアイドル状態になった後にスクリプトを読み込む、よりパフォーマンス重視の戦略です。ただし、広告の表示が若干遅れる可能性があります。

トラフィックの多いサイトでは、afterInteractiveが適切なバランスを提供します。トラフィックが少なくて、パフォーマンスを最優先する場合は、lazyOnloadを検討してください。

レイアウトシフトの最小化 

広告が読み込まれる際、コンテンツがシフトしてユーザー体験が損なわれることがあります。これを防ぐには、広告コンテナに適切な高さを設定する必要があります。

プレースホルダーは高さ300pxで設定していて、一般的な広告サイズに対応しています。実際の広告サイズに合わせて調整することで、レイアウトシフトを最小限に抑えられます。

また、Adsenseのレスポンシブ広告ユニットは、コンテナのサイズに応じて自動的にサイズを調整するので、レイアウトシフトが発生しにくくなっています。

広告の配置戦略 

広告の配置はパフォーマンスとユーザー体験に大きく影響します。以下のガイドラインに従うことで、最適な配置を実現できます。

ファーストビュー(最初に表示される画面領域)には広告を配置しないことをおすすめします。これで、初回コンテンツ表示が高速化されて、読者は即座にコンテンツを読み始められます。

記事の中盤や末尾に広告を配置することで、読者がコンテンツに興味を持った後に広告を表示できます。Adsenseは2024年2月から、従来のクリック型(CPC)からインプレッション型(CPM)の収益モデルへと変更されました。これはディスプレイ広告業界の標準に合わせるための変更で、広告が表示されるだけで収益が発生するようになっています。適切な位置に広告を配置することで、表示回数を増やし、収益の向上が期待できます。

AdsenseDoubleRectangleコンポーネントは、記事の末尾で特に効果的です。読者が記事を読み終えた後、自然な流れで広告に目を向けることができます。

自動広告との併用 

個別に広告ユニットを配置する方法に加えて、Googleが自動的に最適な位置に広告を配置する自動広告機能も利用できます。

自動広告を有効にするには、Adsense管理画面で設定を行った後、LoadAdsenseScriptコンポーネントを配置するだけで完了です。個別の広告ユニットコンポーネントは不要になって、シンプルな実装で運用できます。

ただし、広告の表示位置を細かく制御したい場合や、特定のレイアウトを維持したい場合は、この記事で紹介している手動配置の方法を選んでください。

両方を併用することも可能ですが、広告の密度が高くなりすぎないよう注意が必要です。Googleのポリシーでは、過度な広告配置はペナルティの対象となる可能性があります。

本番環境へのデプロイ前のチェックリスト 

実装が完了したら、本番環境にデプロイする前に以下の項目を確認してください。

まず、環境変数が正しく設定されていることを確認します。.env.localファイルの内容が、デプロイ先の環境変数設定に反映されているか確認してください。Vercelなどのホスティングサービスを使っている場合は、管理画面から環境変数を設定できます。

環境変数は以下の2つが必須です。

  • NEXT_PUBLIC_ADSENSE_CLIENT_ID: 完全なクライアントID(ca-pub-を含む)
  • NEXT_PUBLIC_ADSENSE_SLOT_ID: 広告スロットID

次に、Adsense管理画面でサイトが承認されていて、広告ユニットが正しく作成されていることを確認します。サイトが未承認の場合、広告は表示されません。

また、LoadAdsenseScriptvisibleプロパティが環境に応じて正しく設定されているか確認してください。本番環境ではtrue、開発環境ではfalseになっているべきです。

コンポーネントのインポートパスが正しいことも確認しましょう。TypeScriptのパスエイリアス(@/)が正しく設定されていない場合、ビルドエラーが発生します。

最後に、Googleのポリシーに準拠していることを確認します。不適切なコンテンツや誤クリックを誘発するような配置は避けて、ユーザーエクスペリエンスを損なわないように注意してください。

デプロイ後は、実際のサイトにアクセスして広告が表示されることを確認してください。広告の表示には数分から数時間かかる場合があります。

まとめ 

Next.js App RouterとTypeScriptを使ったプロジェクトにAdsense広告を実装する方法について、実践的なコンポーネント設計とともに解説してきました。

重要なポイントとして、usePathnameフックを使ってページ遷移を検知して、広告を再初期化する仕組みが必要です。また、visibleプロパティを使って開発環境と本番環境で違う表示に切り替えることで、開発効率と本番環境のパフォーマンスを両立できます。

提供したコンポーネントは、基本的な広告表示から複雑なレイアウトまで対応できる柔軟な設計になっています。プロジェクトのニーズに応じて、これらのコンポーネントをカスタマイズして使ってください。

この記事で紹介した実装方法を活用することで、安定した広告配信を実現できます。定期的にAdsense管理画面でパフォーマンスを確認して、必要に応じて広告の配置や設定を調整することをおすすめします。