AutomationFlowsWeb Scraping › Market Radar - Weekly Intelligence

Market Radar - Weekly Intelligence

Market Radar - Weekly Intelligence. Uses httpRequest. Scheduled trigger; 21 nodes.

Cron / scheduled trigger★★★★☆ complexity21 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 21 Complexity: ★★★★☆ Added:

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": "Market Radar - Weekly Intelligence",
  "nodes": [
    {
      "id": "trigger-schedule",
      "name": "Weekly Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        400
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 19 * * 6"
            }
          ]
        }
      },
      "notes": "Default: Saturday 19:00 UTC. Adjust to your own timezone and day - see n8n/README.md."
    },
    {
      "id": "start-fanout",
      "name": "Start Fan-Out",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        220,
        400
      ],
      "parameters": {}
    },
    {
      "id": "src-newsroom",
      "name": "Company Newsroom RSS",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        -300
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "https://example.com/newsroom/rss",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "notes": "Replace with your own company's newsroom/investor RSS feed."
    },
    {
      "id": "parse-newsroom",
      "name": "Parse Newsroom",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        -300
      ],
      "parameters": {
        "jsCode": "const windowDays = 7;\nconst now = new Date();\nconst cutoff = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);\nlet items = [];\ntry {\n  const xml = $input.first().json.data || '';\n  const itemRegex = /<item>([\\s\\S]*?)<\\/item>/gi;\n  const titleRegex = /<title>(?:<!\\[CDATA\\[)?([^\\]<]+)(?:\\]\\]>)?<\\/title>/i;\n  const pubDateRegex = /<pubDate>([^<]+)<\\/pubDate>/i;\n  const linkRegex = /<link>([^<]+)<\\/link>/i;\n  const descRegex = /<description>(?:<!\\[CDATA\\[)?([\\s\\S]*?)(?:\\]\\]>)?<\\/description>/i;\n  let match;\n  while ((match = itemRegex.exec(xml)) !== null) {\n    const block = match[1];\n    const t = titleRegex.exec(block);\n    const d = pubDateRegex.exec(block);\n    const l = linkRegex.exec(block);\n    const s = descRegex.exec(block);\n    if (t) {\n      const pubDate = d ? new Date(d[1]) : null;\n      if (!pubDate || pubDate >= cutoff) {\n        items.push({ source: 'newsroom', title: t[1].trim(), url: l ? l[1].trim() : '', published: d ? d[1].trim() : null, summary: s ? s[1].replace(/<[^>]+>/g, '').trim().substring(0, 300) : '' });\n      }\n    }\n  }\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'newsroom_rss', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-google-news-company",
      "name": "Google News - Company",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        -140
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "=https://news.google.com/rss/search?q={{ encodeURIComponent('\"Acme Services\"') }}&hl=en-AU&gl=AU&ceid=AU:en",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "notes": "Replace the quoted query with your own company name. No API key needed; no published SLA either - see README design notes."
    },
    {
      "id": "parse-google-news-company",
      "name": "Parse Google News - Company",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        -140
      ],
      "parameters": {
        "jsCode": "const windowDays = 7;\nconst now = new Date();\nconst cutoff = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);\nlet items = [];\ntry {\n  const xml = $input.first().json.data || '';\n  const itemRegex = /<item>([\\s\\S]*?)<\\/item>/gi;\n  const titleRegex = /<title>(?:<!\\[CDATA\\[)?([^\\]<]+)(?:\\]\\]>)?<\\/title>/i;\n  const pubDateRegex = /<pubDate>([^<]+)<\\/pubDate>/i;\n  const linkRegex = /<link>([^<]+)<\\/link>/i;\n  let match;\n  while ((match = itemRegex.exec(xml)) !== null) {\n    const block = match[1];\n    const t = titleRegex.exec(block);\n    const d = pubDateRegex.exec(block);\n    const l = linkRegex.exec(block);\n    if (t && d) {\n      const pubDate = new Date(d[1]);\n      if (pubDate >= cutoff) {\n        items.push({ source: 'google_news_company', title: t[1].trim(), url: l ? l[1].trim() : '', published: d[1].trim(), summary: '' });\n      }\n    }\n  }\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'google_news_company', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-google-news-competitor",
      "name": "Google News - Competitor",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        20
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "=https://news.google.com/rss/search?q={{ encodeURIComponent('\"Northbridge Group\" infrastructure') }}&hl=en-AU&gl=AU&ceid=AU:en",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "notes": "Duplicate this node once per tracked competitor. Replace the quoted query."
    },
    {
      "id": "parse-google-news-competitor",
      "name": "Parse Google News - Competitor",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        20
      ],
      "parameters": {
        "jsCode": "const windowDays = 7;\nconst now = new Date();\nconst cutoff = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);\nlet items = [];\ntry {\n  const xml = $input.first().json.data || '';\n  const itemRegex = /<item>([\\s\\S]*?)<\\/item>/gi;\n  const titleRegex = /<title>(?:<!\\[CDATA\\[)?([^\\]<]+)(?:\\]\\]>)?<\\/title>/i;\n  const pubDateRegex = /<pubDate>([^<]+)<\\/pubDate>/i;\n  const linkRegex = /<link>([^<]+)<\\/link>/i;\n  let match;\n  while ((match = itemRegex.exec(xml)) !== null) {\n    const block = match[1];\n    const t = titleRegex.exec(block);\n    const d = pubDateRegex.exec(block);\n    const l = linkRegex.exec(block);\n    if (t && d) {\n      const pubDate = new Date(d[1]);\n      if (pubDate >= cutoff) {\n        items.push({ source: 'google_news_competitor', title: t[1].trim(), url: l ? l[1].trim() : '', published: d[1].trim(), summary: '' });\n      }\n    }\n  }\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'google_news_competitor', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-tender-portal",
      "name": "Tender Portal (AU example: AusTender)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        180
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "https://api.tenders.gov.au/ocds/findByDates/publishDate/{from}/{to}",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "notes": "AU example (AusTender OCDS API). For NZ use GETS RSS; for US/UK/EU swap in SAM.gov, Contracts Finder, or TED - see radar.yaml.example comments."
    },
    {
      "id": "parse-tender-portal",
      "name": "Parse Tender Portal",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        180
      ],
      "parameters": {
        "jsCode": "let items = [];\ntry {\n  const data = $input.first().json;\n  const releases = data.releases || data.results || data.data || [];\n  const arr = Array.isArray(releases) ? releases : [];\n  items = arr.map(r => ({ source: 'tender_portal', title: (r.tender && r.tender.title) || '', url: (r.tender && r.tender.id) || '', published: r.date || null, summary: (r.tender && r.tender.description) || '' }));\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'tender_portals', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-exchange",
      "name": "Exchange Announcements",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        340
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "https://example.com/asx-api/announcements?ticker=YOUR_TICKER",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "notes": "Replace with your own exchange announcement feed (own ticker and/or listed competitors/clients)."
    },
    {
      "id": "parse-exchange",
      "name": "Parse Exchange Announcements",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        340
      ],
      "parameters": {
        "jsCode": "let items = [];\ntry {\n  const data = $input.first().json;\n  const arr = data.data || data.items || [];\n  items = (Array.isArray(arr) ? arr : []).map(a => ({ source: 'exchange_announcements', title: a.headline || a.title || '', url: a.url || '', published: a.date || null, summary: '' }));\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'exchange_announcements', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-trade-press",
      "name": "Trade Press RSS",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        500
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "https://example.com/trade-press/feed",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "notes": "Replace with the trade/industry publication feeds relevant to your sectors. Duplicate for more than one."
    },
    {
      "id": "parse-trade-press",
      "name": "Parse Trade Press",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        500
      ],
      "parameters": {
        "jsCode": "const windowDays = 7;\nconst now = new Date();\nconst cutoff = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);\nlet items = [];\ntry {\n  const xml = $input.first().json.data || '';\n  const itemRegex = /<item>([\\s\\S]*?)<\\/item>/gi;\n  const titleRegex = /<title>(?:<!\\[CDATA\\[)?([^\\]<]+)(?:\\]\\]>)?<\\/title>/i;\n  const pubDateRegex = /<pubDate>([^<]+)<\\/pubDate>/i;\n  const linkRegex = /<link>([^<]+)<\\/link>/i;\n  let match;\n  while ((match = itemRegex.exec(xml)) !== null) {\n    const block = match[1];\n    const t = titleRegex.exec(block);\n    const d = pubDateRegex.exec(block);\n    const l = linkRegex.exec(block);\n    if (t && d) {\n      const pubDate = new Date(d[1]);\n      if (pubDate >= cutoff) {\n        items.push({ source: 'trade_press', title: t[1].trim(), url: l ? l[1].trim() : '', published: d[1].trim(), summary: '' });\n      }\n    }\n  }\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'trade_press_rss', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "src-regulator",
      "name": "Regulator Media Releases",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        660
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "GET",
        "url": "https://example.com/regulator/media-releases/rss",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "notes": "Replace with your sector or competition regulator's media release feed."
    },
    {
      "id": "parse-regulator",
      "name": "Parse Regulator",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        660
      ],
      "parameters": {
        "jsCode": "const windowDays = 7;\nconst now = new Date();\nconst cutoff = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);\nlet items = [];\ntry {\n  const xml = $input.first().json.data || '';\n  const itemRegex = /<item>([\\s\\S]*?)<\\/item>/gi;\n  const titleRegex = /<title>(?:<!\\[CDATA\\[)?([^\\]<]+)(?:\\]\\]>)?<\\/title>/i;\n  const pubDateRegex = /<pubDate>([^<]+)<\\/pubDate>/i;\n  const linkRegex = /<link>([^<]+)<\\/link>/i;\n  let match;\n  while ((match = itemRegex.exec(xml)) !== null) {\n    const block = match[1];\n    const t = titleRegex.exec(block);\n    const d = pubDateRegex.exec(block);\n    const l = linkRegex.exec(block);\n    if (t && d) {\n      const pubDate = new Date(d[1]);\n      if (pubDate >= cutoff) {\n        items.push({ source: 'regulator', title: t[1].trim(), url: l ? l[1].trim() : '', published: d[1].trim(), summary: '' });\n      }\n    }\n  }\n} catch (e) { items = []; }\nreturn [{ json: { branch: 'regulator_rss', data: items, count: items.length, error: null } }];"
      }
    },
    {
      "id": "build-prompt",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1000,
        180
      ],
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst branchData = {};\nconst failedBranches = [];\nfor (const item of allItems) {\n  const j = item.json;\n  if (j && j.branch) {\n    branchData[j.branch] = j;\n    if (j.error) failedBranches.push(j.branch);\n  }\n}\nconst company = 'Acme Services'; // replace with your company name\nconst weekEnding = new Date().toLocaleDateString('en-AU', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });\nconst dataStr = JSON.stringify(branchData, null, 2);\nconst instructions = 'You are a market intelligence analyst for ' + company + '. Use only the evidence below. Cite every claim with its source URL. Label each claim confirmed, reported, or speculated. If a value is not disclosed, say so - never estimate. Never use an em dash (Unicode U+2014); use a colon, a comma, or split the sentence. Produce a markdown brief with sections: Executive summary, ' + company + ' direct, Competitors, Tenders and awards, Clients and policy, So what, Sources. Then a fenced json code block with {\"events\": [...]}, each event with keys date, type, entity, headline, value, source_url, confidence, as_at.';\nconst prompt = instructions + '\\n\\nWeek ending: ' + weekEnding + '\\n\\nEVIDENCE:\\n' + dataStr;\nreturn [{ json: { prompt, weekEnding, failedBranches, sourcesScanned: Object.keys(branchData).length } }];"
      }
    },
    {
      "id": "llm-synthesis",
      "name": "LLM Synthesis (Anthropic)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1250,
        180
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'claude-haiku-4-5-20251001', max_tokens: 4000, messages: [{ role: 'user', content: $json.prompt }] }) }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          },
          "timeout": 120000
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "Create a Header Auth credential named 'Anthropic API': header name x-api-key, value your Anthropic API key. See n8n/README.md."
    },
    {
      "id": "format-brief",
      "name": "Format Brief",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1500,
        180
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst promptData = $('Build Prompt').first().json;\nlet text = '';\nlet inputTokens = 0;\nlet outputTokens = 0;\ntry {\n  text = response.content[0].text;\n  inputTokens = response.usage ? response.usage.input_tokens : 0;\n  outputTokens = response.usage ? response.usage.output_tokens : 0;\n} catch (e) {\n  text = '# Error\\nSynthesis failed: ' + JSON.stringify(response);\n}\nconst fenceMatch = /```json\\s*([\\s\\S]*?)```/g;\nlet lastMatch = null;\nlet m;\nwhile ((m = fenceMatch.exec(text)) !== null) { lastMatch = m; }\nlet brief = text;\nlet events = [];\nif (lastMatch) {\n  brief = text.slice(0, lastMatch.index).trim();\n  try { events = (JSON.parse(lastMatch[1]).events) || []; } catch (e) { events = []; }\n}\nconst dateStr = new Date().toISOString().slice(0, 10);\nconst filename = dateStr + '-brief.md';\nreturn [{ json: { filename, brief, events, weekEnding: promptData.weekEnding, inputTokens, outputTokens, path: 'reports/' + filename } }];"
      }
    },
    {
      "id": "sink-commit",
      "name": "Commit Brief (git sink, optional)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1750,
        80
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "PUT",
        "url": "=https://api.github.com/repos/YOUR_GITHUB_USERNAME/YOUR_REPORTS_REPO/contents/reports/{{ $json.filename }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/vnd.github+json"
            },
            {
              "name": "X-GitHub-Api-Version",
              "value": "2022-11-28"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ message: 'Weekly brief - ' + $json.filename, content: Buffer.from($json.brief).toString('base64'), branch: 'main' }) }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          },
          "timeout": 30000
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "Optional. Create a Header Auth credential named 'GitHub API': header name Authorization, value 'token <your fine-grained PAT>'. Replace the repo path. Delete this node if you only want the local Python runner's git sink instead."
    },
    {
      "id": "sink-chat",
      "name": "Chat Notification (optional)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1750,
        280
      ],
      "continueOnFail": true,
      "parameters": {
        "method": "POST",
        "url": "={{ 'https://api.telegram.org/bot' + $env.TELEGRAM_BOT_TOKEN + '/sendMessage' }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ chat_id: $env.TELEGRAM_CHAT_ID, text: 'Market radar brief ready: ' + $json.filename + '\\n' + $json.events.length + ' event(s) found.' }) }}",
        "options": {
          "timeout": 15000
        }
      },
      "notes": "Optional. Set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID as n8n environment variables (Settings > Variables), never hardcoded. Delete this node if unused."
    }
  ],
  "connections": {
    "Weekly Schedule Trigger": {
      "main": [
        [
          {
            "node": "Start Fan-Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Fan-Out": {
      "main": [
        [
          {
            "node": "Company Newsroom RSS",
            "type": "main",
            "index": 0
          },
          {
            "node": "Google News - Company",
            "type": "main",
            "index": 0
          },
          {
            "node": "Google News - Competitor",
            "type": "main",
            "index": 0
          },
          {
            "node": "Tender Portal (AU example: AusTender)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Exchange Announcements",
            "type": "main",
            "index": 0
          },
          {
            "node": "Trade Press RSS",
            "type": "main",
            "index": 0
          },
          {
            "node": "Regulator Media Releases",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Company Newsroom RSS": {
      "main": [
        [
          {
            "node": "Parse Newsroom",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Newsroom": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google News - Company": {
      "main": [
        [
          {
            "node": "Parse Google News - Company",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Google News - Company": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google News - Competitor": {
      "main": [
        [
          {
            "node": "Parse Google News - Competitor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Google News - Competitor": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tender Portal (AU example: AusTender)": {
      "main": [
        [
          {
            "node": "Parse Tender Portal",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Tender Portal": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Exchange Announcements": {
      "main": [
        [
          {
            "node": "Parse Exchange Announcements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Exchange Announcements": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trade Press RSS": {
      "main": [
        [
          {
            "node": "Parse Trade Press",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Trade Press": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Regulator Media Releases": {
      "main": [
        [
          {
            "node": "Parse Regulator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Regulator": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "LLM Synthesis (Anthropic)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM Synthesis (Anthropic)": {
      "main": [
        [
          {
            "node": "Format Brief",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Brief": {
      "main": [
        [
          {
            "node": "Commit Brief (git sink, optional)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Chat Notification (optional)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "staticData": null,
  "tags": [
    {
      "name": "market-radar"
    }
  ],
  "triggerCount": 1
}

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

Market Radar - Weekly Intelligence. Uses httpRequest. Scheduled trigger; 21 nodes.

Source: https://github.com/Jiplet/market-radar/blob/main/n8n/market-radar.workflow.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1
Web Scraping

This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n

Microsoft SharePoint, Microsoft Teams, Microsoft Entra +1
Web Scraping

Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.

HTTP Request, Jira
Web Scraping

Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.

HTTP Request, N8N Nodes Surrealdb, Spotify
Web Scraping

As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o

HTTP Request, n8n, N8N Trigger +1