n8nでGSC・GA4を自動取得する方法|Google Sheetsでキーワード管理した実践ログ
# n8nでGSC・GA4を自動取得する方法|Google Sheetsでキーワード管理した実践ログ
n8nでキーワード管理をしていると、CSVファイルの上書き消去・重複チェック漏れ・データが消えたのかどうかすら分からない状態に陥ることがあります。私もJogtimeのn8nフロー0を構築する中で、同じ問題に何度も直面しました。
この記事では、GSC・GA4データのバッチ取得スクリプトをVPSに設置し、n8nフロー0のキーワードスコアリングに統合するまでの手順を実践ログとして公開します。CSV管理からGoogle Sheets移行の判断理由・26列構成の設計・AI Agentによる定性精査まで、実際に動いた構成をそのまま残しています。
CSV管理をやめてGoogle Sheetsに移行した理由
n8nでキーワードキューをCSVで管理していたとき、最初に困ったのはファイルの上書き消去でした。n8nのCSV書き込みノードは、設定を誤ると既存のデータをまるごと上書きします。バックアップから復元できたものの、その後も「今のCSVが正しいのか」という不安が常につきまとっていました。
Google Sheetsに移行した理由は3つあります。
理由1:ブラウザから直接確認・編集できる
n8nがVPS上で動いている場合、CSVファイルの中身を確認するにはSSH接続が必要です。Google Sheetsならブラウザから即座に確認でき、手動でのステータス変更も簡単です。
理由2:Append or Update Rowで重複防止ができる
n8nのGoogle Sheets連携ノードには「Append or Update Row」という操作があります。指定したキー列(今回はkeyword_ja)で一致するものがあれば更新、なければ追記という動作をします。CSVでは同じ実装が難しく、重複チェックをコードで書く必要がありました。
理由3:statusカラムで多段階管理ができる
todo → selected → writing → drafted → publishedという状態遷移をカラム1つで管理できます。フィルタや条件付き書式も使えるため、運用管理が大幅に楽になります。
移行の手間はありましたが、CSV管理に戻りたいとは思っていません。
GSC・GA4バッチ取得スクリプトをVPSに設置する手順
GSCとGA4のデータをn8nフローの中で取得しようとすると、APIの認証やレート制限の問題が出やすいです。私はVPS上にPythonスクリプトを置き、n8nからSSH経由で実行するバッチ取得方式を選びました。
必要なもの
- サービスアカウント(
bizinets-fetcher@bizinets-metrics.iam.gserviceaccount.com) - JSONキー(
/root/metrics/gsc_ga4_key.json) - GA4プロパティID
- GSCドメインプロパティ(
sc-domain:ドメイン名)
スクリプトの設置手順
# VPS上に配置するディレクトリを作成
mkdir -p /root/metrics
# 必要なPythonライブラリをインストール
pip3 install google-auth google-auth-httplib2 google-api-python-client
# スクリプトを配置(SFTPまたはscpで転送)
scp fetch_metrics_jogtime.py root@VPSのIP:/root/metrics/
# 実行権限を付与
chmod +x /root/metrics/fetch_metrics_jogtime.py
# 動作確認
python3 /root/metrics/fetch_metrics_jogtime.pyスクリプトの出力は /root/metrics/performance_cache_jogtime.json に保存されます。n8nフロー0のSSHノードからこのパスを読み込む構成です。
n8nでの呼び出し方
n8nのSSHノードで以下のコマンドを実行します。
python3 /root/metrics/fetch_metrics_jogtime.py && echo "OK"実行後、別のSSHノードで cat /root/metrics/performance_cache_jogtime.json を実行してキャッシュを読み込みます。
判断基準:
- GSCクエリが0件で返ってくる → Search ConsoleでサービスアカウントにフルユーザーPermissionが付与されているか確認する
- GA4データが取れない → GA4プロパティIDが正しいか・サービスアカウントがGA4プロパティに追加されているか確認する
- スクリプトがエラーで止まる → JSONキーのパスとファイル権限を確認する(
chmod 600 /root/metrics/gsc_ga4_key.json)
n8nフロー0のキーワードスコアリング設計
GSCとGA4のデータが取れたとして、次の問題は「どのキーワードを新規記事候補にするか」の判断です。数値だけで自動的に決めようとすると、サイトのテーマと無関係なキーワードが混入してしまいます。
フロー0のキーワードスコアリングは、以下の2段階で構成しています。
第1段階:コードによる数値フィルタリング
GSCクエリの中から以下の条件をすべて満たすものを通過させます。
return (
q.impressions >= 10 && // 表示回数10以上(需要がある)
q.avg_position >= 5 && // 平均順位5位以下(上位に入っていない)
q.avg_position <= 50 && // 平均順位50位以内(圏外ではない)
ctr < 0.15 // CTR15%未満(クリックされていない=改善余地あり)
);この条件は「需要はあるが、まだ取れていないキーワード」を拾う設計です。順位1〜4位のキーワードは既に上位表示できているため除外します。
第2段階:思想フィルター(Jogtimeの場合)
数値条件を通過したクエリに対して、サイトテーマへの適合判定を行います。
// 除外ワード(テーマ外・YMYL過剰リスク)
const excludeWords = ['病院', '診断', '治療', '手術', '薬', ...];
// 適合ワード(Jogtimeのテーマに合うもの)
const includeWords = ['フレイル', '介護予防', '外出', '歩く', 'ウォーキング', ...];
// 除外ワードを含むものは除外・適合ワードを含むもののみ通過
if (excludeWords.some(w => query.includes(w))) return false;
if (!includeWords.some(w => query.includes(w))) return false;この思想フィルターはサイトによって完全に書き直す必要があります。bizinets.bizとjogtime.jpでは適合ワードがまったく異なります。
各キーワードにはSEOスコア・GEOスコア・YMYLスコアを算出して付与し、スコア降順でソートして最大30件をAI Agent精査に渡します。
AI Agentでキーワードを定性精査する設計
数値スコアリングでは「このキーワードで記事を書く価値があるか」という定性的な判断ができません。競合記事の質・検索意図のずれ・すでに似た記事があるかどうかは、数値だけでは判断できないためです。
n8nのAI Agentノード(GPT-4oとTavily Web Searchを組み合わせ)でSERP分析を行い、各キーワードに対してapproved/rejectedの判定を返す設計にしています。
例えば「表示回数が増えている」だけでは、サイトテーマとの相性までは判断できません。Jogtimeでは「需要がある」だけでは採用せず、「フレイル予防の思想に合うか」まで確認しています。この定性判定をAI Agentに補助させています。
AIへの指示の設計
AIに渡すプロンプトの骨格はこうなっています。
以下のキーワード候補について、SERPを調査してください。
- 検索意図が明確で、Jogtimeのテーマと一致するか
- 上位記事との差別化余地があるか
- YMYL強度が高すぎてライターとして書けない内容ではないか
approved/rejectedを判定してJSONで返してください。パースの設計
AIが返すJSONをn8nのCodeノードで受け取ります。
const raw = $input.first().json.output[0].content[0].text;
const cleaned = raw.replace(/```json|```/g, '').trim();
const parsed = JSON.parse(cleaned);
return [{
json: {
approved: parsed.approved ?? [],
rejected: parsed.rejected ?? [],
}
}];AIが返すJSONはコードブロックで囲まれていることが多いため、`json と ` を除去してからパースします。この処理を入れないとSyntaxErrorになります。
approvedになったキーワードのみGoogle Sheetsに追記され、rejectedは通知なしでスキップされます。
ただし、このままだと取得したデータをどう設計してキーワード判断に使うかは決められません。
なぜなら、「何をどの順番でスコアリングするか」という設計判断の基準がまだ整理されていないからです。
→ 判断軸の整理はこちら
Google Sheets 26列構成の設計と各カラムの役割
キーワード管理シートは最終的に26列構成になりました。最初は10列程度で始めましたが、運用を続けるうちに管理したい情報が増え、最終的に26列構成になりました。どのカラムが本当に必要で、どれが後付けになったか気になりませんか?
重要なのは「最初から完璧を目指さないこと」です。まず必要最低限で作り、運用しながら足りない列を追加する方が管理しやすくなります。
主要なカラムとその役割は以下の通りです。
カラム名 | 役割
--- | ---
queue_id | 一意のID(Q001〜)
keyword_ja | 重複防止のキー列(Append or Update Rowで照合)
intent_ja | 検索意図(AI判定)
article_type | 記事タイプ(how-to / explanation / list等)
frailty_stage | フレイルステージ(Jogtime専用)
target_reader | ターゲット読者分類(5種)
ymyl_status | YMYL判定結果
status | 処理ステータス(todo→drafted→published等)
assigned_slug | 生成されたslug
wp_post_id | WordPressの投稿ID
error_log | エラー内容の記録特に重要なのはkeyword_jaとstatusです。keyword_jaはAppend or Update Rowのキーになるため、表記の揺れ(全角・半角・スペースの有無)があると重複防止が機能しません。n8nのCodeノードで.trim().toLowerCase()を通してから渡すことで対処しています。
error_logカラムは後から追加しましたが、あって良かったと感じています。n8nのフローがエラーで止まったとき、どのキーワードでどんなエラーが起きたかをSheetsで確認できると、デバッグが格段に早くなります。
よくある質問
フロー0の構築で詰まりやすいポイントを3つまとめました。同じ問題で困っている方はいないでしょうか。
Q. GSCデータが取れているのにクエリが0件になります。
Search ConsoleのSettings → Users and permissionsで、サービスアカウントに「フルユーザー」権限が付与されているか確認してください。権限変更後は反映まで時間がかかる場合があります。
Q. Append or Update Rowで重複が発生します。
keyword_jaの値に表記ゆれがあると別キーとして扱われます。n8nのCodeノードで.trim().toLowerCase()を通してからSheetsに渡してください。また、Sheets側のカラム名が完全に一致していないと照合が機能しないため、スペルミスにも注意が必要です。
Q. AI Agentの精査に時間がかかりすぎます。
Tavily Web SearchはAPIコールごとに数秒かかるため、キーワードが多いと全体の処理時間が長くなります。スコアリングの段階で上位10〜15件に絞ってからAI Agentに渡すか、n8nのタイムアウト設定を延長することで対処できます。
まとめ
GSC・GA4のデータをn8nで自動取得してGoogle Sheetsで管理する構成は、最初の設置に少し手間がかかりますが、一度動き始めると週次で安定的に動いてくれます。
今日できる一歩として、まずサービスアカウントのSearch Console権限を確認することをおすすめします。GSCクエリが0件で返ってくる問題の多くはここで解決します。権限確認後にスクリプトを再実行すれば、データが取れるようになります。
CSV管理からの移行は「大げさすぎる」と思っていましたが、Sheetsに移行してからキーワード管理のストレスが大幅に減りました。同じ構成を検討している方の参考になれば幸いです。
ただし、このままだと自分のサイトに合ったスコアリング設計や思想フィルターをどう判断するかは決められません。
なぜなら、「何を基準にキーワードを採用・却下するか」という設計判断の軸が、まだ整理されていないからです。
→ 判断軸の整理はこちら
bizinets.biz
記事を読んで「もっと知りたい」と思ったあなたへ
bizinets.biz では、ビジネスの仕組みづくりを体系的に学べるコンテンツを用意しています。まずは一度、覗いてみてください。
bizinets.biz へ行く →