JAMstack構成(例: Next.jsやGatsby.js + ヘッドレスCMS)は、フロントエンドとバックエンドを分離することで、使用する技術選択の自由度が高く、パフォーマンスやセキュリティ面でのメリットも大きいモダンなWebサイト構築のアプローチです。
しかし、その一方で、従来のWordPressサイトなどではプラグインで簡単に実現できた機能、例えば「人気記事一覧(ランキング)」などを実装しようとすると、少し工夫が必要になります。
WordPressで人気記事一覧が容易なのは、記事データとページ閲覧数(PV数)が同じデータベース内に記録されており、動的にデータを取得・集計してランキング表示できるためです。しかし、JAMstack構成の多くは、ビルド時に静的なHTMLファイルを生成するため、リアルタイムで変動する閲覧数を基にした動的なランキング表示は得意ではありません。また、フロントエンドとバックエンドが分離しているため、アクセス数を記録・参照する共通の仕組みが標準では備わっていません。
そこで活用したいのが、多くのWebサイトで導入されているアクセス解析ツール「Google Analytics」です。Google Analyticsに蓄積されたページごとの閲覧数データを、そのAPI(Google Analytics Data API (GA4 Data API))経由で取得し、ビルドプロセスに組み込むことで、静的サイトでありながら「人気記事一覧」を表示することが可能になります。
この記事では、Google Analytics Data API (GA4) を利用して人気記事データを取得し、Next.jsやGatsby.jsといった静的サイトジェネレーター環境で「人気記事一覧」を実装するための具体的な手順と考え方を紹介します。
この記事の内容
静的サイト(ヘッドレスCMS)で人気記事一覧を実装する難しさ

前述の通り、従来の動的なCMS(WordPressなど)では、データベースへのアクセスを通じてリアルタイムにPV数を集計し、人気記事ランキングを表示することが一般的でした。
しかし、JAMstack構成の静的サイトでは、サイトのコンテンツはビルド時に生成され、サーバー側での動的なデータ処理は基本的には行いません。そのため、サイトが表示されるたびにPV数をリアルタイムで集計してランキングを変動させる、といった実装は困難です。
そこで、外部サービスであるGoogle Analyticsのデータを活用するアプローチが有効になります。基本的な流れは以下のようになります。
- ビルド前にデータを取得: スクリプトを実行し、Google Analytics Data APIを通じて、指定期間のページ別閲覧数を取得します。(例: 直近30日間のPV数トップ10記事)
- データを整形・保存: 取得したランキングデータ を扱いやすい形式(例: JSONファイル)に整形して、プロジェクト内に保存します。
- ビルド時にデータを参照: Next.jsやGatsby.jsなどの静的サイトジェネレーターがサイトをビルドする際に、保存されたJSONファイルを読み込みます。
- 静的ページに埋め込み: 読み込んだランキングデータ(記事タイトル、URL、PV数など)を使って、「人気記事一覧」のコンポーネントやリストを生成し、静的なHTMLページ内に埋め込みます。
この方法であれば、サイトをデプロイ(ビルド)するたびに最新のランキング情報が反映され、かつサイト自体は高速な静的ファイルとして提供できるため、パフォーマンスを損なうこともありません。
Google Analytics Data API (GA4) の有効化と基本準備
まず、Google Analyticsのデータをプログラムから取得するために、APIの有効化と必要な情報を準備します。

- Google Cloud Platform (GCP) でAPIを有効化:
- Google Cloud Console (https://console.cloud.google.com/) にアクセスし、プロジェクトを選択または新規作成します。
- 「APIとサービス」>「ライブラリ」で「Google Analytics Data API」を検索し、有効にします。
- サービスアカウントを作成し、キーをダウンロード:
- GCPの「APIとサービス」>「認証情報」で、「認証情報を作成」>「サービスアカウント」を選択し、新しいサービスアカウントを作成します。(名前は任意、ロールは不要な場合が多い)
- 作成したサービスアカウントを選択し、「キー」タブ>「鍵を追加」>「新しい鍵を作成」で「JSON」形式のキーを作成・ダウンロードします。このJSONファイルは後でスクリプトから使用します。大切に保管してください。
- サービスアカウントにGA4プロパティへのアクセス権を付与:
- Google Analytics (https://analytics.google.com/) にアクセスし、対象のGA4プロパティの「管理」(歯車アイコン)を開きます。
- 「プロパティ設定」>「プロパティのアクセス管理」で、「+」ボタン >「ユーザーを追加」を選択します。
- 先ほど作成したサービスアカウントのメールアドレス(GCPの認証情報画面で確認できます)を入力し、「役割」として少なくとも「閲覧者」の権限を付与して追加します。
- GA4プロパティIDを控える:
- Google Analyticsの「管理」>「プロパティ設定」で、「プロパティ ID」(数字のみのID)を確認し、控えておきます。これもスクリプトで使用します。
これらの準備(特にGCPやGA4の操作)については、Googleの公式ドキュメントや他の解説記事も参考に、ご自身の環境に合わせて進めてください。
サービスアカウントの利用とセキュリティ上の注意点

Google Analytics Data APIのように、Googleのサービスにプログラムからアクセスする際には、通常「サービスアカウント」という特殊なアカウントを使用します。これは、個人のGoogleアカウントではなく、アプリケーションやスクリプトが自身を認証するためのものです。
前述のステップで作成しダウンロードしたサービスアカウントキー(JSONファイル)には、そのサービスアカウントとしてAPIにアクセスするための秘密の情報が含まれています。そのため、このキーファイルの取り扱いには細心の注意が必要です。
- 絶対に公開しない: JSONキーファイルは、Gitリポジトリ(特にPublicリポジトリ)に絶対にコミットしないでください。誤って公開してしまうと、第三者に不正利用される危険性があります。
.gitignore
ファイルにキーファイル名を追加し、Gitの管理対象から除外しましょう。 - 安全な場所に保管: ローカル開発環境ではプロジェクトルートなどに置くこともありますが、本番環境(デプロイ先)では、環境変数やシークレット管理機能を使って安全にキー情報を渡すのが一般的です。(後述のスクリプト例参照)
- 権限は最小限に: GA4プロパティでサービスアカウントに付与する権限は、データ取得に必要な最低限の「閲覧者」権限にしておきましょう。
Node.jsによる人気記事データ取得スクリプトの実装例
ここでは、準備したサービスアカウントキーとGA4プロパティIDを使って、実際に人気記事データを取得し、JSONファイルとして保存するNode.jsスクリプトの例を示します。
【準備】
- プロジェクトのルートディレクトリに
scripts
フォルダを作成し、その中に以下のスクリプトをfetch-popular-posts.js
などの名前で保存します。 - プロジェクトのルートディレクトリに、GCPからダウンロードしたサービスアカウントキーのJSONファイルを
service-account.json
(または任意 の名前)として配置します。 - プロジェクトのルートディレクトリに
.env
ファイルを作成し、以下の形式でGA4プロパティIDを記述します(?????????
の部分は実際のIDに置き換えてください)。GA4_PROPERTY_ID=?????????
- 【重要】
service-account.json
と.env
ファイルは機密情報を含むため、必ず.gitignore
ファイルに追加して、Gitリポジトリに含まれないようにします。# .gitignore ファイルの例 service-account.json .env
- 必要なnpmパッケージをインストールします。ターミナルで以下のコマンドを実行してください。
npm install @google-analytics/data dotenv
(または
yarn add @google-analytics/data dotenv
)
【スクリプト例: scripts/fetch-popular-posts.js
】
// .envファイルから環境変数を読み込む
require("dotenv").config();
// Google Analytics Data APIクライアントライブラリ
const { BetaAnalyticsDataClient } = require("@google-analytics/data");
// Node.jsのファイルシステムとパス操作モジュール
const fs = require("fs");
const path = require("path");
// 非同期関数として人気記事取得処理を定義
async function fetchPopularPosts() {
let credentials;
// --- 認証情報の設定 ---
// 本番環境用に環境変数 GA_CREDENTIALS_JSON があればそれを使う (推奨)
if (process.env.GA_CREDENTIALS_JSON) {
try {
credentials = JSON.parse(process.env.GA_CREDENTIALS_JSON);
} catch (e) {
console.error("Failed to parse GA_CREDENTIALS_JSON environment variable.", e);
process.exit(1);
}
}
// 環境変数がなければ、ローカルの service-account.json を読み込む
else {
const keyFilePath = path.resolve(__dirname, "../service-account.json");
if (fs.existsSync(keyFilePath)) {
credentials = JSON.parse(fs.readFileSync(keyFilePath, "utf8"));
} else {
console.error(`Service account key file not found at ${keyFilePath}. Or set GA_CREDENTIALS_JSON env var.`);
process.exit(1);
}
}
// --- GA4 Data API クライアントの初期化 ---
const analyticsDataClient = new BetaAnalyticsDataClient({
credentials: {
client_email: credentials.client_email,
private_key: credentials.private_key,
},
});
// --- GA4 プロパティIDの取得 ---
const propertyId = process.env.GA4_PROPERTY_ID;
if (!propertyId) {
throw new Error("GA4_PROPERTY_ID is not set in environment variables.");
}
// --- APIリクエストの実行 ---
try {
const [response] = await analyticsDataClient.runReport({
// プロパティIDを指定
property: `properties/${propertyId}`,
// データ取得期間 (過去30日間)
dateRanges: [{ startDate: "30daysAgo", endDate: "today" }],
// 取得するディメンション (ページのパス, ページのタイトル)
dimensions: [{ name: "pagePath" }, { name: "pageTitle" }],
// 取得するメトリクス (表示回数)
metrics: [{ name: "screenPageViews" }], // GA4では "ga:pageviews" ではなく "screenPageViews"
// 並び順 (表示回数の降順 = 多い順)
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: true }],
// 取得件数 (上位10件)
limit: 10,
// ディメンションフィルタ (ブログ記事パス '/blog/' で始まるページのみ対象とする例)
dimensionFilter: {
filter: {
fieldName: "pagePath",
stringFilter: {
matchType: "PARTIAL_REGEXP", // 正規表現に部分一致
value: "^/blog/", // /blog/ で始まるパス
},
},
},
});
// --- 結果の整形 ---
const popularPosts = response.rows.map((row) => ({
pagePath: row.dimensionValues[0].value,
pageTitle: row.dimensionValues[1].value,
pageViews: parseInt(row.metricValues[0].value, 10), // 閲覧数を整数に変換
}));
// --- JSONファイルへの書き出し ---
// プロジェクトルートに data フォルダがなければ作成
const dataDir = path.resolve(__dirname, "../data");
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir);
}
// dataフォルダ内に popular-posts.json として保存
fs.writeFileSync(
path.join(dataDir, "popular-posts.json"),
JSON.stringify(popularPosts, null, 2) // 読みやすいように整形して出力
);
console.log("Successfully fetched popular posts and saved to data/popular-posts.json");
} catch (error) {
console.error("Error fetching Google Analytics data:", error);
process.exit(1); // エラー発生時はプロセスを終了
}
}
// 関数を実行
fetchPopularPosts();
スクリプトのポイント:
- 認証情報: 環境変数 `GA_CREDENTIALS_JSON` があればそれを優先的に使用し、なければローカルの `service-account.json` を読み込みます。これにより、ローカル開発と本番環境(Cloudflare Pagesなど)で認証情報を安全に扱うことができます。(本番環境では、環境変数にJSONキーの内容全体を設定するのが一般的です)
- APIリクエスト: `runReport` メソッドでGA4にリクエストを送ります。
dateRanges
: データ取得期間を指定します(例: “30daysAgo”~”today”)。dimensions
: 取得したい情報の種類(ページのパス、タイトルなど)を指定します。metrics
: 集計したい指標(表示回数 `screenPageViews` など)を指定します。orderBys
: 並び順を指定します(例: 表示回数の多い順)。limit
: 取得する最大件数を指定します。dimensionFilter
: 【重要】 取得するページを絞り込むためのフィルターです。この例では「ページのパス (`pagePath`) が正規表現^/blog/
に一致するもの」だけを取得しています。これにより、ブログ記事以外のページ(トップページ `/` など)がランキングに含まれるのを防ぎます。この `value` は、あなたのブログ記事のURL構造に合わせて必ず変更してください。
- 結果の整形と保存: APIからの応答データを扱いやすいJSON形式(パス、タイトル、閲覧数のオブジェクト配列)に変換し、
data/popular-posts.json
ファイルに書き出します。
このスクリプトをターミナルで node scripts/fetch-popular-posts.js
と実行すると、`data` フォルダ(なければ作成される)に人気記事のデータがJSONファイルとして保存されます。
ビルド時にJSONデータを活用し、静的サイトに組み込む方法
人気記事データを含むJSONファイルが用意できたら、あとは静的サイトジェネレーター(Next.jsやGatsby.js)のビルドプロセスでこのJSONファイルを読み込み、ページやコンポーネントにデータを渡して表示するだけです。
しかし、ここで重要なのは「サイトをビルド(デプロイ)するたびに、このJSONファイルが最新の情報に更新されるようにする」ことです。そうしないと、ランキングが古いままになってしまいます。
これを実現するには、通常、プロジェクトの package.json
ファイル内の scripts
セクションを編集し、ビルドコマンドの実行前にデータ取得スクリプトが実行されるように設定します。
【package.json
の設定例 (Gatsby.jsの場合)】
{
"scripts": {
// データ取得スクリプトを実行するコマンドを定義
"fetch-data": "node scripts/fetch-popular-posts.js",
// 開発サーバー起動時にもデータを取得する場合 (任意)
"develop": "npm run fetch-data && gatsby develop",
// 本番ビルド時に必ずデータ取得を実行するように設定
"build": "npm run fetch-data && gatsby build",
// startコマンドも同様に(開発用サーバー起動など)
"start": "npm run develop",
// 他にも test や serve など...
}
}
この例では、
fetch-data
という名前でデータ取得スクリプトを実行するコマンドを定義しています。build
コマンド(本番用ビルド)の実行時に、まずnpm run fetch-data
を実行し、その後にgatsby build
が実行されるように設定しています。(&&
はコマンドを順番に実行する指定子)- 同様に、開発サーバー起動時 (
develop
,start
) にもデータを取得するようにしています(開発中も最新データで確認したい場合)。Next.jsの場合はnext dev
やnext build
の前にnpm run fetch-data &&
を追加します。
このように設定しておくことで、npm run build
コマンドを実行(またはVercelやCloudflare Pagesなどのホスティングサービスで自動ビルドが実行される際)に、
- まず
fetch-popular-posts.js
が実行され、最新の人気記事データがdata/popular-posts.json
に保存されます。 - 次に、Gatsby (またはNext.js) のビルドプロセスが開始され、その中で
data/popular-posts.json
ファイルを読み込み、人気記事一覧を含む静的HTMLページが生成されます。
この「ビルド時データフェッチ」のアプローチにより、サイト訪問者は常に(ビルド時点での)最新の人気記事一覧を高速な静的ページとして閲覧でき、サーバーへの負荷やAPIの実行時呼び出しを気にする必要がなくなります。これはパフォーマ ンスとセキュリティの観点からもJAMstack構成の大きなメリットです。
あとは、各フレームワークの方法に従って、ビルド時にJSONデータを読み込み、Reactコンポーネントなどに渡して表示する部分を実装してください。(例: Gatsbyではgatsby-node.js
でJSONを読み込みGraphQLデータレイヤーに追加、Next.jsではgetStaticProps
内でfs.readFile
を使ってJSONを読み込むなど)
まとめ:静的サイトでもAPI連携で人気記事一覧は実現できる!
JAMstackやヘッドレスCMSを採用した静的サイト環境では、WordPressのような従来の動的CMSとは異なり、「人気記事一覧」をリアルタイムで表示することは困難です。
しかし、この記事で解説したように、Google Analytics Data API (GA4) を活用し、サイトのビルドプロセス前にアクセスデータを取得・整形してJSONファイルなどの形で保存し、それをビルド時に静的ページに埋め込むというアプローチを取ることで、静的サイトのメリット(高速表示、高セキュリティ、スケーラビリティ)を維持しつつ、最新の人気記事ランキングを表示することが可能になります。
この方法は、特定のCMSやフロントエンドフレームワークに強く依存しないため、Next.js、Gatsby.jsだけでなく、様々なJAMstack構成に応用できます。サービスアカウントキーの安全 な管理や、APIリクエストのフィルター設定など、いくつか注意点はありますが、一度仕組みを構築すれば、自動でランキングが更新される便利な機能を実現できます。
ぜひ、ご自身の静的ブログサイトやWebサイトの構成に合わせて、この手法を参考に「人気記事一覧」の実装に挑戦してみてください。