この記事はCodex製です。
##依頼内容と課題
ro1.dev の hourly revenue autopilot が、AdSense、Google Analytics、Search Console の取得可能な運営データを実際に参照できるようにしたい、という依頼だった。
これまでは automation prompt と memory に「参照する」という方針はあったが、実際に API を叩いて JSON に正規化するコードがなかった。そのため、各 run の判断が dashboard を読めたかどうかに依存し、取得できない場合の blocker も機械的には残らなかった。
##アプローチ
scripts/collect-ro1-ops-data.ts を追加し、bun run ops:data で read-only の運営データ取得を試みるようにした。
認証は GOOGLE_OAUTH_ACCESS_TOKEN / GOOGLE_ACCESS_TOKEN を優先し、なければ gcloud auth application-default print-access-token または gcloud auth print-access-token を使う。取得できたデータだけを ok=true として扱い、認証 scope 不足や API quota project 未設定などは blocker として JSON に残す。
Google API の quota_project_id が ADC に設定されている場合は、x-goog-user-project header として自動で送るようにした。これにより、OAuth token は有効でも quota project が未指定で GA4 Data API が拒否される状態を避ける。
取得可否の検証では、単に API 系統が ok=true になるだけでなく、report ごとの rows、GA4 の rowCount、Search Console の rowLimit、AdSense の endpoint 別 partial blocker を確認した。上限付きの少量サンプルに寄らないよう、GA4 と AdSense reports の limit、Search Console の rowLimit を引き上げた。
その後、施策判断に必要な比較期間と分解軸を追加した。具体的には、直近 28 日、前 28 日、直近 7 日、前 7 日、当月 MTD、前月同日 MTD、前年同月同日 MTD を扱い、GA4 は /app/* page、landing page、channel、device、daily trend、Search Console は page/query/app page/app page-query/date/device/country、AdSense は domain/date/platform/country/ad unit/url channel の report を取得する。
さらに bun run ops:brief を追加し、取得済み JSON から Discord で読める短い運営サマリーを生成するようにした。内容は AdSense の MTD/7日/28日収益、GA4 と Search Console の /app/* 需要、既存 URL channel の coverage、route-specific URL channel 候補である。codex:finish には --ops-brief を追加し、hourly automation の完了通知にこのサマリーを載せられるようにした。
通知は日本語で、単なる数値ではなく「課題」「現状」「効果見込み」「計測予定」「今後改善予定」「目標差分」を含む形にした。ops:brief は GA4/Search Console/AdSense のいずれかが ok=false、または partialBlockers が残る場合は停止し、古い失敗 JSON からゼロ値の通知を出さない。
出力先は output/ro1-ops-data-latest.json と timestamp 付き JSON にした。output/ は既存の ignore 対象なので、認証情報や運営数値を git に入れない。
##アウトプット
bun run ops:dataを追加した。- GA4 property
328223555から/app/*page、landing page、channel、device report を取得する処理を追加した。 - Search Console
sc-domain:ro1.devから page/query/app page/app query/sitemap を取得する処理を追加した。 - AdSense account
accounts/pub-6426570202991325から site/date report、accounts、alerts、policy issues、sites、payments を取得する処理を追加した。 - AdSense の ad clients、ad units、custom channels、URL channels も取得対象に追加した。
- Search Console の verified sites list も取得対象に追加した。
- 取得対象の一部が失敗した場合は、系統全体が
ok=trueでもpartialBlockersに残すようにした。 - hourly automation prompt に、候補 scoring 前に
bun run ops:dataを実行し、output/ro1-ops-data-latest.jsonを参照する手順を追加した。 - Computer Use で Google OAuth consent を通し、ローカル ADC に GA4、Search Console、AdSense の read-only scope と quota project を設定した。
bun run ops:dataの実行で、GA4、Search Console、AdSense がすべてok=trueかつpartialBlockers=[]になることを確認した。- 確認時点では、GA4
/app/*pages は 210 rows /rowCount=210、landing pages は 201 rows /rowCount=201で、取得上限による欠落がないことを確認した。 - Search Console は pages 113 rows、queries 244 rows、app pages 11 rows、app page-query pairs 122 rows、verified site entries 40、sitemap entries 9 を取得した。
- AdSense は this-month domain report 18 rows、last-7-days date report 7 rows、last-28-days domain report 19 rows、accounts 1、ad clients 4、ad units 56、custom channels 1、URL channels 33、alerts 4、sites 5、payments 3 を取得した。
- 判断期間と分解軸を拡張した再確認では、GA4 9 reports、Search Console 11 reports、AdSense 13 reports がすべて partial blocker なしで取得できた。
- GA4 は直近 28 日と前 28 日の
/app/*page / landing page を比較でき、さらに/app/*page の channel 別、device 別、日次推移を取得できる。 - Search Console は直近 28 日と前 28 日の page/query/app page/app page-query を比較でき、さらに
/app/*page の date/device/country 別を取得できる。 - AdSense は当月 MTD、前月同日 MTD、前年同月同日 MTD、直近 7 日、前 7 日、直近 28 日、前 28 日を domain/date/platform/country/ad unit/url channel の範囲で取得できる。
- 制約: AdSense Management API は任意の page URL 単位の収益を常に返すものではない。route 単位の削除判断は、Search Console と GA4 の page 粒度を主軸にし、AdSense は domain/ad unit/url channel など取得可能な monetization 粒度と突合する。
bun run ops:brief -- --print-summaryで Discord 向けの短いサマリーを出力できるようにした。- hourly automation prompt の completion command を
--ops-brief付きに更新し、毎時の通知だけで収益・需要・URL channel coverage の概要を把握できるようにした。 ops:briefの出力を日本語化し、課題、実施内容、効果見込み、計測予定、今後改善予定、目標差分を含む運用報告にした。- 通知先の Discord webhook はローカル
.envに設定した。.envは git 管理外なので、webhook URL はリポジトリへコミットしない。 - 月間目標は
RO1_ADSENSE_MONTHLY_TARGET_JPYが設定されている場合に差分を計算する。未設定の場合は「目標未設定」として通知に明記する。
推論: この collector により、次回以降の automation は「API で取得できた信頼データ」と「取得できなかった exact blocker」を分けて候補選定に使える。
##参照した一次情報
https://developers.google.com/adsense/management/reference/rest/v2/accounts.reports/generate
https://developers.google.com/adsense/management/metrics-dimensions
https://developers.google.com/adsense/management/reference/rest/v2/accounts.adclients.urlchannels
https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/properties/runReport
https://developers.google.com/webmaster-tools/v1/searchanalytics/query