AutomationFlowsWeb Scraping › Public Webhook Relay

Public Webhook Relay

ByJay Hartley @jay on n8n.io

This template only works on n8n local instances!

Cron / scheduled trigger★★★★☆ complexity18 nodesHTTP Request@Horka
Web Scraping Trigger: Cron / scheduled Nodes: 18 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #2443 — 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": "4a82b490-3550-4700-8e9a-5ae1ef7c327f",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -100,
        600
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "seconds",
              "secondsInterval": 10
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "bfe180f2-329c-4d00-9d93-3a87d694cb4e",
      "name": "Get Auth Token",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        720,
        1080
      ],
      "parameters": {
        "url": "https://webhook.site/token",
        "method": "POST",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "26089f68-9d3c-4abd-8541-1d63a8a303c1",
      "name": "Unprocessed Requests",
      "type": "n8n-nodes-base.code",
      "position": [
        1420,
        680
      ],
      "parameters": {
        "jsCode": "let filter_method = \"POST\"\nlet last_processed = $json.value ? $json.value : 0\nlet data = $json.data\n\nfunction dateToTime(datetime){\n  return new Date(datetime.replace(\" \", \"T\") + \"Z\").getTime()\n}\n\n//Convert datetimes to timestamps\ndata.forEach(datum=>{datum.created_at = dateToTime(datum.created_at)})\n\n//Filter all new POST requests\nreturn data.filter(datum=>!last_processed || datum.created_at > last_processed).filter(datum=>!filter_method || datum.method==filter_method)"
      },
      "typeVersion": 2
    },
    {
      "id": "00a5c01c-0cc1-4a56-9b5b-b90cc778ee36",
      "name": "Get Latest Requests",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1060,
        800
      ],
      "parameters": {
        "url": "=https://webhook.site/token/{{ $json.value }}/requests",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "42fbb0c3-34c9-4d97-8761-1b9c84c2f8f7",
      "name": "POST to n8n",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2000,
        680
      ],
      "parameters": {
        "url": "={{ $('Local Webhook Address').first().json.webhook }}",
        "body": "={{ $('Unprocessed Requests').item.json.content }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "=application/json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "fd38a00e-2d7f-4621-8f18-47d1770ef3ac",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        1220,
        680
      ],
      "parameters": {
        "mode": "combine",
        "options": {
          "includeUnpaired": true
        },
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "ef347c09-9870-42db-9109-934277290e0b",
      "name": "Local Webhook Address",
      "type": "n8n-nodes-base.set",
      "position": [
        160,
        700
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3c53386d-23a8-4c8a-b5e9-dfbb755e2be1",
              "name": "webhook",
              "type": "string",
              "value": "http://localhost:5678/webhook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "89baa16d-4a06-4f98-9735-9cc9fda5ff09",
      "name": "Latest Update Time",
      "type": "n8n-nodes-base.code",
      "position": [
        1600,
        680
      ],
      "parameters": {
        "jsCode": "var datetimes = $('Unprocessed Requests').all().map(x=>x.json.created_at)\nreturn {last_time: Math.max(...datetimes)}"
      },
      "typeVersion": 2
    },
    {
      "id": "c826677d-317f-4ad4-959d-153862de4ff7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        620,
        980
      ],
      "parameters": {
        "width": 460.2964713549969,
        "height": 288.34663983291097,
        "content": "## 1. Retrieve existing or get new auth token for webhook.site"
      },
      "typeVersion": 1
    },
    {
      "id": "f4bc9a8c-d9dc-4969-9251-ce892a5ed41e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1080,
        517.8563272190441
      ],
      "parameters": {
        "width": 483.2839292355176,
        "height": 384.1277143350834,
        "content": "## 2. Check if any new requests to webhook that came later than the last checked request"
      },
      "typeVersion": 1
    },
    {
      "id": "adaf19be-cb2f-4727-9881-1a3e4098c528",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1608.5062710597388,
        518.9281636095216
      ],
      "parameters": {
        "width": 395.16534069351894,
        "height": 380.2964713549969,
        "content": "## 3. Relay the request to the local n8n workflow set in *Local Webhook Address*"
      },
      "typeVersion": 1
    },
    {
      "id": "4e7add8c-1e95-4ebb-b7c8-35cee3cdeed5",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -760,
        340
      ],
      "parameters": {
        "color": 4,
        "width": 566.9804381508956,
        "height": 859.1365566530386,
        "content": "# Public Webhook Relay\n## How it Works\nUtilizes webhook.site to receive public webhook requests and relays them to your local n8n workflow\n\n## How to Use\n- To use with local key-value store:\n Go to settings > community nodes and enter ```@horka.tv/n8n-nodes-storage-kv``` to install the key-value store node\n- To use with a different storage method:\n Replace the four key-value nodes with a temporary storage option of your choice (Airtable, Notion, Firebase, etc). This is required to save data between runs.\n- Set **Schedule Trigger** with a polling interval (default is every 10 seconds).\n- Set your local workflow address in Local Webhook Address.\n\n## How to Test\n- Set the workflow to *Active*.\n- After workflow executes at least once, you can check the input to **Get Latest Requests** for your auth token.\n- Run this command: ```curl -X POST -H \"Content-Type: application/json\" -d '{\"foo\":\"bar\"}'  https://webhook.site/[THE AUTH TOKEN YOU JUST GOT]```\n- Now check **Executions** and confirm that the workflow ran all the way to the end. Confirm in **Unprocessed Requests** that your data was retrieved (data[0].content should be equal to {\"foo\":\"bar\"})\n- Now check your other local workflow and confirm that it was triggered with the correct data packet ```{\"foo\":\"bar\"}```.\n- *You're done!*\n\n## Caveats\nAt present, the relay expects a POST with form/json data. If you wish to relay raw data or GET requests, please alter the **Unprocessed Requests** and **POST to n8n** nodes accordingly."
      },
      "typeVersion": 1
    },
    {
      "id": "5d8db2a1-569e-47c0-99a1-d66cb8b86897",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        608.688533362355
      ],
      "parameters": {
        "color": 3,
        "width": 304.23688498154337,
        "height": 264.4911255434983,
        "content": "### 0. Set this to your local workflow address (Production URL or Test URL in your Workflow Trigger node)"
      },
      "typeVersion": 1
    },
    {
      "id": "e728e8fe-1a7d-4f44-96b8-7344b70b0452",
      "name": "Store Auth Token",
      "type": "@horka.tv/n8n-nodes-storage-kv.keyValueStorage",
      "position": [
        880,
        1080
      ],
      "parameters": {
        "key": "auth_token",
        "value": "={{ $json.uuid }}",
        "fileName": "savefile"
      },
      "typeVersion": 1
    },
    {
      "id": "1c19ff08-d6ed-4874-9c1a-69e92b25138a",
      "name": "Store Last Processed",
      "type": "@horka.tv/n8n-nodes-storage-kv.keyValueStorage",
      "position": [
        1800,
        680
      ],
      "parameters": {
        "key": "last_processed",
        "value": "={{ $json.last_time }}",
        "fileName": "savefile"
      },
      "typeVersion": 1
    },
    {
      "id": "ea927186-6147-42c7-8873-029616bdbe6d",
      "name": "Retrieve Auth Token",
      "type": "@horka.tv/n8n-nodes-storage-kv.keyValueStorage",
      "position": [
        380,
        860
      ],
      "parameters": {
        "key": "auth_token",
        "fileName": "savefile",
        "operation": "read"
      },
      "typeVersion": 1
    },
    {
      "id": "f217889c-7104-4183-8adb-4459f6cdc3d6",
      "name": "Retrieve Last Processed",
      "type": "@horka.tv/n8n-nodes-storage-kv.keyValueStorage",
      "position": [
        680,
        620
      ],
      "parameters": {
        "key": "last_processed",
        "fileName": "savefile",
        "operation": "read"
      },
      "typeVersion": 1
    },
    {
      "id": "12293fc3-8964-40da-8326-85c36dade0df",
      "name": "If Auth Token Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        580,
        860
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4356f226-da36-418b-957d-880872ddc420",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.value }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.1
    }
  ],
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Unprocessed Requests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Auth Token": {
      "main": [
        [
          {
            "node": "Store Auth Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Local Webhook Address",
            "type": "main",
            "index": 0
          },
          {
            "node": "Retrieve Last Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Auth Token": {
      "main": [
        [
          {
            "node": "Get Latest Requests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Latest Update Time": {
      "main": [
        [
          {
            "node": "Store Last Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Latest Requests": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Retrieve Auth Token": {
      "main": [
        [
          {
            "node": "If Auth Token Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Auth Token Exists": {
      "main": [
        [
          {
            "node": "Get Latest Requests",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Auth Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Last Processed": {
      "main": [
        [
          {
            "node": "POST to n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Unprocessed Requests": {
      "main": [
        [
          {
            "node": "Latest Update Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Local Webhook Address": {
      "main": [
        [
          {
            "node": "Retrieve Auth Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieve Last Processed": {
      "main": [
        [
          {
            "node": "Merge",
            "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 template only works on n8n local instances!

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

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
Web Scraping

This workflow acts as an automated engagement bot. It sends a Direct Message (DM) with a link or resource to any follower who replies to your post with a specific target keyword.

HTTP Request