AutomationFlowsSlack & Telegram › Competitor Feature-parity Watcher

Competitor Feature-parity Watcher

Competitor Feature-Parity Watcher. Uses rssFeedRead, httpRequest, googleSheets, telegram. Scheduled trigger; 24 nodes.

Cron / scheduled trigger★★★★☆ complexity24 nodesRSS Feed ReadHTTP RequestGoogle SheetsTelegram
Slack & Telegram Trigger: Cron / scheduled Nodes: 24 Complexity: ★★★★☆ Added:

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Competitor Feature-Parity Watcher",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 1
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Weekly Scan",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -1900,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Keep this current \u2014 the LLM judges relevance against what's listed here.\nreturn [{\n  json: {\n    productName: \"REPLACE_YOUR_PRODUCT_NAME\",\n    features: [\n      \"REPLACE_FEATURE_ONE\",\n      \"REPLACE_FEATURE_TWO\",\n      \"REPLACE_FEATURE_THREE\"\n    ]\n  }\n}];"
      },
      "id": "your-product-context",
      "name": "Your Product Context (edit me)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1680,
        -140
      ]
    },
    {
      "parameters": {
        "jsCode": "const watchlist = [\n  { name: \"REPLACE_COMPETITOR_ONE\", changelogUrl: \"https://example.com/changelog.rss\", sourceType: \"rss\" },\n  { name: \"REPLACE_COMPETITOR_TWO\", changelogUrl: \"https://example.com/whats-new\", sourceType: \"webpage\" }\n];\nreturn watchlist.map(w => ({ json: w }));"
      },
      "id": "competitor-watchlist",
      "name": "Competitor Watchlist (edit me)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1680,
        60
      ]
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "split-in-batches",
      "name": "Loop One Competitor At A Time",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -1460,
        60
      ]
    },
    {
      "parameters": {
        "mode": "rules",
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "id": "c-rss",
                    "leftValue": "={{ $json.sourceType }}",
                    "rightValue": "rss",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "rss"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "id": "c-web",
                    "leftValue": "={{ $json.sourceType }}",
                    "rightValue": "webpage",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "webpage"
            }
          ]
        },
        "options": {}
      },
      "id": "route-by-source-type",
      "name": "Route By Source Type",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        -1240,
        60
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.changelogUrl }}",
        "options": {}
      },
      "id": "rss-read",
      "name": "Read RSS Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        -1020,
        -80
      ]
    },
    {
      "parameters": {
        "jsCode": "const competitor = $('Loop One Competitor At A Time').first().json;\nconst items = $input.all().map(i => i.json);\nconst normalized = items.map(it => ({\n  title: it.title,\n  link: it.link,\n  date: it.isoDate || it.pubDate || null\n}));\nreturn [{ json: { competitor: competitor.name, status: 'ok', rawItems: normalized } }];"
      },
      "id": "normalize-rss",
      "name": "Normalize RSS Items",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -800,
        -80
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $json.changelogUrl }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "fetch-webpage",
      "name": "Fetch Changelog Page",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -1020,
        140
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "fetch-ok",
              "leftValue": "={{ $json.statusCode }}",
              "rightValue": 400,
              "operator": {
                "type": "number",
                "operation": "lt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "check-fetch-ok",
      "name": "Fetch Succeeded?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -800,
        140
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://openrouter.ai/api/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_OPENROUTER_API_KEY"
            },
            {
              "name": "HTTP-Referer",
              "value": "https://github.com/Skull-boy/n8n_workflows"
            },
            {
              "name": "X-OpenRouter-Title",
              "value": "n8n_workflows-competitor-watcher"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ models: [\"nvidia/nemotron-3-ultra:free\", \"qwen/qwen3-coder:free\", \"openai/gpt-oss:free\"], messages: [{ role: \"system\", content: \"Extract a JSON array of recent product updates from this raw changelog page text. Each item: {title, date}. Return ONLY the JSON array, nothing else.\" }, { role: \"user\", content: $json.data.slice(0, 8000) }] }) }}",
        "options": {}
      },
      "id": "extract-updates-via-llm",
      "name": "Extract Updates (LLM)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -580,
        140
      ],
      "credentials": {}
    },
    {
      "parameters": {
        "jsCode": "const competitor = $('Loop One Competitor At A Time').first().json;\ntry {\n  const raw = $input.first().json.choices[0].message.content;\n  const items = JSON.parse(raw);\n  return [{ json: { competitor: competitor.name, status: 'ok', rawItems: items.map(i => ({ title: i.title, link: competitor.changelogUrl, date: i.date })) } }];\n} catch (e) {\n  return [{ json: { competitor: competitor.name, status: 'parse_failed', rawItems: [] } }];\n}"
      },
      "id": "normalize-webpage",
      "name": "Normalize Webpage Items",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -360,
        140
      ]
    },
    {
      "parameters": {
        "jsCode": "const competitor = $('Loop One Competitor At A Time').first().json;\nreturn [{ json: { competitor: competitor.name, status: 'fetch_failed', rawItems: [] } }];"
      },
      "id": "log-fetch-failure",
      "name": "Log Fetch Failure",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -580,
        300
      ]
    },
    {
      "parameters": {
        "operation": "lookup",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "CompetitorState",
          "mode": "name"
        },
        "lookupColumn": "competitor",
        "lookupValue": "={{ $json.competitor }}"
      },
      "id": "lookup-last-checked",
      "name": "Look Up Last Checked",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        -140,
        60
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const cur = $('Normalize RSS Items').itemMatching ? null : null;\n// Pull the item that actually reached this node (rss, webpage, or failure path)\nconst src = $input.first().json;\nconst prevRows = $items('Look Up Last Checked');\nconst lastCheckedDate = (prevRows.length > 0 && prevRows[0].json.lastCheckedDate) ? prevRows[0].json.lastCheckedDate : null;\n\nif (src.status !== 'ok') {\n  return [{ json: { competitor: src.competitor, status: src.status, newItems: [] } }];\n}\n\nconst newItems = lastCheckedDate\n  ? src.rawItems.filter(i => i.date && new Date(i.date) > new Date(lastCheckedDate))\n  : src.rawItems;\n\nreturn [{ json: { competitor: src.competitor, status: 'ok', newItems, latestDate: src.rawItems.reduce((max, i) => (i.date && (!max || new Date(i.date) > new Date(max))) ? i.date : max, lastCheckedDate) } }];"
      },
      "id": "filter-new-items",
      "name": "Filter To New Items Only",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        80,
        60
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "has-new",
              "leftValue": "={{ $json.status }}",
              "rightValue": "ok",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "has-items",
              "leftValue": "={{ $json.newItems.length }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "any-new-to-judge",
      "name": "Any New Items To Judge?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        300,
        60
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://openrouter.ai/api/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_OPENROUTER_API_KEY"
            },
            {
              "name": "HTTP-Referer",
              "value": "https://github.com/Skull-boy/n8n_workflows"
            },
            {
              "name": "X-OpenRouter-Title",
              "value": "n8n_workflows-competitor-watcher"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ models: [\"nvidia/nemotron-3-ultra:free\", \"qwen/qwen3-coder:free\", \"openai/gpt-oss:free\"], messages: [{ role: \"system\", content: `You judge competitive relevance. Our product (${$('Your Product Context (edit me)').first().json.productName}) has these features: ${$('Your Product Context (edit me)').first().json.features.join(', ')}. For each competitor update given, score 1-5 how relevant/threatening it is to us specifically (5 = direct feature overlap or gap, 1 = irrelevant noise). Also assign ONE reasonCode from this fixed set: pricing, enterprise, integration, migration-risk, new_offer, positioning_shift, other. Keep reasonCode to exactly one of these values, nothing else, so scores stay filterable and debuggable over time. Return ONLY a JSON array: [{title, score, reasonCode, reason}]` }, { role: \"user\", content: JSON.stringify($json.newItems) }] }) }}",
        "options": {}
      },
      "id": "judge-relevance",
      "name": "Judge Relevance Against Our Features",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        520,
        -80
      ],
      "credentials": {}
    },
    {
      "parameters": {
        "jsCode": "const competitor = $('Filter To New Items Only').first().json.competitor;\nconst newItems = $('Filter To New Items Only').first().json.newItems;\nlet judged = [];\ntry {\n  judged = JSON.parse($input.first().json.choices[0].message.content);\n} catch (e) {\n  judged = [];\n}\nconst VALID_CODES = ['pricing','enterprise','integration','migration-risk','new_offer','positioning_shift','other'];\nconst relevant = judged.filter(j => j.score >= 3).map(j => {\n  const match = newItems.find(n => n.title === j.title);\n  const reasonCode = VALID_CODES.includes(j.reasonCode) ? j.reasonCode : 'other';\n  return { competitor, title: j.title, score: j.score, reasonCode, reason: j.reason, link: match ? match.link : '', scanDate: new Date().toISOString().slice(0,10) };\n});\nreturn relevant.map(r => ({ json: r }));"
      },
      "id": "parse-and-filter-relevant",
      "name": "Parse & Filter Relevant",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        740,
        -80
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "FlaggedUpdates",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "competitor": "={{ $json.competitor }}",
            "title": "={{ $json.title }}",
            "score": "={{ $json.score }}",
            "reason": "={{ $json.reason }}",
            "link": "={{ $json.link }}",
            "scanDate": "={{ $json.scanDate }}",
            "reasonCode": "={{ $json.reasonCode }}"
          }
        }
      },
      "id": "save-flagged-items",
      "name": "Save Flagged Updates",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        960,
        -80
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const src = $('Filter To New Items Only').first().json;\nif (src.status === 'fetch_failed' || src.status === 'parse_failed') {\n  return [{ json: { skip: true } }];\n}\nreturn [{ json: { competitor: src.competitor, latestDate: src.latestDate || new Date().toISOString() } }];"
      },
      "id": "prep-state-update",
      "name": "Prep State Update",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        520,
        220
      ]
    },
    {
      "parameters": {
        "operation": "upsert",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "CompetitorState",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "competitor": "={{ $json.competitor }}",
            "lastCheckedDate": "={{ $json.latestDate }}"
          }
        },
        "matchingColumns": [
          "competitor"
        ]
      },
      "id": "update-state",
      "name": "Update Last-Checked State",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        740,
        220
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "amount": 2,
        "unit": "seconds"
      },
      "id": "rate-limit-wait",
      "name": "Wait (Avoid Rate Limit)",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        960,
        220
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "FlaggedUpdates",
          "mode": "name"
        },
        "filters": {
          "conditions": [
            {
              "keyField": "scanDate",
              "condition": "equal",
              "keyValue": "={{ $now.format('yyyy-MM-dd') }}"
            }
          ]
        }
      },
      "id": "get-todays-flagged",
      "name": "Get This Week's Flagged Updates",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        -1460,
        460
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const rows = $input.all().map(i => i.json);\nif (rows.length === 0) {\n  return [{ json: { digest: '\ud83d\udcca Competitor Watch: no relevant updates this week.' } }];\n}\nconst byCompetitor = {};\nfor (const r of rows) {\n  byCompetitor[r.competitor] = byCompetitor[r.competitor] || [];\n  byCompetitor[r.competitor].push(r);\n}\nlet msg = '\ud83d\udcca Weekly Competitor Watch\\n\\n';\nfor (const [comp, items] of Object.entries(byCompetitor)) {\n  msg += `\ud83d\udd39 ${comp}\\n`;\n  for (const it of items) {\n    msg += `  \u2022 [${it.score}/5 \u00b7 ${it.reasonCode}] ${it.title}\\n    ${it.reason}\\n    ${it.link}\\n`;\n  }\n  msg += '\\n';\n}\nreturn [{ json: { digest: msg } }];"
      },
      "id": "build-digest",
      "name": "Build Digest Report",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1240,
        460
      ]
    },
    {
      "parameters": {
        "chatId": "REPLACE_YOUR_TELEGRAM_CHAT_ID",
        "text": "={{ $json.digest }}",
        "additionalFields": {}
      },
      "id": "send-digest",
      "name": "Send Digest (Telegram)",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -1020,
        460
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Weekly Scan": {
      "main": [
        [
          {
            "node": "Your Product Context (edit me)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Competitor Watchlist (edit me)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Competitor Watchlist (edit me)": {
      "main": [
        [
          {
            "node": "Loop One Competitor At A Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop One Competitor At A Time": {
      "main": [
        [
          {
            "node": "Get This Week's Flagged Updates",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Route By Source Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route By Source Type": {
      "main": [
        [
          {
            "node": "Read RSS Feed",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fetch Changelog Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read RSS Feed": {
      "main": [
        [
          {
            "node": "Normalize RSS Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize RSS Items": {
      "main": [
        [
          {
            "node": "Look Up Last Checked",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Changelog Page": {
      "main": [
        [
          {
            "node": "Fetch Succeeded?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Succeeded?": {
      "main": [
        [
          {
            "node": "Extract Updates (LLM)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Fetch Failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Updates (LLM)": {
      "main": [
        [
          {
            "node": "Normalize Webpage Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Webpage Items": {
      "main": [
        [
          {
            "node": "Look Up Last Checked",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Fetch Failure": {
      "main": [
        [
          {
            "node": "Look Up Last Checked",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Look Up Last Checked": {
      "main": [
        [
          {
            "node": "Filter To New Items Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter To New Items Only": {
      "main": [
        [
          {
            "node": "Any New Items To Judge?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prep State Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any New Items To Judge?": {
      "main": [
        [
          {
            "node": "Judge Relevance Against Our Features",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Judge Relevance Against Our Features": {
      "main": [
        [
          {
            "node": "Parse & Filter Relevant",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Filter Relevant": {
      "main": [
        [
          {
            "node": "Save Flagged Updates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep State Update": {
      "main": [
        [
          {
            "node": "Update Last-Checked State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Last-Checked State": {
      "main": [
        [
          {
            "node": "Wait (Avoid Rate Limit)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait (Avoid Rate Limit)": {
      "main": [
        [
          {
            "node": "Loop One Competitor At A Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get This Week's Flagged Updates": {
      "main": [
        [
          {
            "node": "Build Digest Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Digest Report": {
      "main": [
        [
          {
            "node": "Send Digest (Telegram)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Flagged Updates": {
      "main": [
        [
          {
            "node": "Wait (Avoid Rate Limit)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Competitor Feature-Parity Watcher. Uses rssFeedRead, httpRequest, googleSheets, telegram. Scheduled trigger; 24 nodes.

Source: https://github.com/Skull-boy/n8n_workflows/blob/main/workflows/competitor-feature-parity-watcher/workflow.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

Auto Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.

HTTP Request, Google Sheets, RSS Feed Read +1
Slack & Telegram

Auto-Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.

HTTP Request, Google Sheets, RSS Feed Read +1
Slack & Telegram

FireReach — Always-On SDR Workflow. Uses rssFeedRead, httpRequest, telegram, googleSheets. Scheduled trigger; 11 nodes.

RSS Feed Read, HTTP Request, Telegram +1
Slack & Telegram

03 · RSS → GPT → Post Draft (human approval). Uses rssFeedRead, httpRequest, googleSheets, telegram. Scheduled trigger; 10 nodes.

RSS Feed Read, HTTP Request, Google Sheets +1
Slack & Telegram

. Uses googleSheets, telegram, httpRequest, wise. Scheduled trigger; 36 nodes.

Google Sheets, Telegram, HTTP Request +2