- 動作確認日:2026-10-01
- n8nのバージョン:2.41.3(Docker、セルフホスト)
目次
① 結論:このワークフローでできること
ブログのRSSフィードを読み込み、記事ごとに「公開日・タイトル・URL」をGoogleスプレッドシートに1行ずつ記録します。
- 同じURLの記事は、上書きされます。何回実行しても、行が重複しません。
- URLの
?utm_source=...は取り除いてから記録します。 - 使う認証情報(Credentials)は、Google Sheetsの1つだけです。
- 動作確認のため、起動にはWebhookを使っています。実際に使うときは、定期実行に置き換える想定です。
② 完成イメージ

WebhookのURLにGETでアクセスすると、シートに記録したうえで、次の文章が返ってきます(実際の出力です)。
10件をシートに記録しました
記録されたシートは、次のとおりです。

実行したときの件数の流れは、次のとおりです。
| ノード | 出てきた件数 |
|---|---|
| Webhook | 1 |
| RSS Read | 10 |
| Format Row | 10 |
| Google Sheets | 10 |
| Respond to Webhook | 10(返事は1回だけ) |
同じワークフローを3回実行したあとも、シートは10行のままでした。URLも10件すべて別々で、重複はありませんでした。
動かしてみて気づいた点が3つあります。
- 空のシートでも、1回目の実行で1行目に見出し(
published、title、url)が自動で入りました。 2026-09-30 08:02という文字で送った公開日は、シート上では日時として扱われ、2026-09-30 8:02と表示されました。並べ替えに使えます。- URLの列では、一部のセルがリンク先ページのタイトルの表示(スマートチップ)に変わりました。セルの中身はURLのままです。
③ 使うノードと必要なもの
必要なもの
- n8n(今回はバージョン2.41.3をDockerで動かしました)
- 読み込みたいRSSフィードのURL(今回は
https://automatelabo.com/feed) - 記録先のGoogleスプレッドシート(空のもので大丈夫です)
- 認証情報:Google Sheets OAuth2 API(Google Cloudで作ったOAuthクライアントを使います)
使うノード
| ノード | 役割 | 設定したこと |
|---|---|---|
| Webhook | 動作確認用の起動ボタン | Path:test-rss-sheets、Respond:Using 'Respond to Webhook' Node |
| RSS Read | フィードを読み込む | URL:https://automatelabo.com/feed |
| Edit Fields(Format Row) | シートに書く3つの項目を作る | 下の表のとおり |
| Google Sheets | シートに追記、または上書きする | Operation:Append or Update Row、Column to match on:url |
| Respond to Webhook | 記録した件数を返す | Respond With:Text、本文:{{ $input.all().length }}件をシートに記録しました |
Edit Fields(Format Row)では、次の3つの項目を作っています。コードは書かずに、式(Expression)だけで済みます。
| 項目名 | 値 |
|---|---|
published | {{ DateTime.fromISO($json.isoDate).setZone('Asia/Tokyo').toFormat('yyyy-MM-dd HH:mm') }} |
title | {{ $json.title }} |
url | {{ $json.link.split('?')[0] }} |
published:RSSの日時(UTC)を、日本時間のyyyy-MM-dd HH:mmの形に直しています。url:「?」より前だけを残して、計測用のパラメータを取り除いています。

Google Sheetsノードのポイントは、次の2つです。
- Operationを
Append or Update Rowにすると、「照合する列」の値が同じ行があれば上書きし、なければ追記します。 - 照合する列(Column to match on)を
urlにしたので、同じ記事は1行にまとまります。 - Mapping Column Modeは
Map Automaticallyにしました。Format Rowで作った項目名が、そのままシートの列名になります。
④ JSON
n8nの公開API(POST /api/v1/workflows)でこのJSONからワークフローを作成し、有効化してから、上の結果を確認しました。
使うときは、次の2か所を自分の環境に合わせて書き換えてください。
YOUR_SPREADSHEET_ID:記録先のスプレッドシートのID(URLの/d/と/editの間の文字列)YOUR_CREDENTIAL_ID:n8nに登録したGoogle Sheetsの認証情報のID。今回の環境では、YOUR_CREDENTIAL_IDのまま読み込んでも、登録済みの「Google Sheets account」が自動で選ばれました。選ばれていない場合は、ノードの画面で認証情報を選び直してください。
{
"name": "test-rss-sheets",
"nodes": [
{
"parameters": { "path": "test-rss-sheets", "responseMode": "responseNode", "options": {} },
"id": "c3f2e8e4-0001-4000-8000-000000000001",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [0, 0],
"webhookId": "d4a1b2c3-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
},
{
"parameters": { "url": "https://automatelabo.com/feed", "options": {} },
"id": "c3f2e8e4-0002-4000-8000-000000000002",
"name": "RSS Read",
"type": "n8n-nodes-base.rssFeedRead",
"typeVersion": 1.2,
"position": [220, 0]
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "a1", "name": "published", "value": "={{ DateTime.fromISO($json.isoDate).setZone('Asia/Tokyo').toFormat('yyyy-MM-dd HH:mm') }}", "type": "string" },
{ "id": "a2", "name": "title", "value": "={{ $json.title }}", "type": "string" },
{ "id": "a3", "name": "url", "value": "={{ $json.link.split('?')[0] }}", "type": "string" }
]
},
"options": {}
},
"id": "c3f2e8e4-0003-4000-8000-000000000003",
"name": "Format Row",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [440, 0]
},
{
"parameters": {
"operation": "appendOrUpdate",
"documentId": { "__rl": true, "value": "YOUR_SPREADSHEET_ID", "mode": "id" },
"sheetName": { "__rl": true, "value": "gid=0", "mode": "list" },
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": ["url"],
"schema": []
},
"options": {}
},
"id": "c3f2e8e4-0004-4000-8000-000000000004",
"name": "Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [660, 0],
"credentials": { "googleSheetsOAuth2Api": { "id": "YOUR_CREDENTIAL_ID", "name": "Google Sheets account" } }
},
{
"parameters": {
"respondWith": "text",
"responseBody": "={{ $input.all().length }}件をシートに記録しました",
"options": {}
},
"id": "c3f2e8e4-0005-4000-8000-000000000005",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [880, 0]
}
],
"connections": {
"Webhook": { "main": [[{ "node": "RSS Read", "type": "main", "index": 0 }]] },
"RSS Read": { "main": [[{ "node": "Format Row", "type": "main", "index": 0 }]] },
"Format Row": { "main": [[{ "node": "Google Sheets", "type": "main", "index": 0 }]] },
"Google Sheets": { "main": [[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]] }
},
"settings": { "executionOrder": "v1" }
}
⑤ つまずきポイントと対処
Google Sheetsノードで「Unable to sign without access token」になる
- 出たエラー:
Unable to sign without access token(Google Sheetsノード) - 原因:n8nの認証情報に、Client IDとClient Secretは入っていたものの、Googleとの接続(Sign in with Google)が済んでいませんでした。認証情報の画面には「Connect your account to use this credential」と出ていました。
- 対処:認証情報の画面で「Sign in with Google」を押して許可し、「Account connected」になったのを確認してから、実行し直しました。
Googleのログイン画面で「invalid_client」になる
- 出たエラー:
The OAuth client was not found.、エラー 401: invalid_client - 原因:n8nに入れたClient IDが、Google Cloudで作ったOAuthクライアントのものと合っていませんでした。
- 対処:Google Cloudの「クライアント」画面からClient IDとClient Secretをコピーし直して、n8nの認証情報に貼り直しました。
シートの1行目に、関係ない列ができる
- 起きたこと:シートのA1セルに文字が入っていたため、見出しが
n8n-test-rss / published / title / urlになり、データがB列から入りました。 - 対処:A1セルを消してから実行し直したところ、見出しが
published / title / urlの3つになりました。
⑥ 応用アイデア
どれも、まだ試していないアイデアです。
- Webhookを「Schedule Trigger」に替えて、毎朝決まった時刻に記録する
- 複数のフィードを読み込み、「どのサイトの記事か」の列を足して、1つのシートにまとめる
- 記録した記事のうち、新しく追加された行だけをSlackやDiscordに通知する
- シートに「読んだ」列を作り、あとで読む記事リストとして使う
