AutomationFlowsGeneral › Track & Alert Public Transport Delays Using Scrapegraphai, Teams and Todoist

Track & Alert Public Transport Delays Using Scrapegraphai, Teams and Todoist

Byvinci-king-01 @vinci-king-01 on n8n.io

⚠️ COMMUNITY TEMPLATE DISCLAIMER: This is a community-contributed template that uses ScrapeGraphAI (a community node). Please ensure you have the ScrapeGraphAI community node installed in your n8n instance before using this template.

Webhook trigger★★★★☆ complexity16 nodesN8N Nodes ScrapegraphaiMicrosoft TeamsTodoist
General Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #12010 — 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
{
  "id": "y0Yk7da21T4u9zlp",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Public Transport Delay Tracker with Microsoft Teams and Todoist",
  "tags": [],
  "nodes": [
    {
      "id": "efd3927d-c4af-4892-b88b-10f6e51e1c3c",
      "name": "Webhook \u2013 Incoming Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -864,
        608
      ],
      "parameters": {
        "path": "public-transport-tracker",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1.1
    },
    {
      "id": "69275fd6-f3df-4799-a79c-229926c24b59",
      "name": "Validate & Parse Request",
      "type": "n8n-nodes-base.code",
      "position": [
        -688,
        608
      ],
      "parameters": {
        "jsCode": "// Validate incoming body and ensure required fields exist\nconst items = $input.all();\nreturn items.map(item => {\n  const body = item.json;\n  if (!body.line || !body.stop) {\n    throw new Error('Request body must include \"line\" and \"stop\"');\n  }\n  return { json: { line: body.line, stop: body.stop } };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "213c1c60-4f87-4ef5-b2fb-687357604b64",
      "name": "Generate Target URLs",
      "type": "n8n-nodes-base.code",
      "position": [
        -528,
        592
      ],
      "parameters": {
        "jsCode": "// Build status & schedule URLs for the requested line/stop\nconst line = $json.line;\nconst stop = encodeURIComponent($json.stop);\nconst base = `https://www.citytransitauthority.com/api/next-departures?line=${line}&stop=${stop}`;\nreturn [{ json: { url: base, line } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "983317b5-ca3c-4816-996f-278e1fe7dbce",
      "name": "Split URLs",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -304,
        608
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "e99eed8c-aad6-4941-8601-39f242f1a63f",
      "name": "Scrape Schedules & Delays",
      "type": "n8n-nodes-scrapegraphai.scrapegraphAi",
      "position": [
        -96,
        592
      ],
      "parameters": {
        "userPrompt": "Extract the next three departures for this stop including departure_time (ISO8601), destination, and delay_minutes (integer, 0 if on time). Return JSON array named \"departures\".",
        "websiteUrl": "={{ $json.url }}"
      },
      "typeVersion": 1
    },
    {
      "id": "4bffbb82-e2ab-402d-bfba-56fe28280608",
      "name": "Clean & Enrich Data",
      "type": "n8n-nodes-base.code",
      "position": [
        64,
        592
      ],
      "parameters": {
        "jsCode": "// Flatten each departure into individual items with useful metadata\nconst data = $json.departures;\nreturn data.map(dep => {\n  return {\n    json: {\n      line: $item(0).$json.line,\n      destination: dep.destination,\n      departureISO: dep.departure_time,\n      delayMinutes: Number(dep.delay_minutes) || 0,\n      title: `${$item(0).$json.line} \u2192 ${dep.destination} @ ${dep.departure_time}`,\n      msTeamsMessage: `Line ${$item(0).$json.line} to ${dep.destination} departs at ${dep.departure_time}. Current delay: ${dep.delay_minutes} min.`\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "b0edc489-b2f5-4b25-a0bf-79120fed481b",
      "name": "Delay > 0?",
      "type": "n8n-nodes-base.if",
      "position": [
        336,
        576
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.delayMinutes }}",
              "value2": 0,
              "operation": "larger"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "03e62d0c-61ce-45af-abbd-3fa19e246058",
      "name": "Prepare Teams Message",
      "type": "n8n-nodes-base.set",
      "position": [
        368,
        1216
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "a31ab106-851e-4668-b13a-066fbccf53f7",
      "name": "Send Teams Alert",
      "type": "n8n-nodes-base.microsoftTeams",
      "position": [
        608,
        1168
      ],
      "parameters": {
        "chatId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "message": "={{ '<b>' + $json.title + ':</b> ' + $json.message }}",
        "options": {},
        "resource": "chatMessage",
        "contentType": "html"
      },
      "typeVersion": 2
    },
    {
      "id": "5d8a8e7c-ff09-4e3b-92f4-29bde65d2006",
      "name": "Prepare Todoist Task",
      "type": "n8n-nodes-base.set",
      "position": [
        512,
        448
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "917f76e1-152c-49d1-bb85-a867b9b7242f",
      "name": "Create Todoist Task",
      "type": "n8n-nodes-base.todoist",
      "position": [
        656,
        416
      ],
      "parameters": {
        "content": "={{ $json.content }}",
        "options": {},
        "project": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9be8ca93-6421-4f76-92a5-a8567443fc23",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1504,
        256
      ],
      "parameters": {
        "width": 550,
        "height": 738,
        "content": "## How it works\n\nThis workflow provides real-time public transport monitoring for busy commuters. A mobile app or any HTTP client sends a POST request containing a line number and stop name to the webhook trigger. The workflow validates the payload, builds the correct transit authority URL, and hands the request to ScrapeGraphAI. Using AI-powered scraping, the node extracts the next three departures along with current delay information. Cleaned results pass through a conditional check: if any departure is delayed, a Microsoft Teams message alerts the appropriate channel. Regardless of delay status, every departure becomes a Todoist task so travellers can track schedules directly within their personal productivity system.\n\n## Setup steps\n\n1. Create ScrapeGraphAI, Todoist, and Microsoft Teams credentials in n8n.\n2. Replace `{{YOUR_TEAM_ID}}` and `{{YOUR_CHANNEL_ID}}` in the Teams node.\n3. Deploy the workflow and copy the webhook URL.\n4. Send a test POST request with `{\"line\":\"A\",\"stop\":\"Central Station\"}`.\n5. Confirm Teams notifications appear when delays occur.\n6. Check Todoist for newly created tasks.\n7. Enable the workflow for continuous use."
      },
      "typeVersion": 1
    },
    {
      "id": "32e7a97b-9d4d-4638-8d2d-10816f6381fa",
      "name": "Section \u2013 Trigger & Input",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        240
      ],
      "parameters": {
        "color": 7,
        "width": 514,
        "height": 750,
        "content": "## Trigger & Input Validation\n\nThe first two functional nodes form the entry point for the entire automation. The webhook listens for HTTP POST requests so any external system\u2014mobile app, chatbot, or another workflow\u2014can supply line and stop information in real time. Using a webhook keeps latency low and avoids polling schedules that might miss last-minute changes. Immediately after the trigger, the **Validate & Parse Request** Code node checks that the payload includes both a `line` and a `stop`. Throwing an error early prevents wasted API calls and ensures the workflow processes only well-formed requests. Parsing here also normalizes the stop name, converting any special characters to a URL-safe format so downstream nodes can build clean query strings for the transit API."
      },
      "typeVersion": 1
    },
    {
      "id": "50676904-21ff-48b7-bf8b-ed22b39238bf",
      "name": "Section \u2013 Scraping & Transformation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        224
      ],
      "parameters": {
        "color": 7,
        "width": 546,
        "height": 766,
        "content": "## Scraping & Transformation\n\nAfter generating the target URL, the Split In Batches node lets you scale beyond a single stop or line by queuing multiple requests one at a time. This prevents rate-limit issues with the transit authority site. **Scrape Schedules & Delays** leverages ScrapeGraphAI to interpret HTML or JSON responses using an LLM, reliably pulling departure times, destinations, and delay minutes even if the website layout changes. The following **Clean & Enrich Data** Code node flattens the scraped array into individual items and injects helpful metadata such as a human-readable title and a pre-formatted Microsoft Teams message. This transformation keeps later nodes simple because they no longer need to understand raw scrape output."
      },
      "typeVersion": 1
    },
    {
      "id": "14cfbbfb-0959-40b6-91bb-5158b893de2b",
      "name": "Section \u2013 Conditional Logic & Storage",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 450,
        "height": 670,
        "content": "## Conditional Logic & Todoist Storage\n\nThe **Delay > 0?** IF node adds smart routing without over-complicating the overall linear design. If a departure is delayed, the workflow branches to include a Teams alert before converging back to task creation. The **Prepare Todoist Task** Set node converts enriched JSON into Todoist-friendly fields\u2014`content` for the task label, `dueDate` for reminders, and `priority` that increases when a delay is present. Finally, the **Create Todoist Task** node records each departure in the user\u2019s Todoist inbox, giving travellers a personal itinerary that updates automatically. This storage step also serves as an audit trail, enabling users to review historical punctuality trends later."
      },
      "typeVersion": 1
    },
    {
      "id": "4a0fa795-10de-4deb-a53c-ffc435451b18",
      "name": "Section \u2013 Microsoft Teams Alerts",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        864
      ],
      "parameters": {
        "color": 7,
        "width": 450,
        "height": 526,
        "content": "## Microsoft Teams Notifications\n\nDelays often require immediate action\u2014perhaps choosing an alternate route or informing colleagues of a late arrival. When the IF node detects any non-zero `delayMinutes`, execution continues through **Prepare Teams Message** and **Send Teams Alert**. The Set node keeps only the fields required by the Teams connector and formats HTML for improved readability. The Teams node posts directly into a designated channel, ensuring visibility for everyone who needs the update. Because the path eventually rejoins the Todoist branch, even delayed departures are still logged as tasks, giving users one consolidated view of their travel schedule while simultaneously alerting relevant stakeholders in real time."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e145c2a6-c149-45c6-9733-37d7881458b6",
  "connections": {
    "Delay > 0?": {
      "main": [
        [
          {
            "node": "Prepare Teams Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Todoist Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split URLs": {
      "main": [
        [
          {
            "node": "Scrape Schedules & Delays",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Teams Alert": {
      "main": [
        [
          {
            "node": "Prepare Todoist Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean & Enrich Data": {
      "main": [
        [
          {
            "node": "Delay > 0?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Target URLs": {
      "main": [
        [
          {
            "node": "Split URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Todoist Task": {
      "main": [
        [
          {
            "node": "Create Todoist Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Teams Message": {
      "main": [
        [
          {
            "node": "Send Teams Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate & Parse Request": {
      "main": [
        [
          {
            "node": "Generate Target URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Schedules & Delays": {
      "main": [
        [
          {
            "node": "Clean & Enrich Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook \u2013 Incoming Request": {
      "main": [
        [
          {
            "node": "Validate & Parse Request",
            "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

⚠️ COMMUNITY TEMPLATE DISCLAIMER: This is a community-contributed template that uses ScrapeGraphAI (a community node). Please ensure you have the ScrapeGraphAI community node installed in your n8n instance before using this template.

Source: https://n8n.io/workflows/12010/ — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

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

General

A production-ready authentication workflow implementing secure user registration, login, token verification, and refresh token mechanisms. Perfect for adding authentication to any application without

Crypto, Data Table, Execute Workflow Trigger
General

Portfolio Orchestrator. Uses httpRequest. Webhook trigger; 59 nodes.

HTTP Request
General

This n8n template demonstrates how a simple Multi-Layer Perceptron (MLP) neural network can predict housing prices. The prediction is based on four key features, processed through a three-layer model.

General

github code Try yourself

Google Calendar
General

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

N8N Nodes 1Shot