AutomationFlowsSlack & Telegram › Keyboard Interest Checker: Geekhack Forum to Discord Notifications

Keyboard Interest Checker: Geekhack Forum to Discord Notifications

ByAnurag Patil @anurag4884 on n8n.io

This n8n workflow automatically monitors GeekHack forum RSS feeds every hour for new keyboard posts in Interest Checks and Group Buys sections. When it finds a new thread (not replies), it: Monitors RSS Feeds: Checks two GeekHack RSS feeds for new posts (50 items each) Filters…

Cron / scheduled trigger★★★★☆ complexity19 nodesRSS Feed ReadPostgresHTTP RequestForm TriggerDebug Helper
Slack & Telegram Trigger: Cron / scheduled Nodes: 19 Complexity: ★★★★☆ Added:

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

This workflow follows the Form Trigger → HTTP Request 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": "H65aZTpWNSXT6jTw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "geekhack updater",
  "tags": [],
  "nodes": [
    {
      "id": "520a15d4-f80e-4ac7-b1dd-2bdf7a804079",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -224,
        176
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7870a6cc-71d8-4e1e-ab03-4d92323d99b0",
      "name": "Interest Checks RSS",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        0,
        32
      ],
      "parameters": {
        "url": "https://geekhack.org/index.php?action=.xml;type=rss2;board=132.0;limit=50",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "d0583fe2-84dd-4844-8d9f-9855a10d83e5",
      "name": "Group Buys RSS",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        0,
        224
      ],
      "parameters": {
        "url": "https://geekhack.org/index.php?action=.xml;type=rss2;board=70.0;limit=50",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "ccf58428-11e7-414a-92ae-8f308c697855",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        224,
        176
      ],
      "parameters": {},
      "typeVersion": 3.2,
      "alwaysOutputData": false
    },
    {
      "id": "cf94de87-5fab-47f8-a853-2b71853f8ea3",
      "name": "Filter New Threads",
      "type": "n8n-nodes-base.code",
      "position": [
        448,
        176
      ],
      "parameters": {
        "jsCode": "// Filter to get only new threads (not replies)\nconst items = $input.all();\nconst newThreads = [];\n\nfor (const item of items) {\n  const title = item.json.title;\n  const link = item.json.link;\n  \n  // Check if title starts with \"Re:\" \n  // This is the most reliable indicator of a reply\n  if (!title.startsWith('Re:')) {\n    \n    // Extract topic ID for tracking\n    const topicMatch = link.match(/topic=(\\d+)/);\n    if (topicMatch) {\n      item.json.topicId = topicMatch[1];\n      newThreads.push(item);\n    }\n  }\n}\n\nreturn newThreads;"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "9f5d422a-880a-4734-9780-4e73afb133cf",
      "name": "Check if Processed",
      "type": "n8n-nodes-base.postgres",
      "position": [
        896,
        224
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "processed_threads",
          "cachedResultName": "processed_threads"
        },
        "where": {
          "values": [
            {
              "value": "={{ $json.topicId }}",
              "column": "topic_id"
            }
          ]
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6,
      "alwaysOutputData": true
    },
    {
      "id": "5a865d9e-ba33-4521-b126-196188a774d0",
      "name": "Update entry",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2016,
        128
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "processed_threads",
          "cachedResultName": "processed_threads"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "title": "={{ $('Filter New Threads').item.json.title }}",
            "topic_id": "={{ $('Filter New Threads').item.json.topicId }}",
            "processed_at": "={{ $now }}"
          },
          "schema": [
            {
              "id": "topic_id",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "topic_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "processed_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "processed_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "69a4700c-9b17-4a18-a031-1e94cf8156b5",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        672,
        176
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "fc90716d-62c2-4f11-9d9d-5637356dbc04",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        896,
        32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5b12ea87-5ff8-4f49-930f-34d598ab8090",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              },
              "leftValue": "={{ $json.isNotEmpty() }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bfee66c4-e285-40ad-aa82-99d8e1d02083",
      "name": "Get geekhack page",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1120,
        32
      ],
      "parameters": {
        "url": "={{ $('Filter New Threads').item.json.link }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (compatible; bot)"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d3ab519c-cdef-4734-bc14-e4305cbe34fe",
      "name": "Extract images",
      "type": "n8n-nodes-base.code",
      "position": [
        1568,
        32
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Get the HTML content from current input\nconst htmlContent = $json.html; // Adjust this path based on your data structure\n\nif (!htmlContent) {\n  return {}; // Return empty if no HTML content\n}\n\n// Use regex to extract all img tags and their attributes\nconst imgRegex = /<img[^>]*>/gi;\nconst srcRegex = /src\\s*=\\s*[\"']([^\"']*)[\"']/i;\nconst altRegex = /alt\\s*=\\s*[\"']([^\"']*)[\"']/i;\nconst classRegex = /class\\s*=\\s*[\"']([^\"']*)[\"']/i;\nconst widthRegex = /width\\s*=\\s*[\"']?([^\"'\\s>]*)[\"']?/i;\nconst heightRegex = /height\\s*=\\s*[\"']?([^\"'\\s>]*)[\"']?/i;\n\n// Find all img tags\nconst imgTags = htmlContent.match(imgRegex) || [];\n\n// Extract image data\nconst images = imgTags.map((imgTag, index) => {\n  const srcMatch = imgTag.match(srcRegex);\n  const altMatch = imgTag.match(altRegex);\n  const classMatch = imgTag.match(classRegex);\n  const widthMatch = imgTag.match(widthRegex);\n  const heightMatch = imgTag.match(heightRegex);\n  \n  return {\n    index: index + 1,\n    src: srcMatch ? srcMatch[1] : '',\n    alt: altMatch ? altMatch[1] : '',\n    class: classMatch ? classMatch[1] : '',\n    width: widthMatch ? widthMatch[1] : '',\n    height: heightMatch ? heightMatch[1] : '',\n    fullTag: imgTag\n  };\n});\n\n// Filter out images without src\nconst validImages = images.filter(img => img.src);\n\n// Return the results as a single object\nreturn {\n  json: {\n    totalImages: validImages.length,\n    images: validImages\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8e786f49-87a0-4bcd-b260-3514b9d1b5a5",
      "name": "Extract author message",
      "type": "n8n-nodes-base.html",
      "position": [
        1344,
        32
      ],
      "parameters": {
        "options": {},
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "html",
              "cssSelector": "=#msg_{{ $('Filter New Threads').item.json.link.split('#msg')[1] }}",
              "returnValue": "html"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "fc206472-2dcf-41bd-8edc-3c56a46d4a0a",
      "name": "Create Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        1792,
        32
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Get the data from previous nodes\nconst threadData = $('Filter New Threads').item.json;\nconst images = $json.images || [];\n\n// Create the base embed with all metadata\nconst baseEmbed = {\n  title: threadData.title,\n  url: threadData.link,\n  color: 5814783,\n  footer: {\n    text: threadData.categories[0]\n  },\n  timestamp: threadData.isoDate\n};\n\n// Create embeds array\nconst embeds = [];\n\n// Limit to max 4 images\nconst maxImages = Math.min(images.length, 4);\n\nfor (let i = 0; i < maxImages; i++) {\n  if (i === 0) {\n    // First embed gets all the metadata + first image\n    embeds.push({\n      ...baseEmbed,\n      image: {\n        url: images[i].src\n      }\n    });\n  } else {\n    // Additional embeds only get URL and image (for multi-image merge)\n    embeds.push({\n      description: \"Additional images\",\n      url: threadData.link,\n      image: {\n        url: images[i].src\n      }\n    });\n  }\n}\n\n// If no images, create single embed without image\nif (images.length === 0) {\n  embeds.push(baseEmbed);\n}\n\n// Create final webhook payload\nconst webhookPayload = {\n  username: \"Geekhack Updates\",\n  embeds: embeds\n};\n\n// Return the payload for the next node\nreturn {\n  json: webhookPayload\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "32d3b8ca-4ff5-440c-ac58-86b591bdfe1f",
      "name": "Insert rows in a table",
      "type": "n8n-nodes-base.postgres",
      "position": [
        0,
        448
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "webhooks",
          "cachedResultName": "webhooks"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "url": "={{ $json.URL }}",
            "created_at": "={{ $json.submittedAt }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "82930485-b5b4-4558-8db7-fe01a6992f45",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -224,
        448
      ],
      "parameters": {
        "options": {},
        "formTitle": "Add new webhooks",
        "formFields": {
          "values": [
            {
              "fieldLabel": "URL"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "78bb0733-add4-4943-b6ed-c6a8fb5d6d0a",
      "name": "Select rows from a table",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2016,
        -64
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "webhooks",
          "cachedResultName": "webhooks"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "options": {},
        "operation": "select",
        "returnAll": true
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "73e86751-764f-4ff0-a79c-2cb639fc634d",
      "name": "Send to discord",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2464,
        32
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $('Create Payload').item.json }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "038c2f22-c473-4455-86b9-366f2062caeb",
      "name": "DebugHelper",
      "type": "n8n-nodes-base.debugHelper",
      "position": [
        2672,
        32
      ],
      "parameters": {
        "category": "doNothing"
      },
      "typeVersion": 1
    },
    {
      "id": "338cacb6-ca43-4a0a-b37d-845085dcd2df",
      "name": "Merge SQL outputs",
      "type": "n8n-nodes-base.merge",
      "position": [
        2240,
        32
      ],
      "parameters": {},
      "typeVersion": 3.2
    }
  ],
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b4fcf226-0b73-437c-8ccf-a982dc4f0d2a",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Get geekhack page",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Filter New Threads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update entry": {
      "main": [
        [
          {
            "node": "Merge SQL outputs",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Create Payload": {
      "main": [
        [
          {
            "node": "Select rows from a table",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract images": {
      "main": [
        [
          {
            "node": "Create Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Group Buys RSS": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check if Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to discord": {
      "main": [
        [
          {
            "node": "DebugHelper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Interest Checks RSS",
            "type": "main",
            "index": 0
          },
          {
            "node": "Group Buys RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get geekhack page": {
      "main": [
        [
          {
            "node": "Extract author message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge SQL outputs": {
      "main": [
        [
          {
            "node": "Send to discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Processed": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter New Threads": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Insert rows in a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Interest Checks RSS": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract author message": {
      "main": [
        [
          {
            "node": "Extract images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select rows from a table": {
      "main": [
        [
          {
            "node": "Merge SQL outputs",
            "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

This n8n workflow automatically monitors GeekHack forum RSS feeds every hour for new keyboard posts in Interest Checks and Group Buys sections. When it finds a new thread (not replies), it: Monitors RSS Feeds: Checks two GeekHack RSS feeds for new posts (50 items each) Filters…

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

Any external system triggers a reminder via webhook with a tenant token — the workflow validates the token, fetches the tenant's channel config and message template from PostgreSQL, renders the messag

Postgres, Telegram, Form Trigger +1
Slack & Telegram

This guide details the setup and functionality of an automated workflow designed to monitor the health, uptime, and SLA compliance of travel supplier APIs, specifically the Amadeus Flight API and Book

HTTP Request, Debug Helper, WhatsApp
Slack & Telegram

The template allows to make Dropcontact batch requests up to 250 requests every 10 minutes (1500/hour). Valuable if high volume email enrichment is expected.

Postgres, HTTP Request, Slack
Slack & Telegram

This automated n8n workflow monitors ingredient price changes from external APIs or manual sources, analyzes historical trends, and provides smart buying recommendations. The system tracks price fluct

HTTP Request, Postgres, Email Send