n8nでSEOの日次順位レポートを作成するには?
手作業での順位トラッキングは、データを取得してシートに貼り付け、前日と比較し、また同じ作業を繰り返すという負担の大きい作業です。この定義では、n8nがSEMrush、Google Sheets、Slackを1つの自動化ワークフローにつなぎ、プロセス全体を毎日のスケジュールで処理する仕組みを説明します。この作業を手作業で続けたくない方は、ここから始めてください。
寄稿者
SaaS Hackers
簡単な答え:n8nで毎日のSEO順位レポートを作成するには、SEMrushのAPIをスケジュールどおりに呼び出してキーワードの順位データを取得し、変化検出のステップで順位変動にフラグを付け、整形したサマリーをSlackに送信します。ワークフロー全体が自動で動くため、手動エクスポートやスプレッドシートの手作業は不要です。
手作業で行うと、順位トラッキングは毎朝20~30分かかる作業です。SEMrushからデータを取得し、シートに貼り付け、前日と比較し、変動の大きいキーワードを強調して、チームにサマリーを送ります。このチュートリアルでは、このプロセス全体をn8nの中に構築し、毎日、朝のコーヒーを飲む前に自動で実行されるようにする方法を紹介します。
最終的に、SEMrushから毎日のスケジュールでキーワード順位を取得し、前日のデータとの順位変動を検出して、見やすいレポートをSlackチャンネルに送信する、動作するワークフローが完成します。
始める前に必要なもの
- n8nのインスタンス(セルフホスト版またはn8n Cloud)
- SEMrushのAPIキー(SEMrushの有料プランであればどれでも利用可能)
- ボットトークンとレポート用チャンネルを備えたSlackワークスペース
- 過去の順位データを保存するGoogle Sheet(実行間の永続的なメモリとして機能します)
ステップ1:スケジュールトリガーを設定する
自動レポートはすべてトリガーから始まります。n8nで新しいワークフローを開き、Schedule Triggerノードを追加します。
1日に1回実行するよう設定します。おすすめの初期設定は現地時間の7:00です。チームの朝のスタンドアップが始まる前に、レポートがSlackに届きます。
適用する設定:
- Trigger interval: Days
- Run every: 1
- At hour: 7
- At minute: 0
ノードを保存します。これがワークフロー全体の心臓部です。
ステップ2:SEMrushからキーワード順位を取得する
Schedule Triggerの後にHTTP Requestノードを追加します。SEMrushはAPIを通じて順位データを提供しており、n8nのHTTP Requestノードを使えばこの呼び出しをすっきり処理できます。
HTTP Requestノードを設定します:
- Method:
GET - URL:
https://api.semrush.com/ - Query parameters(それぞれ別のフィールドとして追加):
type=domain_ranks(またはphrase_organicキーワード単位のデータを取得する場合)key= SEMrushのAPIキーdomain= トラッキング対象のドメインdatabase= 対象国のデータベース(例:usは米国)export_columns=Ph,Po,Nq,Cp,Ur(Phrase、Position、Search Volume、CPC、URL)
キーワード単位で順位をトラッキングする場合は、次を使用し、 type=phrase_organic さらに、キーワードごとに phrase パラメータを追加します。キーワードのリストをトラッキングする場合は、次のノードでループ処理します: n8n Split In Batches ノード(ステップ3で説明します)。
レスポンスの例:
SEMrushはセミコロン区切りのテキストでレスポンスを返します。HTTP Requestの後にCodeノードを追加し、整ったJSONに変換します。
const lines = $input.first().json.data.split('\n');
const headers = lines[0].split(';');
const rows = lines.slice(1).filter(line => line.trim() !== '');
return rows.map(row => {
const values = row.split(';');
const obj = {};
headers.forEach((header, i) => {
obj[header.trim()] = values[i]?.trim();
});
return { json: obj };
});これにより、キーワードごとに1つのアイテムが作成され、次のようなフィールドが含まれます。 Keyword, Position, Search Volume、および URL.
ステップ3:キーワードリストをループ処理する
ドメインの全順位を取得するのではなく、あらかじめ決めたキーワードリストをトラッキングする場合は、キーワードリストをGoogle Sheetに保存し、ワークフローの冒頭で読み込みます。
HTTP Requestの前にGoogle Sheetsノードを追加します。
- Operation: Read Rows
- Sheet: キーワードトラッキング用のシート(例:「Keywords」)
- Range: A:A(キーワードはA列)
次にSplit In Batchesノードを追加し、各キーワードを順に処理して、キーワードごとにSEMrush APIを個別に呼び出します。データを整理し、レート制限の問題を避けるため、バッチサイズは1に設定してください。
接続順:Google Sheets → Split In Batches → HTTP Request → Code(パーサー)
ステップ4:Google Sheetsから前日の順位を読み込む
変化を検出するには基準となるデータが必要です。Google Sheetは過去データの保存先としても使えます。当日のデータを変換した後、Google Sheetsノードをもう1つ追加して、前日の順位を読み込みます。
トラッキング用シートは次の列で構成します。
| Date | Keyword | Position | URL | Search Volume |
Google Sheetsノードの設定:
- Operation: Read Rows
- Filter by date: 前日の日付(次のような式を使用:
{{ $now.minus({days: 1}).toFormat('yyyy-MM-dd') }})
次に、 Merge ノードを追加し、当日のデータと前日のデータを次のフィールドで結合します: Keyword フィールド。 Merge by Key モードを使用し、 Keyword を照合フィールドに指定します。
これで、各アイテムに同じキーワードの現在の順位と前回の順位の両方が含まれる結合データセットができます。
ステップ5:順位の変化を検出する
Mergeノードの後にCodeノードを追加し、各キーワードの変化を計算して、大きく動いたキーワードにフラグを付けます。
return $input.all().map(item => {
const today = parseInt(item.json.Position_today) || 0;
const yesterday = parseInt(item.json.Position_yesterday) || 0;
const change = yesterday - today; // positive = improved, negative = dropped
let status = 'stable';
if (change >= 3) status = 'improved';
if (change <= -3) status = 'dropped';
return {
json: {
keyword: item.json.Keyword,
position_today: today,
position_yesterday: yesterday,
change: change,
status: status,
url: item.json.URL_today
}
};
});しきい値(現在は3位に設定)は、アラートの感度に応じて調整できます。遷移先のページ自体も改善したい場合、こうした順位変動は、メッセージの強化やコンバージョンを意識した更新が必要なページを示していることが多くあります。そのため、SEOのワークフローとあわせて、実績のあるSaaSランディングページのベストプラクティスと事例も確認しておくとよいでしょう。
ステップ6:当日のデータをGoogle Sheetsに書き戻す
レポートを送信する前に、当日の順位を保存し、翌日の基準データにします。
Google Sheetsノードを追加します。
- Operation: Append Row
- フィールドをマッピングします:Date(当日の日付)、Keyword、Position、URL、Search Volume
このノードは変化検出のステップの後に実行されるため、常に日次の履歴が更新され続けます。
ステップ7:Slackレポートを整形して送信する
Slackメッセージを作成するCodeノードを追加します。見やすいレポートは、上昇したキーワード、下落したキーワード、変動のないキーワードを分けて表示するので、30秒以内にざっと確認できます。
const items = $input.all().map(i => i.json);
const improved = items.filter(i => i.status === 'improved');
const dropped = items.filter(i => i.status === 'dropped');
const formatRow = (i) =>
`• *${i.keyword}*: ${i.position_today} (was ${i.position_yesterday}, ${i.change > 0 ? '+' : ''}${i.change})`;
const message = [
`*Daily SEO Rank Report – ${new Date().toDateString()}*`,
'',
improved.length > 0 ? `*Improved (${improved.length})*\n${improved.map(formatRow).join('\n')}` : '',
dropped.length > 0 ? `*Dropped (${dropped.length})*\n${dropped.map(formatRow).join('\n')}` : '',
`_${items.length} keywords tracked_`
].filter(Boolean).join('\n');
return [{ json: { message } }];次にSlackノードを追加します。
- Resource: Message
- Operation: Send
- Channel: レポート用チャンネル(例:
#seo-reports) - Text:
{{ $json.message }}
ステップ8:エラーハンドラーを追加する
本番運用のワークフローにはフォールバックが必要です。次のノードを追加します: Error Trigger ノードを追加し、2つ目のSlackノードに接続して、いずれかのステップが失敗した場合に次のチャンネルへ投稿します: #workflow-errors チャンネル。
これにより、レポートが届かないのに誰も気づかず、順位がすでに変動してしまってから発覚するという、サイレント障害を防げます。
完成したワークフローの全体像
Schedule Trigger (07:00 daily)
→ Google Sheets (read keyword list)
→ Split In Batches
→ HTTP Request (SEMrush API)
→ Code (parse response)
→ Google Sheets (read yesterday's data)
→ Merge (by keyword)
→ Code (change detection)
→ Google Sheets (append today's data)
→ Code (format Slack message)
→ Slack (send report)ノード数の合計:エラーハンドラーの設定にもよりますが10~11個です。n8nに慣れている方が初めて構築する場合の所要時間は、おおよそ90分です。
よくある問題と対処法
SEMrushが空のデータを返す
次のパラメータを確認してください: database 対象市場に合った地域のデータベースが指定されているか確認します。また、APIキーに十分なユニットが残っているかも確認してください。キーワードを1件調べるごとにAPIクレジットを消費します。
Mergeノードで一致するデータが見つからない
多くの場合、書き込みステップと読み込みステップで日付の形式が一致していないことが原因です。次の形式に固定してください: yyyy-MM-dd 全体を通して、次を使用します: $now.toFormat('yyyy-MM-dd').
Slackメッセージが長すぎる
Slackは4,000文字を超えるメッセージをブロックします。50~60を超えるキーワードをトラッキングしている場合は、Slackへの出力を5位以上変動したキーワードのみに絞り込み、全体像はGoogle Sheet全体へのリンクで確認できるようにします。
SEMrushのレート制限
Split In Batchesのループ内のバッチ間にWaitノード(1秒に設定)を追加します。SEMrushのAPIは短時間の集中アクセスは許容しますが、高速なリクエストを継続すると429エラーが返されます。
このワークフローを拡張するには
基本のワークフローが安定して動くようになったら、次の3つの拡張で大きな価値を加えられます。
週次サマリーダイジェスト:月曜日に実行する2つ目のSchedule Triggerを追加し、Google Sheetsの過去7日分のデータを読み込んで、日次レポートとあわせて週次のトレンドサマリーを送信します。
しきい値アラートのみ:ワークフローを複製し、日次サマリーを取り除きます。このバージョンでは、キーワードが1日で5位を超えて下落した場合にのみSlackノードが動作するよう設定します。クライアント向けのモニタリングなど、ノイズよりもシグナルが重要な場面で使います。
Google Looker Studioとの連携:Google Sheetはすでに整ったデータテーブルになっています。これをLooker Studio(無料)に接続すれば、毎朝自動で更新されるライブの順位推移チャートを作成できます。
よくある質問
n8nの毎日のSEO順位レポートのワークフローは何をしますか?
自動の毎日のスケジュールでSEMrushからキーワードの順位データを取得し、各キーワードの現在の順位をGoogle Sheetsに保存された前日のデータと比較して、大きな順位変動を特定し、整形したサマリーをSlackチャンネルに送信します。一度設定すれば、手動の操作なしで動作します。
n8nでこれを構築するのに、コーディング経験は必要ですか?
必須ではありませんが、基本的なJavaScriptを読んで編集できる程度の知識は必要です。このワークフローのCodeノードでは、シンプルな配列メソッドを使っています。上の例に沿って変数名を調整できれば、このワークフローを構築できます。HTTP Request、Google Sheets、Slackの各ノードは、すべてポイント&クリックで設定できます。
このワークフローを毎日実行するコストはどのくらいですか?
n8n Cloudの料金は月額約$20からです。SEMrush APIの費用は、プランとキーワード数によって異なります。各 phrase_organic の検索は、1回につき10 APIユニットを消費します。50キーワードを毎日トラッキングすると500ユニットを使いますが、これはほとんどのSEMrush有料プランの範囲内です。この用途であれば、SlackとGoogle Sheetsは無料で利用できます。
SEMrushの代わりに、別の順位トラッキングAPIを使えますか?
はい。DataForSEOとBright DataはどちらもREST APIを提供しており、このチュートリアルと同じ手順でn8nのHTTP Requestノードから利用できます。どのAPIを選ぶ場合でも、Codeノードの変換処理は、そのAPIのレスポンス形式に合わせて調整する必要があります。
ワークフローが夜間に失敗した場合はどうなりますか?
ワークフローの最後にあるError Triggerノードがあらゆる失敗を検知し、エラー用のSlackチャンネルにアラートを送信します。このノードがないと、失敗に気づけません。スケジュール実行のワークフローは、本番運用に入れる前に必ずエラー処理を追加してください。
このワークフローは、複数のクライアントを担当するエージェンシーでも使えますか?
調整すれば使えます。最もシンプルな方法は、クライアントごとにワークフローを複製し、ドメイン、キーワードシート、Slackチャンネルを差し替えることです。より高度な構成では、クライアント設定シートを読み込み、各クライアントの設定を動的にループ処理する1つのワークフローを使います。SEOレポート、自動化、あるいはより広範なグロースの仕組みを拡張するために外部の支援が必要になった場合は、SaaS Hackersで専門家を探すこともできますし、実装を支援する審査済みのB2B SaaSのSEOエージェンシーを見ることもできます。
寄稿者
SaaS Hackers


