第8回 GA4 Data APIで記事別PVを取得する―Google Analyticsからアクセスデータを取得
Google Analytics Data APIを有効化し、gcloud CLIとOAuth Desktop ClientでADC認証を設定。Node.jsからpagePathとscreenPageViewsを取得し、ゆまラボの記事別PVを実データで確認した記録です。

第7回では、Bing Webmaster Toolsへbringain.comを登録し、X投稿に付けたUTMからGA4でx / socialの流入まで確認した。
一方、第3回 人気記事を自動表示したい―Cloudflareでも見られるがGoogle Analyticsを使うことにするでは、将来トップページへ直近30日の人気記事を自動表示するため、Google Analytics Data APIから記事別の表示回数を取得する方針を決めていた。
第4回 Google Analyticsをゆまラボへ導入する―GA4を設定してリアルタイム計測まで確認でGA4を導入してからデータもたまってきた。
今回は、そのデータを管理画面で見るのではなく、Google Analytics Data APIから実際に取得するところまで進める。
トップページへの人気記事表示はまだ作らない。今回の範囲は、/blog/配下のpagePathとscreenPageViewsをAPIから取得し、ターミナルで確認するところまでとした。
GA4のプロパティIDを確認する#
Data APIを呼び出す前に、Google Analyticsでゆまラボのプロパティを確認した。

Data APIでは、Googleタグで使うG-から始まる測定IDではなく、GA4の数値プロパティIDを指定する。
今回使用するプロパティは既存のゆまラボ用GA4プロパティで、新しく作り直してはいない。
Google Analytics Data APIを有効にする#
Google Cloud側では、今回使うプロジェクトからGoogle Analytics Data APIを開いた。
最初はまだ有効になっておらず、「有効にする」が表示されている。

そのままAPIを有効化した。

ここで外部サービス側の準備はできたが、ローカルのNode.jsからAPIを呼ぶには認証も必要になる。
gcloud CLIが入っていなかった#
既存環境を確認すると、gcloud CLIは未導入。
そのため、認証やAPI実装へ進む前にGoogle Cloud CLIをWindowsへインストールした。
インストール後にPowerShellを開き直し、gcloud --versionを確認した。

確認時点ではGoogle Cloud SDK 585.0.0が起動している。
ここからApplication Default Credentials(ADC)を使って、Node.jsクライアントからGoogle Analytics Data APIへアクセスする準備を進めた。
最初のADC認証は「このアプリはブロックされます」で失敗した#
最初は、ユーザーアカウントでADCを作る通常の流れとして、analytics.readonlyを含むスコープで認証を開始した。
しかしGoogleの認可画面まで進むと、次の表示で止まった。

「このアプリはブロックされます」と表示され、そのまま認証を完了できなかった。通常のADC認証でそのまま進めるつもりだったので、ここは予想外だった。
ここでサービスアカウントへ切り替えたり、認証情報を別方式で保存したりはしなかった。
Google CloudのADCドキュメントを確認すると、Google Cloud以外のサービス向けスコープを追加してユーザー認証を使う場合は、OAuthクライアントIDを作り、gcloud auth application-default loginへ--client-id-fileと--scopesを指定する方法が案内されている。
今回はその方法へ変更した。
Google Auth Platformを構成する#
Google Cloud ConsoleでGoogle Auth Platformを開くと、まだ構成されていない。

今回の用途は自分のローカル環境からゆまラボのGA4を読むことなので、外部向けのテスト状態で設定し、実際に認証へ使うGoogleアカウントをテストユーザーへ追加した。

※ 公開不要なメールアドレス部分は画像内で伏せている。
続いてData AccessからGoogle Analyticsの読み取りスコープを追加した。

追加したスコープは次のもの。
https://www.googleapis.com/auth/analytics.readonly
さらに、ローカルで使うOAuthクライアントをDesktop appとして作成した。

ここで発行したOAuthクライアントのJSONはリポジトリ外へ保存した。記事用ファイルやGit管理対象には含めていない。
OAuth Desktop Clientを指定してADC認証をやり直す#
作成したOAuthクライアントを--client-id-fileで指定し、ADC認証をもう一度実行した。
認可画面では、Google Analyticsのデータ参照とGoogle Cloud側の権限が表示された。

※ Googleアカウントを特定できる表示は画像内で伏せている。
この認可を続行でき、gcloud CLI側でも認証完了まで進んだ。

その後、gcloud auth application-default print-access-tokenでADCが利用できることだけ確認した。
アクセストークン自体は記事へ残していない。ファイルへ保存もしていない。
なお、Codexを実行していたPowerShellではインストール後のPATHがまだ反映されていなかったため、確認時はインストール済みのgcloud.cmdを絶対パスで実行した。認証方式を変えたわけではない。
Node.jsからData APIを呼ぶ#
認証が通ったところで、Astroリポジトリ側へGoogle Analytics Data APIのNode.jsクライアントを追加した。
追加したパッケージは次の1つ。
@google-analytics/data 7.1.0
変更したファイルは3つ。
package.json
package-lock.json
scripts/ga-pageviews.mjs
AstroのページやTOPページは変更していない。PVデータを保存するJSONや定期実行も追加していない。
scripts/ga-pageviews.mjsではBetaAnalyticsDataClientからrunReport()を実行する形にした。
指定した条件は以下。
property properties/553074385
dimension pagePath
metric screenPageViews
startDate 30daysAgo
endDate yesterday
filter pagePath BEGINS_WITH /blog/
order screenPageViews DESC
Google Analytics Data APIでは、pagePathはホスト名とクエリ文字列の間にあるページパス、screenPageViewsはWebページまたはアプリ画面の表示回数として取得できる。
今回はBEGINS_WITH /blog/で絞り、記事に関係するURLを先に取得する形にした。
まだ「公開済みMarkdownと一致するURLだけに限定する」「一覧ページを除外する」といった追加処理は入れていない。
記事別PVを74件取得できた#
実行したコマンドはこれだけ。
node scripts/ga-pageviews.mjs
実際の取得結果では74行が返った。

取得時点の上位10件は次の結果。
/blog/ 416
/blog/codex-luna-astra-astro-comparison/ 66
/blog/sns-publishing-candidates/ 38
/blog/27-astro-image-optimization-lazy-loading/ 30
/blog/technical-blog-monetization/ 30
/blog/01-blog-monetization-models/ 26
/blog/chatgpt-url-cache-miss-web-search/ 25
/blog/02-google-adsense-application/ 19
/blog/codex-full-access-permission-profile/ 19
/blog/yumalabo-responsive-browser-test/ 18
ここで1つ分かったことがある。
/blog/で始まるパスをそのまま対象にしたため、記事詳細だけではなく記事一覧の/blog/も含まれている。取得結果では/blog/が416で先頭になった。
さらに、GA4に残っている実データには次のような不自然なpagePathも1件あった。
/blog/28-astro-eyecatch-image/](https:/bringain.com/blog/28-astro-eyecatch-image/
APIから何が返るかを確認する回なので、この段階では削除も正規化もしていない。
人気記事として実際にTOPへ表示するときは、/blog/一覧を除外し、現在公開されている記事slugとの照合も必要になる。
この確認ができたことで、「Data APIを呼べればそのまま人気記事ランキングになる」わけではなく、取得後の絞り込みがもう1段必要なことも分かった。
Astroのビルドを確認する#
Data API取得後にnpm run buildを実行した。

結果は成功。
確認できた内容は以下。
Astro 235ページ生成
Pagefind 78ページをインデックス
内部リンク 9536件確認
broken links 0件
既存のFrontmatter警告7件、npm install時のWindows権限警告、node-domexception@1.0.0のdeprecated警告、npm auditのhigh severity 3件は出ているが、今回のData API実装によるビルドエラーは発生していない。
今回の範囲外なので、それらの既存警告や依存関係の修正は行わなかった。
最終的なGitの変更も、今回の3ファイルだけになっている。
M package-lock.json
M package.json
?? scripts/ga-pageviews.mjs
pagePathとPVを取得できた#
第3回で考えていた「Google Analyticsのデータをプログラムから取得する」ところまで、実データで確認できた。
今回行った作業をまとめる。
GA4プロパティを確認
↓
Google Analytics Data APIを有効化
↓
gcloud CLIを導入
↓
通常のADC認証を試す
↓
「このアプリはブロックされます」で停止
↓
Google Auth Platformを構成
↓
OAuth Desktop Clientを作成
↓
--client-id-file付きでADC認証
↓
@google-analytics/dataを追加
↓
runReport()でpagePath / screenPageViewsを取得
↓
74行の実データを確認
↓
npm run build成功
今回はPVを取得しただけで、TOPページの「注目コンテンツ」はまだ変更していない。
次に人気記事を自動表示する場合は、今回見つかった/blog/一覧や不自然なpagePathをどう扱うかを決め、公開中の記事と照合してから上位3~5件を表示する処理へ進む。


