AutomationFlowsSlack & Telegram › Automated Indonesian Weather Alerts with Bmkg Data & Telegram Notifications

Automated Indonesian Weather Alerts with Bmkg Data & Telegram Notifications

ByTegar karunia ilham @tegarkaruniailham on n8n.io

Stay ahead of weather changes with this comprehensive monitoring system that fetches real-time data from Indonesia's official meteorological agency (BMKG) and delivers beautiful, actionable weather reports directly to your Telegram.

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

This workflow corresponds to n8n.io template #9675 — 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
{
  "id": "oezF9oCv3tPecrSv",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "BMKG Weather Monitoring & Telegram Alert System",
  "tags": [
    {
      "id": "5elPMuYGw7BLPyD5",
      "name": "Weather Monitoring EN",
      "createdAt": "2025-10-15T00:58:29.022Z",
      "updatedAt": "2025-10-15T00:58:29.022Z"
    }
  ],
  "nodes": [
    {
      "id": "a7760673-0f36-4693-b0e2-b12ec5319247",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -448,
        -16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bf292408-48a2-4fb8-baf5-38c7b5f36862",
      "name": "Get BMKG Weather Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        112,
        192
      ],
      "parameters": {
        "url": "https://api.bmkg.go.id/publik/prakiraan-cuaca",
        "options": {}
      },
      "typeVersion": 4.1
    },
    {
      "id": "af473f94-7a67-4023-94b5-3bdf8015280a",
      "name": "Process Weather Data",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        0
      ],
      "parameters": {
        "jsCode": "// Process BMKG weather data\nconst inputData = $input.all();\nconst weatherData = inputData[0].json;\n\n// Check if data exists\nif (!weatherData || !weatherData.data || !weatherData.data[0] || !weatherData.data[0].cuaca) {\n    return [{\n        json: {\n            success: false,\n            error: 'Weather data not available from BMKG API',\n            timestamp: new Date().toISOString()\n        }\n    }];\n}\n\n// Extract location information\nconst location = weatherData.lokasi || {};\nconst cuacaData = weatherData.data[0].cuaca;\n\n// Process current and upcoming weather\nlet processedData = {\n    success: true,\n    timestamp: new Date().toISOString(),\n    location: {\n        desa: location.desa || 'Unknown',\n        kecamatan: location.kecamatan || 'Unknown',\n        kotkab: location.kotkab || 'Unknown',\n        provinsi: location.provinsi || 'Unknown',\n        lat: location.lat || 0,\n        lon: location.lon || 0,\n        timezone: location.timezone || 'Asia/Jakarta'\n    },\n    current_weather: {},\n    forecast_24hour: [],\n    summary: {\n        avg_temperature: 0,\n        avg_humidity: 0,\n        dominant_condition: '',\n        warnings: []\n    }\n};\n\n// Process current weather (first data point)\nif (cuacaData[0] && cuacaData[0][0]) {\n    const current = cuacaData[0][0];\n    processedData.current_weather = {\n        time: current.local_datetime || current.datetime,\n        temperature: current.t || 0,\n        humidity: current.hu || 0,\n        condition: current.weather_desc || current.weather_desc_en || 'Unknown',\n        wind_speed: current.ws || 0,\n        wind_direction: current.wd || 'N/A',\n        visibility: current.vs_text || 'N/A',\n        cloud_cover: current.tcc || 0,\n        rain_probability: current.tp || 0,\n        icon_url: current.image || ''\n    };\n}\n\n// Process 24-hour forecast\nlet totalTemperature = 0;\nlet totalHumidity = 0;\nlet count = 0;\nlet conditionCount = {};\n\n// Collect data from first day (today)\nif (cuacaData[0]) {\n    cuacaData[0].forEach(jam => {\n        if (jam && jam.t !== undefined) {\n            processedData.forecast_24hour.push({\n                time: jam.local_datetime || jam.datetime,\n                temperature: jam.t,\n                humidity: jam.hu || 0,\n                condition: jam.weather_desc || jam.weather_desc_en || 'Unknown',\n                wind_speed: jam.ws || 0,\n                wind_direction: jam.wd || 'N/A',\n                rain_probability: jam.tp || 0,\n                icon_url: jam.image || ''\n            });\n            \n            totalTemperature += jam.t;\n            totalHumidity += jam.hu || 0;\n            count++;\n            \n            const condition = jam.weather_desc || jam.weather_desc_en || 'Unknown';\n            conditionCount[condition] = (conditionCount[condition] || 0) + 1;\n        }\n    });\n}\n\n// Calculate averages and dominant condition\nif (count > 0) {\n    processedData.summary.avg_temperature = Math.round(totalTemperature / count * 10) / 10;\n    processedData.summary.avg_humidity = Math.round(totalHumidity / count);\n}\n\n// Find dominant weather condition\nlet maxCount = 0;\nfor (const [condition, conditionNum] of Object.entries(conditionCount)) {\n    if (conditionNum > maxCount) {\n        maxCount = conditionNum;\n        processedData.summary.dominant_condition = condition;\n    }\n}\n\n// Generate warnings\nconst warnings = [];\nif (processedData.summary.avg_temperature > 35) {\n    warnings.push('\u26a0\ufe0f Very hot temperature, avoid outdoor activities');\n}\nif (processedData.summary.avg_temperature < 20) {\n    warnings.push('\ud83e\udde5 Cold temperature, wear warm clothes');\n}\n\n// Check for rain probability\nconst avgRainProb = processedData.forecast_24hour.reduce((sum, item) => sum + (item.rain_probability || 0), 0) / processedData.forecast_24hour.length;\nif (avgRainProb > 60) {\n    warnings.push('\u2614 High rain probability, bring umbrella or raincoat');\n}\nif (avgRainProb > 30 && avgRainProb <= 60) {\n    warnings.push('\ud83c\udf26\ufe0f Possible rain, prepare rain gear');\n}\n\nprocessedData.summary.warnings = warnings;\n\nreturn [{ json: processedData }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1ef3b9f1-5837-4ca4-90e6-b39bc37b778d",
      "name": "Format Telegram Message",
      "type": "n8n-nodes-base.code",
      "position": [
        608,
        16
      ],
      "parameters": {
        "jsCode": "// Format weather data for Telegram message\nconst data = $input.all()[0].json;\n\nif (!data.success) {\n    return [{\n        json: {\n            telegram_message: `\u274c *BMKG Weather Monitoring Error*\\n\\n${data.error}\\n\\nTime: ${data.timestamp}\\n\\n_Powered by BMKG API & n8n_`,\n            parse_mode: 'Markdown'\n        }\n    }];\n}\n\n// Create beautiful Telegram message\nlet message = `\ud83c\udf24\ufe0f *BMKG Weather Report*\\n`;\nmessage += `\ud83d\udccd *${data.location.desa}, ${data.location.kecamatan}*\\n`;\nmessage += `\ud83c\udfd9\ufe0f ${data.location.kotkab}, ${data.location.provinsi}\\n\\n`;\n\n// Current weather\nmessage += `\ud83c\udf21\ufe0f *Current Weather*\\n`;\nmessage += `\u2022 Temperature: *${data.current_weather.temperature}\u00b0C*\\n`;\nmessage += `\u2022 Condition: ${data.current_weather.condition}\\n`;\nmessage += `\u2022 Humidity: ${data.current_weather.humidity}%\\n`;\nmessage += `\u2022 Wind: ${data.current_weather.wind_speed} km/h from ${data.current_weather.wind_direction}\\n`;\nmessage += `\u2022 Visibility: ${data.current_weather.visibility}\\n`;\n\nif (data.current_weather.rain_probability > 0) {\n    message += `\u2022 Rain Prob.: ${data.current_weather.rain_probability}%\\n`;\n}\nmessage += `\\n`;\n\n// Summary\nmessage += `\ud83d\udcca *24 Hour Summary*\\n`;\nmessage += `\u2022 Average Temperature: *${data.summary.avg_temperature}\u00b0C*\\n`;\nmessage += `\u2022 Average Humidity: ${data.summary.avg_humidity}%\\n`;\nmessage += `\u2022 Dominant Condition: ${data.summary.dominant_condition}\\n\\n`;\n\n// Warnings\nif (data.summary.warnings.length > 0) {\n    message += `\u26a0\ufe0f *Warnings & Suggestions:*\\n`;\n    data.summary.warnings.forEach(warning => {\n        message += `\u2022 ${warning}\\n`;\n    });\n    message += `\\n`;\n}\n\n// Next few hours forecast (first 6 hours)\nmessage += `\u23f0 *6 Hour Forecast:*\\n`;\nconst nextHours = data.forecast_24hour.slice(0, 6);\nnextHours.forEach((forecast, index) => {\n    const time = new Date(forecast.time).toLocaleTimeString('en-US', { \n        hour: '2-digit', \n        minute: '2-digit',\n        timeZone: data.location.timezone \n    });\n    message += `\u2022 ${time}: ${forecast.temperature}\u00b0C, ${forecast.condition}`;\n    if (forecast.rain_probability > 30) {\n        message += ` (\u2614${forecast.rain_probability}%)`;\n    }\n    message += `\\n`;\n});\n\nmessage += `\\n\ud83d\udcc5 Updated: ${new Date(data.timestamp).toLocaleString('en-US', {\n    timeZone: data.location.timezone,\n    year: 'numeric',\n    month: 'long',\n    day: 'numeric',\n    hour: '2-digit',\n    minute: '2-digit'\n})} ${data.location.timezone}`;\n\nmessage += `\\n\\n_\ud83e\udd16 Automated by n8n | \ud83d\udce1 Data: BMKG_`;\n\nreturn [{\n    json: {\n        telegram_message: message,\n        parse_mode: 'Markdown',\n        weather_data: data\n    }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ddc33a20-96a8-40bc-9788-6e12f40f88ef",
      "name": "Send Weather Report",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1264,
        400
      ],
      "parameters": {
        "text": "={{ $json.telegram_message }}",
        "chatId": "{{TELEGRAM_CHAT_ID}}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "fdd12bf7-a818-41ef-9c94-65638fd9dac4",
      "name": "Manual Test",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -480,
        240
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "3d011775-063e-4a17-ae84-c6c45bc5f3f1",
      "name": "Check Success",
      "type": "n8n-nodes-base.if",
      "position": [
        368,
        224
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.success }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bfd54738-c07c-4f0e-9acf-e96971e21210",
      "name": "Error Handler",
      "type": "n8n-nodes-base.code",
      "position": [
        624,
        224
      ],
      "parameters": {
        "jsCode": "// Log error details\nconst inputData = $input.all()[0].json;\n\nconsole.error('Weather monitoring error:', inputData);\n\nlet errorMessage = `\u274c *Weather Monitoring System Error*\\n\\n`;\nerrorMessage += `\ud83d\udd50 Time: ${new Date().toLocaleString('en-US')}\\n`;\nerrorMessage += `\u2757 Details: ${inputData.error || 'Unknown error'}\\n\\n`;\nerrorMessage += `_System will try again on next schedule_`;\n\nreturn [{\n    json: {\n        telegram_message: errorMessage,\n        parse_mode: 'Markdown',\n        error_logged: true\n    }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c80c80f8-6f09-4112-8928-9552b6a6ee04",
      "name": "Send Error Alert",
      "type": "n8n-nodes-base.telegram",
      "position": [
        864,
        400
      ],
      "parameters": {
        "text": "={{ $json.telegram_message }}",
        "chatId": "{{TELEGRAM_CHAT_ID}}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "c84af71c-e6b8-465e-b968-9f7eda7f4eaf",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        -64
      ],
      "parameters": {
        "width": 432,
        "height": 416,
        "content": "## \ud83c\udf93 **LEARNING RESOURCES**\n\n### **n8n Documentation:**\n- **Official Docs**: https://docs.n8n.io\n- **Node Reference**: https://docs.n8n.io/integrations/\n- **Workflow Examples**: https://n8n.io/workflows/\n\n### **BMKG API Information:**\n- **API Documentation**: https://api.bmkg.go.id\n- **Region Codes**: Available in API response\n- **Data Format**: JSON structure documentation\n\n### **Telegram Bot API:**\n- **Bot Creation**: https://core.telegram.org/bots\n- **API Reference**: https://core.telegram.org/bots/api\n\n***\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "2581be27-b445-43ba-bc5d-534febc19d38",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        -160
      ],
      "parameters": {
        "width": 784,
        "height": 80,
        "content": "## \ud83c\udf24\ufe0f **BMKG WEATHER MONITORING & TELEGRAM ALERT SYSTEM**"
      },
      "typeVersion": 1
    },
    {
      "id": "889ea56c-10e2-4901-9889-868ed741bf48",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        -64
      ],
      "parameters": {
        "width": 512,
        "height": 560,
        "content": "### **Create Your Bot**\n- Open Telegram and find @BotFather\n\n- Start a chat and send /newbot\n\n- Follow instructions to set bot name and username\n\n- Copy the Bot Token provided (format: 123456789:ABCdef...)\n\n- Save the token securely for configuration\n\n### **Get Your Chat ID**\n- Start a chat with your new bot and send any message\n\n- Visit https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates in a browser (replace <YOUR_BOT_TOKEN> with your bot token)\n\n- Find the Chat ID number in the JSON response under \"chat\": {\"id\": 123456789, ...}\n\n- Copy the Chat ID for use in your workflow or configuration"
      },
      "typeVersion": 1
    },
    {
      "id": "f496550d-b5ea-4d73-bf9b-a38ea9ec3027",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -64
      ],
      "parameters": {
        "width": 528,
        "height": 288,
        "content": "\n### **Enable Automatic Mode:**\n1. **Click workflow name** at top of canvas\n2. **Toggle \"Active\" switch** to ON position\n3. **Workflow status** should show \"Active\"\n4. **Schedule Trigger** will run every 6 hours automatically\n\n### **Schedule Settings:**\n- **Default**: Every 6 hours (4 reports per day)\n- **Modify timing**: Edit \"Schedule Trigger\" node\n- **Options**: 1, 3, 6, 12, or 24 hours\n- **Peak times**: 6AM, 12PM, 6PM, 12AM (with 6-hour interval)"
      },
      "typeVersion": 1
    },
    {
      "id": "13d5c622-9b20-46b6-861a-36cb9babcb1c",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        -64
      ],
      "parameters": {
        "width": 528,
        "height": 368,
        "content": "### **Update Chat IDs**\nReplace {{TELEGRAM_CHAT_ID}} with your actual Chat ID in both \"Send Weather Report\" and \"Send Error Alert\" nodes (e.g., 123456789).\n\n### **Link Telegram Credentials**\n**Select your saved Telegram credential in the \"Credential\" dropdown of both \"Send Weather Report\" and \"Send Error Alert\" nodes.**\n\n### **Configure Location (Optional)**\n**In \"Get BMKG Weather Data\" node, add a Query parameter named adm4 with your BMKG region code (e.g., 31.71.03.1001).**"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c83de10d-8b0b-48ed-bb16-f095f85580fe",
  "connections": {
    "Manual Test": {
      "main": [
        [
          {
            "node": "Get BMKG Weather Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Success": {
      "main": [
        [
          {
            "node": "Format Telegram Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Handler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Handler": {
      "main": [
        [
          {
            "node": "Send Error Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get BMKG Weather Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Weather Data": {
      "main": [
        [
          {
            "node": "Check Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get BMKG Weather Data": {
      "main": [
        [
          {
            "node": "Process Weather Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Telegram Message": {
      "main": [
        [
          {
            "node": "Send Weather Report",
            "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

Stay ahead of weather changes with this comprehensive monitoring system that fetches real-time data from Indonesia's official meteorological agency (BMKG) and delivers beautiful, actionable weather reports directly to your Telegram.

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

⚠️ Heads up: this is satire. The "Hell Yeah!" workflow is a parody of "automate your whole life with AI agents" grindset content. The API endpoints are fictional and the function nodes are illustrativ

HTTP Request, Salesforce, Telegram +4
Slack & Telegram

This workflow continuously monitors the Meta Ads Library for new creatives from a specific competitor pages, logs them into Google Sheets, and sends a concise Telegram notification with the number of

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

This n8n workflow template is designed to provide real-time alerts on new cryptocurrency exchange listings and delistings. It caters especially to crypto traders, investors, and enthusiasts who want t

Supabase, HTTP Request, Telegram +2
Slack & Telegram

&gt; n8n, Binance API, Google Sheets, Slack, Telegram, Jira & Email

HTTP Request, Google Sheets, Slack +3
Slack & Telegram

Stay ahead of commodity market movements with automated news collection, translation, and sector impact analysis. This workflow monitors Oil, Gold, and Grain markets from global English sources, trans

HTTP Request, Discord, Telegram +1