
Next.js ポートフォリオサイトにブログ分析ダッシュボードを自作した話【GA4・Search Console・AI提案付き】
ブログを運営していると「どの記事がよく読まれているか」「どこに問題があるか」を把握したくなります。Google Analytics や Search Console を個別に見るのは手間がかかるため、自分のサイトに直接ダッシュボードを組み込むことにしました。
既存の Next.js ポートフォリオサイトに追加する形で、以下の機能を持つ分析ダッシュボードをゼロから構築しました。
作ったもの
/dashboard
├── 概要 ... 記事数・問題数のサマリー
├── 全記事 ... 検索・フィルター付き一覧テーブル
├── カテゴリ ... カテゴリ別件数・タグ分析
├── リンク ... 内部リンク構造・孤立記事の検出
├── ヘルス ... コンテンツ品質チェック
├── GA4 ... PVトレンドグラフ・エンゲージメント散布図
├── Search Console ... 検索クエリ・SEO機会の検出
├── AI 提案 ... GPT-4o-miniによる改善提案
└── 履歴 ... 提案の実施履歴管理
本番サイトには影響なし。 middleware.ts で NODE_ENV === 'production' 時はルートにリダイレクトするため、ローカル開発専用のツールとして安全に運用できます。
まず先に完成画面をご覧ください







このエンゲージメント分析が完成度高い。
履歴を呼び出すと、リライト前後で、その記事がどの様な影響を与えているか一発で分かります。

これらの画面を作成していきます。
技術スタック
用途 | 技術 |
|---|---|
フレームワーク | Next.js 15 App Router(Server Components中心) |
データ取得 | microCMS JS SDK |
アクセス解析 | Google Analytics Data API v1( |
検索データ | Google Search Console API( |
AI提案 | OpenAI GPT-4o-mini(コスト重視) |
グラフ | recharts |
データ保存 | localStorage(実施済みマーク)/ ローカルJSONファイル(スナップショット) |
各機能の説明
1. コンテンツ分析(microCMSデータ)
microCMS から記事データを取得し、以下の問題を自動検出します。
- タグ未設定・カテゴリ未設定・アイキャッチなし
- 90日以上未更新の記事
- 本文500文字未満の薄いコンテンツ
- 孤立記事(他のどの記事からも内部リンクされていない)
内部リンクの検出は記事 HTML の href 属性を正規表現で解析し、/blog/スラッグ 形式のリンクをカウントします。
function extractInternalBlogLinks(content: string, slugSet: Set<string>): string[] {
const hrefRegex = /href="([^"]+)"/g;
// /blog/スラッグ にマッチするリンクのみ抽出
...
}
2. GA4 アナリティクス
Google Cloud のサービスアカウント JSON を環境変数に設定するだけで、GA4 Data API から直近90日のデータを取得します。
グラフ一覧:
- 日別PVトレンド(折れ線グラフ)
- 週次PV集計(棒グラフ)
- 直帰率 × 平均滞在時間の散布図(円の大きさ = PV数)
散布図は特に有用で、「よく読まれているのに離脱率が高い記事(内部リンク不足)」を一目で発見できます。
3. Search Console
検索クエリと流入ページのデータを取得し、SEO機会(検索順位11〜30位) を自動でハイライトします。わずかな改善で1ページ目に上がれる可能性がある記事を見つけるためです。
4. AI 改善提案(GPT-4o-mini)
単に「問題数が多い」というデータを渡すのではなく、AIが具体的に判断できる情報を整形して渡しています。
// 記事ごとのコンテキスト(AIに渡す)
{
タイトル: "記事タイトル",
内容要約: "本文の最初200文字...",
内部リンク: {
被リンク数: 2,
リンク先スラッグ: ["slug-a", "slug-b"]
},
GA4: { pv: 150, bounceRate: 72, avgDurationSec: 847 }
}
重要な工夫:現在のリンク構造を渡す
【現在の内部リンク構造(この組み合わせは提案不要)】
article-a → article-b
article-c → article-d
これにより「すでに実施済みのリンクを提案する」無駄が省けます。また temperature: 0.4 に下げることで提案の一貫性を高めています。
GA4のパターン分析も組み込みました:
パターン | 診断 | 提案内容 |
|---|---|---|
直帰率高い × 滞在時間短い | コンテンツミスマッチ | 導入文・タイトルの見直し |
滞在時間長い × 直帰率高い | 内部リンク不足 | 末尾への関連記事リンク追加 |
PV多い × 直帰率高い | 最優先改善候補 | CTA追加・目次見直し |
5. 変更履歴管理
AI提案が毎回同じものを出してしまう問題に対応するため、履歴管理を実装しました。
実施済みマーク(localStorage)
提案カードの「実施済みにする」ボタンをクリックすると、提案の ID(カテゴリ + 優先度 + 本文ハッシュ)をブラウザに保存。実施済みカードはフェードアウト表示され、実施日時が記録されます。
スナップショット保存(ローカルJSONファイル)
「📸 スナップショット保存」で現在の提案と実施状況を dashboard-data/snapshots.json に書き込みます(Next.js API Route 経由)。履歴ページでは過去のスナップショットを実施率の進捗バー付きで一覧表示します。
📋 2026/2/24 20:15 記事18件を分析
実施済み 3 / 10 件 [████░░░░░░] 30%
セットアップ
.env.local に以下を追加するだけで全機能が動きます。
# Google サービスアカウント(GA4 + Search Console 共用)
GOOGLE_SERVICE_ACCOUNT_JSON='{ "type": "service_account", ... }'
GA4_PROPERTY_ID=123456789
SEARCH_CONSOLE_SITE_URL=sc-domain:your-domain.com
# OpenAI
OPENAI_API_KEY=sk-...
サービスアカウントには GA4 の「閲覧者」権限と Search Console の「制限付き」権限を付与します。
ポイントまとめ
- Server Components 中心設計 — データ取得はすべてサーバーサイド。React
cache()でリクエスト内の重複取得を防止 - 外部APIの失敗を分離 — GA4が取得できなくても他の分析は動く設計
- AIに「現状」を正確に渡す — 記事内容・現在のリンク構造・実施済み情報をプロンプトに含めることで提案品質が大幅向上
- ローカル専用 —
middleware.tsで本番ブロック、dashboard-data/は.gitignore済み
まとめ
外部ツールに頼らず、自分のサイトに完全に統合されたダッシュボードを持てるのは快適です。microCMS のデータ・GA4・Search Console・AI提案がひとつの画面で確認でき、「実施済みにする → スナップショット保存」のワークフローで改善作業を管理できます。
同じ構成(Next.js + microCMS)を使っている方は参考にしてみてください。
この記事が役に立ったらフォローしてください
