AutomationFlowsSlack & Telegram › Send Daily Brent Crude Oil Futures Prices to Telegram with 0 API Cost

Send Daily Brent Crude Oil Futures Prices to Telegram with 0 API Cost

ByRahul Shah @rahulshah111 on n8n.io

Oil traders, energy analysts, commodity research desks, shipping operations teams, refinery planners, equity investors in oil stocks, macro researchers, and anyone whose day starts with "where is Brent trading?" If you track the international oil benchmark and want hands-free…

Cron / scheduled trigger★★★★☆ complexity9 nodesHTTP RequestTelegram
Slack & Telegram Trigger: Cron / scheduled Nodes: 9 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15172 — we link there as the canonical source.

This workflow follows the HTTP Request → Telegram 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "3973284d-8c68-42c3-81ee-9de605e47f22",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 550,
        "content": "## Brent Crude Futures Tracker\n\nSilently scrapes live Brent Crude futures prices for the next 10 months, formats them into a clean table, and delivers updates to Telegram.\n\n### How it works\n1. Triggers multiple times a day on weekdays\n2. Scrapes oilprice.com Brent Crude page\n3. Parses 10 forward contracts (prices and changes)\n4. Aggregates data into a single array\n5. Formats and sends an HTML table to Telegram\n\n### Setup\n- [ ] Add your Telegram Bot credentials\n- [ ] Enter your Telegram Chat ID in the `Send Telegram Table` node\n- [ ] Adjust the `Market Hours Trigger` node times if you are not in IST timezone\n\n### How to Use\nSimply wait for the scheduled times, or click 'Test Workflow' to receive a live snapshot of the forward curve instantly."
      },
      "typeVersion": 1
    },
    {
      "id": "125f8d81-c5c9-4152-a8d9-5b51f8a85445",
      "name": "Sec1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        48
      ],
      "parameters": {
        "width": 412,
        "height": 244,
        "content": "## 1. Schedule & Fetch\nRuns on schedule and gets raw HTML."
      },
      "typeVersion": 1
    },
    {
      "id": "6afbdff3-ec6a-4b20-8371-3d0e6e5cb3cc",
      "name": "Sec2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        48
      ],
      "parameters": {
        "width": 420,
        "height": 244,
        "content": "## 2. Parse & Combine\nExtracts 10 contracts and bundles them."
      },
      "typeVersion": 1
    },
    {
      "id": "72e21ada-fd5a-44e0-be5f-dac28813893a",
      "name": "Sec3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1280,
        48
      ],
      "parameters": {
        "width": 250,
        "height": 244,
        "content": "## 3. Notify\nSends HTML formatted table to Telegram."
      },
      "typeVersion": 1
    },
    {
      "id": "8959692d-f633-40c8-b2f8-799570b5b165",
      "name": "Market Hours Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        448,
        144
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 9
            },
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 11,
              "triggerAtMinute": 11
            },
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 13,
              "triggerAtMinute": 30
            },
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 16
            },
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 19,
              "triggerAtMinute": 15
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9b4bd061-ca85-4279-9163-f165ad1ed7e5",
      "name": "Fetch Brent Page1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        640,
        144
      ],
      "parameters": {
        "url": "https://oilprice.com/futures/brent/",
        "options": {}
      },
      "typeVersion": 4.3
    },
    {
      "id": "8a60254d-4ad8-4fa3-8d90-cd4df1b68b94",
      "name": "Parse 10 Contracts1",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        896,
        144
      ],
      "parameters": {
        "jsCode": "// CORRECTED Code - Extracts correct \"Last\" price column\nconst htmlContent = $input.item.json.data || \"\";\n\nif (!htmlContent || typeof htmlContent !== 'string') {\n  return [{ json: { error: \"No HTML content\" } }];\n}\n\nconst now = new Date();\nconst scrapeDate = now.toISOString().split('T')[0];\nconst scrapeTime = now.toTimeString().split(' ')[0];\n\nconst symbolsData = [\n  { symbol: 'CBH26', month: 'Mar' },\n  { symbol: 'CBJ26', month: 'Apr' },\n  { symbol: 'CBK26', month: 'May' },\n  { symbol: 'CBM26', month: 'Jun' },\n  { symbol: 'CBN26', month: 'Jul' },\n  { symbol: 'CBQ26', month: 'Aug' },\n  { symbol: 'CBU26', month: 'Sep' },\n  { symbol: 'CBV26', month: 'Oct' },\n  { symbol: 'CBX26', month: 'Nov' },\n  { symbol: 'CBZ26', month: 'Dec' }\n];\n\nconst results = [];\n\nfor (const { symbol, month } of symbolsData) {\n  const idx = htmlContent.indexOf(symbol);\n  \n  if (idx > -1) {\n    // Get context AFTER the symbol (not before)\n    // This ensures we get data from the same row\n    const ctx = htmlContent.substring(idx, Math.min(htmlContent.length, idx + 800));\n    \n    // Look for the \"Last\" column value specifically\n    // Pattern: symbol, then month/year, then the FIRST number is Last price\n    const priceMatch = ctx.match(/CBH26[\\s\\S]{0,200}?<\\/a>[\\s\\S]{0,200}?<div[^>]*>\\s*([0-9]{2}\\.[0-9]{2})\\s*</);\n    \n    // Alternative: Use more specific pattern for \"last\" column\n    const lastPriceMatch = ctx.match(/<div[^>]*class=\"[^\"]*last[^\"]*\"[^>]*>\\s*([0-9]{2}\\.[0-9]{2})/i);\n    \n    // Try another pattern - look for first price after contract name\n    const firstPriceMatch = ctx.match(/2026[^0-9]*([0-9]{2}\\.[0-9]{2})/);\n    \n    const price = lastPriceMatch ? lastPriceMatch[1] : \n                  (priceMatch ? priceMatch[1] : \n                  (firstPriceMatch ? firstPriceMatch[1] : null));\n    \n    if (price) {\n      // Find change value\n      const changeMatch = ctx.match(/([+\\-][0-9]\\.[0-9]{2})/);\n      \n      // Find time\n      const timeMatch = ctx.match(/([0-9]{2}:[0-9]{2})/);\n      \n      results.push({\n        json: {\n          symbol: symbol,\n          month: month,\n          year: \"2026\",\n          contract: `${month} 2026`,\n          price_usd: parseFloat(price),\n          change: changeMatch ? parseFloat(changeMatch[1]) : null,\n          website_update_time: timeMatch ? timeMatch[1] : \"\",\n          scrape_date: scrapeDate,\n          scrape_time: scrapeTime,\n          source: \"https://oilprice.com/futures/brent/\",\n          commodity: \"Brent Crude Oil Futures\"\n        }\n      });\n    }\n  }\n}\n\nif (results.length === 0) {\n  return [{\n    json: {\n      error: \"No contracts extracted\",\n      scrape_date: scrapeDate\n    }\n  }];\n}\n\nreturn results;\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "2f39141f-73cf-4163-9295-6d7522ed30f5",
      "name": "Aggregate Items1",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1088,
        144
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "8467a8ed-7938-46d7-b890-738ac6288fc0",
      "name": "Send Telegram Table1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1360,
        144
      ],
      "parameters": {
        "text": "=\ud83d\udee2\ufe0f <b>Brent Crude Oil Futures</b>\n\ud83d\udcc5 {{ $json.data[0].scrape_date }} \u2022 {{ $json.data[0].scrape_time }}\n\n{{ $json.data.every(item => item.change >= 0) ? '\u2705 ALL UP' : $json.data.every(item => item.change < 0) ? '\u26a0\ufe0f ALL DOWN' : '\ud83d\udcca MIXED' }}\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n<pre>\nContract  Period    Price   Change\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n{{ $json.data.map(item => {\n  const emoji = item.change > 0 ? '\ud83d\udfe2' : item.change < 0 ? '\ud83d\udd34' : '\u26aa';\n  const symbol = item.symbol.padEnd(9);\n  const period = `${item.month} '${String(item.year).slice(-2)}`.padEnd(9);\n  const price = `$${item.price_usd}`.padEnd(7);\n  const change = `${item.change >= 0 ? '+' : ''}$${item.change}`;\n  return `${emoji} ${symbol} ${period} ${price} ${change}`;\n}).join('\\n') }}\n</pre>\n\n\ud83d\udcca Range: ${{ Math.min(...$json.data.map(d => d.price_usd)) }} - ${{ Math.max(...$json.data.map(d => d.price_usd)) }}\n\ud83d\udcc8 Avg: {{ ($json.data.reduce((sum, d) => sum + d.change, 0) / $json.data.length).toFixed(2) >= 0 ? '+' : '' }}${{ ($json.data.reduce((sum, d) => sum + d.change, 0) / $json.data.length).toFixed(2) }}\n\n\ud83d\udd17 <a href=\"{{ $json.data[0].source }}\">Source</a>",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    }
  ],
  "connections": {
    "Aggregate Items1": {
      "main": [
        [
          {
            "node": "Send Telegram Table1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Brent Page1": {
      "main": [
        [
          {
            "node": "Parse 10 Contracts1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse 10 Contracts1": {
      "main": [
        [
          {
            "node": "Aggregate Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Market Hours Trigger1": {
      "main": [
        [
          {
            "node": "Fetch Brent Page1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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

Oil traders, energy analysts, commodity research desks, shipping operations teams, refinery planners, equity investors in oil stocks, macro researchers, and anyone whose day starts with "where is Brent trading?" If you track the international oil benchmark and want hands-free…

Source: https://n8n.io/workflows/15172/ — 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

GNCA AI News Pipeline. Uses rssFeedRead, httpRequest, telegram, errorTrigger. Scheduled trigger; 29 nodes.

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

This workflow automates plant care reminders and records using Google Sheets, Telegram, and OpenWeather API.

Google Sheets, HTTP Request, Telegram
Slack & Telegram

Apollo Data Enrichment Using Company Id to automatically finds contacts for companies listed in your Google Sheet, enriches each person with emails and phone numbers via Apollo’s API, and writes verif

Google Sheets, HTTP Request, Error Trigger +1
Slack & Telegram

MindFrame Psychology - FREE Complete Workflow. Uses httpRequest, googleDrive, telegram. Scheduled trigger; 25 nodes.

HTTP Request, Google Drive, Telegram
Slack & Telegram

++Download the google sheet here++ and replace this with the googles sheet node: Google sheet , upload to google sheets and replace in the google sheets node. Scheduled trigger: Runs once a day at 8 A

Google Sheets, HTTP Request, Telegram