AutomationFlowsWeb Scraping › Weather Alerts via SMS (openweather + Twilio)

Weather Alerts via SMS (openweather + Twilio)

ByDavid Olusola @dae221 on n8n.io

This workflow checks the current weather and forecast every 6 hours using the OpenWeather API, and automatically sends an SMS alert via Twilio if severe conditions are detected. It’s great for keeping teams, family, or field workers updated about extreme heat, storms, or snow.…

Cron / scheduled trigger★★★★☆ complexity9 nodesHTTP RequestTwilio
Web Scraping Trigger: Cron / scheduled Nodes: 9 Complexity: ★★★★☆ Added:

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

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
{
  "nodes": [
    {
      "id": "9ababe8e-1ba5-4255-b97c-1b4e9e79ef99",
      "name": "Setup Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -16
      ],
      "parameters": {
        "width": 712,
        "height": 680,
        "content": "\ud83c\udf24\ufe0f **SETUP REQUIRED:**\n\n1. **OpenWeather API:**\n   - Get FREE API key: openweathermap.org\n   - Update city/coordinates below\n   - 1000 calls/day free tier\n\n2. **Twilio Account:**\n   - Sign up at twilio.com\n   - Get Account SID & Auth Token\n   - Buy phone number ($1/month)\n   - Add to n8n credentials\n\n3. **Recipients:**\n   - Update phone numbers in SMS node\n   - Format: +1234567890\n\n4. **Alert Conditions:**\n   - Currently: rain, snow, extreme temps\n   - Customize in condition nodes\n\n\u26a1 Runs every 6 hours for timely alerts!"
      },
      "typeVersion": 1
    },
    {
      "id": "31bcbe91-559b-4ad4-bd3a-d0b470c7eda4",
      "name": "Check Every 6 Hours",
      "type": "n8n-nodes-base.cron",
      "position": [
        144,
        304
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "fef45e7b-e895-43f6-9101-a8aa879304d5",
      "name": "Get Current Weather",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        352,
        304
      ],
      "parameters": {
        "url": "https://api.openweathermap.org/data/2.5/weather",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "New York,US"
            },
            {
              "name": "appid",
              "value": "YOUR_OPENWEATHER_API_KEY"
            },
            {
              "name": "units",
              "value": "imperial"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "3b0b3916-e46d-4bb3-bc43-660e3da9ac98",
      "name": "Get Weather Forecast",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        352,
        448
      ],
      "parameters": {
        "url": "https://api.openweathermap.org/data/2.5/forecast",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "New York,US"
            },
            {
              "name": "appid",
              "value": "YOUR_OPENWEATHER_API_KEY"
            },
            {
              "name": "units",
              "value": "imperial"
            },
            {
              "name": "cnt",
              "value": "8"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "f1ec579d-ca05-4ab2-bdcb-ba13e43fe32c",
      "name": "Analyze Weather Data",
      "type": "n8n-nodes-base.code",
      "position": [
        544,
        384
      ],
      "parameters": {
        "jsCode": "// Normalize weather data and determine if alerts are needed\nconst currentWeather = $('Get Current Weather').item.json;\nconst forecast = $('Get Weather Forecast').item.json;\n\n// Current weather analysis\nconst current = {\n  temperature: Math.round(currentWeather.main.temp),\n  feels_like: Math.round(currentWeather.main.feels_like),\n  humidity: currentWeather.main.humidity,\n  description: currentWeather.weather[0].description,\n  main_condition: currentWeather.weather[0].main.toLowerCase(),\n  wind_speed: Math.round(currentWeather.wind.speed),\n  city: currentWeather.name,\n  country: currentWeather.sys.country\n};\n\n// Forecast analysis (next 24 hours)\nconst upcoming = [];\nforecast.list.slice(0, 8).forEach(item => {\n  upcoming.push({\n    time: new Date(item.dt * 1000).toLocaleString(),\n    temp: Math.round(item.main.temp),\n    condition: item.weather[0].main.toLowerCase(),\n    description: item.weather[0].description,\n    rain_probability: Math.round((item.pop || 0) * 100)\n  });\n});\n\n// Alert conditions\nconst alerts = [];\n\n// Temperature alerts\nif (current.temperature >= 95) {\n  alerts.push(`\ud83d\udd25 EXTREME HEAT: ${current.temperature}\u00b0F (feels like ${current.feels_like}\u00b0F)`);\n} else if (current.temperature <= 20) {\n  alerts.push(`\ud83e\udd76 EXTREME COLD: ${current.temperature}\u00b0F (feels like ${current.feels_like}\u00b0F)`);\n}\n\n// Severe weather alerts\nif (['thunderstorm', 'tornado'].includes(current.main_condition)) {\n  alerts.push(`\u26c8\ufe0f SEVERE WEATHER: ${current.description}`);\n}\n\n// Precipitation alerts\nif (['rain', 'drizzle'].includes(current.main_condition)) {\n  alerts.push(`\ud83c\udf27\ufe0f RAIN ALERT: ${current.description}`);\n} else if (current.main_condition === 'snow') {\n  alerts.push(`\u2744\ufe0f SNOW ALERT: ${current.description}`);\n}\n\n// Wind alerts\nif (current.wind_speed >= 25) {\n  alerts.push(`\ud83d\udca8 HIGH WINDS: ${current.wind_speed} mph`);\n}\n\n// Check upcoming severe weather\nconst upcomingBad = upcoming.filter(item => \n  ['thunderstorm', 'snow', 'rain'].includes(item.condition) || \n  item.rain_probability >= 70\n);\n\nif (upcomingBad.length > 0) {\n  alerts.push(`\u26a0\ufe0f UPCOMING: ${upcomingBad[0].description} at ${upcomingBad[0].time.split(',')[1]} (${upcomingBad[0].rain_probability}% chance)`);\n}\n\nconst weatherData = {\n  location: `${current.city}, ${current.country}`,\n  current_weather: current,\n  forecast_24h: upcoming,\n  alerts: alerts,\n  has_alerts: alerts.length > 0,\n  alert_count: alerts.length,\n  timestamp: new Date().toLocaleString()\n};\n\nconsole.log(`Weather check for ${weatherData.location}: ${weatherData.alert_count} alerts found`);\n\nreturn {\n  json: weatherData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "5524be11-f80e-4710-85cf-3eb5f6ee8cf8",
      "name": "Alert Needed?",
      "type": "n8n-nodes-base.if",
      "position": [
        752,
        384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-1",
              "operator": {
                "type": "boolean",
                "operation": "equal"
              },
              "leftValue": "={{ $json.has_alerts }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "e903afab-78c9-424a-aa6a-8a985abc8aae",
      "name": "Format SMS Alert",
      "type": "n8n-nodes-base.code",
      "position": [
        944,
        272
      ],
      "parameters": {
        "jsCode": "// Format weather alert SMS message\nconst weatherData = $input.first().json;\n\nlet smsMessage = `\ud83c\udf24\ufe0f WEATHER ALERT - ${weatherData.location}\\n\\n`;\n\n// Add current conditions\nsmsMessage += `NOW: ${weatherData.current_weather.temperature}\u00b0F, ${weatherData.current_weather.description}\\n\\n`;\n\n// Add alerts\nsmsMessage += `\ud83d\udea8 ALERTS (${weatherData.alert_count}):\\n`;\nweatherData.alerts.forEach(alert => {\n  smsMessage += `${alert}\\n`;\n});\n\n// Add next few hours preview\nconst next3Hours = weatherData.forecast_24h.slice(0, 3);\nsmsMessage += `\\n\ud83d\udcc5 NEXT 3 HOURS:\\n`;\nnext3Hours.forEach(forecast => {\n  const time = forecast.time.split(' ')[1]; // Get just time part\n  smsMessage += `${time}: ${forecast.temp}\u00b0F, ${forecast.description}\\n`;\n});\n\nsmsMessage += `\\n\u23f0 Alert sent: ${weatherData.timestamp}`;\n\n// Keep SMS under 160 characters if possible, or split into multiple\nconst formattedAlert = {\n  message: smsMessage,\n  location: weatherData.location,\n  alert_type: weatherData.alerts[0] ? weatherData.alerts[0].split(':')[0] : 'GENERAL',\n  urgency: weatherData.alerts.some(alert => \n    alert.includes('EXTREME') || alert.includes('SEVERE')\n  ) ? 'HIGH' : 'MEDIUM'\n};\n\nconsole.log(`Formatted SMS alert (${formattedAlert.urgency} urgency):`, formattedAlert.alert_type);\n\nreturn {\n  json: formattedAlert\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "49355489-755c-47b7-ba89-a1a9254dd2ef",
      "name": "Send Weather SMS",
      "type": "n8n-nodes-base.twilio",
      "position": [
        1152,
        272
      ],
      "parameters": {
        "message": "={{ $json.message }}",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "daa67817-5a38-4865-a686-4d94862eecdc",
      "name": "Log Alert Sent",
      "type": "n8n-nodes-base.code",
      "position": [
        1344,
        272
      ],
      "parameters": {
        "jsCode": "// Log successful weather alert\nconst alertData = $('Format SMS Alert').item.json;\n\nconsole.log(`\u2705 Weather alert sent successfully!`);\nconsole.log(`\ud83d\udccd Location: ${alertData.location}`);\nconsole.log(`\u26a0\ufe0f Alert Type: ${alertData.alert_type}`);\nconsole.log(`\ud83d\udd25 Urgency: ${alertData.urgency}`);\n\nreturn {\n  json: {\n    status: 'sent',\n    alert_summary: `Weather alert sent for ${alertData.location} - ${alertData.alert_type}`,\n    urgency: alertData.urgency,\n    timestamp: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "Alert Needed?": {
      "main": [
        [
          {
            "node": "Format SMS Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format SMS Alert": {
      "main": [
        [
          {
            "node": "Send Weather SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Weather SMS": {
      "main": [
        [
          {
            "node": "Log Alert Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Every 6 Hours": {
      "main": [
        [
          {
            "node": "Get Current Weather",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Weather Forecast",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Current Weather": {
      "main": [
        [
          {
            "node": "Analyze Weather Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Weather Data": {
      "main": [
        [
          {
            "node": "Alert Needed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Weather Forecast": {
      "main": [
        [
          {
            "node": "Analyze Weather Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow checks the current weather and forecast every 6 hours using the OpenWeather API, and automatically sends an SMS alert via Twilio if severe conditions are detected. It’s great for keeping teams, family, or field workers updated about extreme heat, storms, or snow.…

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

Communication Client Automatisée. Uses httpRequest, emailSend, twilio, firestore. Scheduled trigger; 11 nodes.

HTTP Request, Email Send, Twilio +1
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
Web Scraping

This workflow is an improvement of this workflow by Greg Brzezinka.

HTTP Request, Email Send, XML +1
Web Scraping

N8N-Workflow-Github-Manager. Uses github, httpRequest, n8n. Scheduled trigger; 38 nodes.

GitHub, HTTP Request, n8n
Web Scraping

This workflow uses KlickTipp community nodes, available for self-hosted n8n instances only.

N8N Nodes Klicktipp, Salesforce, Salesforce Trigger +1