AutomationFlowsSlack & Telegram › Scrape Seek.com.au Jobs Daily with Apify to Sheets, Airtable, Slack,…

Scrape Seek.com.au Jobs Daily with Apify to Sheets, Airtable, Slack,…

Original n8n title: Scrape Seek.com.au Jobs Daily with Apify to Sheets, Airtable, Slack, Telegram and Discord

ByUnfenced Group @unfencedgroup on n8n.io

This workflow runs a SEEK.com.au job search via Apify on a daily schedule or on-demand form submission, deduplicates new listings, and routes results to Google Sheets, Airtable, a webhook endpoint, and digest notifications to Slack, Telegram, Discord, and Gmail. Runs daily at 7…

Event trigger★★★★★ complexity40 nodesHTTP RequestGoogle SheetsAirtableSlackTelegramForm Trigger@Apify/N8N Nodes ApifyGmail
Slack & Telegram Trigger: Event Nodes: 40 Complexity: ★★★★★ Added:
Scrape Seek.com.au Jobs Daily with Apify to Sheets, Airtable, Slack,… — n8n workflow card showing HTTP Request, Google Sheets, Airtable integration

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

This workflow follows the Airtable → Form Trigger 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": "E1a3VQCOiinPTfG2",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true,
    "templateCredsSetupCompleted": true
  },
  "name": "Scrape SEEK.com.au jobs daily to Sheets, Airtable, Slack, Email, Telegram or Discord",
  "tags": [],
  "nodes": [
    {
      "id": "79bcb670-3c5e-44cd-acdc-fd2af45d62bf",
      "name": "Map & Normalise",
      "type": "n8n-nodes-base.code",
      "notes": "Maps raw SEEK scraper fields to clean column names and computes Salary Annual.\nHOURS_PER_YEAR = 38 x 52 = 1,976 (standard AU full-time week).\nMidpoint used when both salaryMin and salaryMax are present.\nReturns null for Salary Annual when no salary data is available.",
      "position": [
        1280,
        288
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const H=38*52,M=12;\nfunction toAnnual(v,p){if(v==null)return null;if(p==='HOUR')return Math.round(v*H);if(p==='MONTH')return Math.round(v*M);if(p==='YEAR')return Math.round(v);return null;}\nconst raw=$input.item.json;\nconst cfg=$('Prepare Search').first().json;\nconst min=raw.salaryMin??null,max=raw.salaryMax??null,per=(raw.salaryPeriod||'').toUpperCase();\nconst base=(min!=null&&max!=null)?(min+max)/2:(min??max);\nreturn{json:{Title:raw.title||'',Company:raw.company||'',Location:raw.location||'','Work Type':raw.workType||'','Work Arrangement':raw.workArrangement||'',Salary:raw.salaryLabel||'','Salary Min':min,'Salary Max':max,'Salary Period':raw.salaryPeriod||'','Salary Annual':toAnnual(base,per),'Published Date':raw.publishDate||'',Summary:raw.summary||'','Bullet Points':(raw.bulletPoints||[]).join(' \u00b7 '),Tags:(raw.tags||[]).join(', '),Category:(raw.classificationStructured||[]).map(c=>c.label).join(', '),'Job Score':raw.jobScore??null,'Is Featured':String(raw.isFeatured??''),Description:raw.descriptionText||'',URL:raw.url||'','Job ID':String(raw.id||''),'Content Hash':raw.contentHash||'','Is Repost':String(raw.isRepost??''),'Scraped At':raw.scrapedAt||'',sheetId:cfg.sheetId,sheetName:cfg.sheetName||'Sheet1',webhookUrl:cfg.webhookUrl,airtableBase:cfg.airtableBase,airtableTable:cfg.airtableTable,slackChannel:cfg.slackChannel,telegramChatId:cfg.telegramChatId||'',emailTo:cfg.emailTo||'',discordWebhookUrl:cfg.discordWebhookUrl||'',notifyUrl:cfg.notifyUrl||''}}"
      },
      "typeVersion": 2
    },
    {
      "id": "50df5c83-8d9d-4653-a8e4-be9b1a623690",
      "name": "Dedup: Same Run",
      "type": "n8n-nodes-base.removeDuplicates",
      "notes": "Removes duplicate URLs within the current run.\nSEEK sometimes returns the same listing in both featured and organic positions.\nFirst occurrence wins; copies are dropped.",
      "position": [
        1584,
        288
      ],
      "parameters": {
        "compare": "selectedFields",
        "options": {
          "removeOtherFields": false,
          "disableDotNotation": false
        },
        "fieldsToCompare": "URL"
      },
      "typeVersion": 2
    },
    {
      "id": "b93bfc18-a230-4167-9c8e-549f5ae92631",
      "name": "Dedup: New Only",
      "type": "n8n-nodes-base.removeDuplicates",
      "notes": "Filters out jobs already seen in any previous run.\nURL is the unique key, stored in n8n built-in key-value store.\nUp to 10,000 URLs remembered across executions. No API calls needed.",
      "position": [
        1888,
        288
      ],
      "parameters": {
        "options": {},
        "operation": "removeItemsSeenInPreviousExecutions",
        "dedupeValue": "={{ $json.URL }}"
      },
      "typeVersion": 2
    },
    {
      "id": "66d78184-c16f-4de2-915f-d56e10106585",
      "name": "Alert URL Set?",
      "type": "n8n-nodes-base.if",
      "position": [
        992,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "nf1",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $('Prepare Search').first().json.notifyUrl }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "9e1a1e14-3661-4ca3-8bae-bb61dd9f61b4",
      "name": "\ud83d\udd17 Webhook POST",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2699\ufe0f SETUP (webhook mode):\nSet webhookUrl in Search Config to your target endpoint.\nWorks with Slack incoming webhooks, Make, Zapier, Notion API, or any HTTP endpoint.\nNo credential needed for public endpoints.",
      "position": [
        3200,
        48
      ],
      "parameters": {
        "url": "={{ $json.webhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ { title: $json.Title, company: $json.Company, location: $json.Location, workType: $json['Work Type'], workArrangement: $json['Work Arrangement'], salary: $json.Salary, salaryMin: $json['Salary Min'], salaryMax: $json['Salary Max'], salaryPeriod: $json['Salary Period'], salaryAnnual: $json['Salary Annual'], publishedDate: $json['Published Date'], summary: $json.Summary, bulletPoints: $json['Bullet Points'], tags: $json.Tags, category: $json.Category, jobScore: $json['Job Score'], isFeatured: $json['Is Featured'], description: $json.Description, url: $json.URL, jobId: $json['Job ID'], contentHash: $json['Content Hash'], isRepost: $json['Is Repost'], scrapedAt: $json['Scraped At'] } }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.4
    },
    {
      "id": "0633e215-ebfc-4061-bc56-c8013bc4c691",
      "name": "Notify Failure",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2699\ufe0f OPTIONAL: Set notifyUrl in Search Config to receive a POST here when the scraper returns no data.\nWorks with any webhook: Slack, Make, Zapier, PagerDuty, etc.\nLeave notifyUrl empty to skip silently.",
      "position": [
        1280,
        688
      ],
      "parameters": {
        "url": "={{ $('Prepare Search').first().json.notifyUrl }}",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ { event: 'seek_no_results', workflow: 'SEEK.com.au Job Scraper', timestamp: $now, message: 'The SEEK scraper returned no data. Check your Apify token and compute credits.', apifyUrl: 'https://console.apify.com/actors' } }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.4
    },
    {
      "id": "1ffe072d-2b0b-46c0-ae7f-0c742c79d9a7",
      "name": "\ud83d\udcca Google Sheets Output",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3200,
        -160
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "URL"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "handlingExtraData": "ignoreIt"
        },
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.sheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "7a085032-e210-4dfb-a943-e3b77c7d6840",
      "name": "\ud83d\uddc2 Airtable Output",
      "type": "n8n-nodes-base.airtable",
      "notes": "\u2699\ufe0f SETUP:\n1. Connect your Airtable account via the credential picker\n2. Select your Base and Table\n3. Create fields in Airtable matching the column names from Map & Normalise",
      "position": [
        3360,
        240
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.airtableBase }}"
        },
        "table": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.airtableTable }}"
        },
        "columns": {
          "value": {},
          "schema": [],
          "options": {
            "ignoreFields": "outputMode,sheetId,webhookUrl,airtableBase,airtableTable,slackChannel,notifyUrl"
          },
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "ignoreFields": "outputMode,sheetId,webhookUrl,airtableBase,airtableTable,slackChannel,notifyUrl"
        },
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "760b15ee-6a4a-46a4-acbb-dab11449cca8",
      "name": "\ud83d\udcac Slack Output",
      "type": "n8n-nodes-base.slack",
      "notes": "\u2699\ufe0f SETUP:\n1. Connect your Slack account via the credential picker\n2. The channel is read from slackChannel in Search Config\n3. Edit the message text below to customise the format",
      "onError": "continueRegularOutput",
      "position": [
        3808,
        544
      ],
      "parameters": {
        "text": "={{ $json.slackText }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.slackChannel }}"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        },
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "3bc3186f-0877-4d22-9742-ef4f934c0c38",
      "name": "\ud83d\udcec Telegram Output",
      "type": "n8n-nodes-base.telegram",
      "notes": "\u2699\ufe0f SETUP:\n1. Connect your Telegram bot via the credential picker\n   Create a bot at t.me/BotFather, copy the token\n2. Set telegramChatId in Search Config to your chat ID\n   Find your chat ID by messaging @get_id_bot",
      "onError": "continueRegularOutput",
      "position": [
        3808,
        752
      ],
      "parameters": {
        "text": "={{ $json.telegramText }}",
        "chatId": "={{ $json.telegramChatId }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false,
          "disable_web_page_preview": true
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ff0e396f-4177-4521-a555-c7bcc7e013f8",
      "name": "\ud83c\udfae Discord Output",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2699\ufe0f SETUP:\n1. In Discord: right-click your channel \u2192 Edit Channel \u2192 Integrations \u2192 Webhooks \u2192 New Webhook \u2192 Copy Webhook URL\n2. Paste that URL into discordWebhookUrl in Search Config\n\nNo credential needed \u2014 Discord webhooks are public URLs.",
      "onError": "continueRegularOutput",
      "position": [
        3808,
        1152
      ],
      "parameters": {
        "url": "={{ $json.discordWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.parse($json.discordPayload) }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.4
    },
    {
      "id": "16bd57e8-3d57-4ea1-945c-80ab8b65d09c",
      "name": "Format Digest",
      "type": "n8n-nodes-base.code",
      "notes": "Formats all new jobs into a single digest message.\nProduces: slackText, telegramText, emailHtml, discordText, emailTo, slackChannel, telegramChatId, discordWebhookUrl, jobCount.",
      "position": [
        3504,
        752
      ],
      "parameters": {
        "jsCode": "const jobs=$input.first().json.jobs||[],count=jobs.length;\nif(count===0)return[];\nconst cfg=jobs[0];\nconst sl=jobs.map(j=>`*<${j.URL}|${j.Title}>* \u2014 ${j.Company} | ${j.Location}`+(j.Salary?` | \ud83d\udcb0 ${j.Salary}`:'')+( j.Summary?`\\n${j.Summary.slice(0,120)}${j.Summary.length>120?'\u2026':''}`:'')).join('\\n\\n');\nconst slackText=`\ud83e\udd98 *${count} new SEEK job${count===1?'':'s'} found*\\n\\n`+sl;\nconst tl=jobs.map(j=>`<b><a href=\"${j.URL}\">${j.Title}</a></b> \u2014 ${j.Company} | ${j.Location}`+(j.Salary?` | \ud83d\udcb0 ${j.Salary}`:'')+( j.Summary?`\\n${j.Summary.slice(0,120)}${j.Summary.length>120?'\u2026':''}`:'')).join('\\n\\n');\nconst telegramText=`\ud83e\udd98 <b>${count} new SEEK job${count===1?'':'s'} found</b>\\n\\n`+tl;\nconst embeds=jobs.slice(0,10).map(j=>({title:j.Title.slice(0,256),url:j.URL,description:[`**${j.Company}** \u2014 ${j.Location}`,j.Salary?`\ud83d\udcb0 ${j.Salary}`:'',j['Work Type']?`\u23f0 ${j['Work Type']}`:'',j.Summary?j.Summary.slice(0,200):''].filter(Boolean).join('\\n').slice(0,400),color:5843758}));\nconst rem=count>10?count-10:0;\nlet dc=`\ud83e\udd98 **${count} new SEEK job${count===1?'':'s'} found**`+(rem>0?` \u2014 showing first 10, ${rem} more on SEEK`:'');\nconst discordPayload=JSON.stringify({content:dc,embeds});\nconst rows=jobs.map(j=>`<tr><td style=\"padding:8px;border-bottom:1px solid #eee\"><a href=\"${j.URL}\" style=\"font-weight:bold;color:#1a73e8\">${j.Title}</a></td><td style=\"padding:8px;border-bottom:1px solid #eee\">${j.Company}</td><td style=\"padding:8px;border-bottom:1px solid #eee\">${j.Location}</td><td style=\"padding:8px;border-bottom:1px solid #eee\">${j.Salary||'\u2014'}</td><td style=\"padding:8px;border-bottom:1px solid #eee\">${j['Published Date']}</td></tr>`).join('');\nconst emailHtml=`<h2 style=\"color:#1a73e8\">\ud83e\udd98 ${count} new SEEK job${count===1?'':'s'} found</h2><table style=\"border-collapse:collapse;width:100%;font-family:sans-serif;font-size:14px\"><thead><tr style=\"background:#f8f9fa\"><th style=\"padding:8px;text-align:left\">Title</th><th style=\"padding:8px;text-align:left\">Company</th><th style=\"padding:8px;text-align:left\">Location</th><th style=\"padding:8px;text-align:left\">Salary</th><th style=\"padding:8px;text-align:left\">Posted</th></tr></thead><tbody>${rows}</tbody></table><p style=\"color:#888;font-size:12px\">Powered by unfenced-group/seek-com-au-scraper via Apify</p>`;\nreturn[{json:{jobCount:count,slackText,telegramText,discordPayload,emailHtml,emailSubject:`\ud83e\udd98 ${count} new SEEK job${count===1?'':'s'} found \u2014 ${new Date().toLocaleDateString()}`,slackChannel:cfg.slackChannel,telegramChatId:cfg.telegramChatId,emailTo:cfg.emailTo,discordWebhookUrl:cfg.discordWebhookUrl}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "dff74bc3-1488-4443-93fc-9beeb5123bab",
      "name": "Send to Sheets?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToSheets in Search Config to enable/disable.",
      "position": [
        2784,
        -160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s1",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.sheetId }}",
              "rightValue": "YOUR_GOOGLE_SHEET_ID"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ad3f6754-a072-4ea8-a51c-182aa33dc7b5",
      "name": "Send to Webhook?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToWebhook in Search Config to enable/disable.",
      "position": [
        2784,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s2",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.webhookUrl }}",
              "rightValue": "YOUR_WEBHOOK_URL"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7aab70f0-58a6-4f2d-b696-723c54b4941b",
      "name": "Send to Airtable?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToAirtable in Search Config to enable/disable.",
      "position": [
        2784,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s3",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.airtableBase }}",
              "rightValue": "YOUR_AIRTABLE_BASE_ID"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2ebed3d4-d02a-4528-a1ee-7ec75fc5399c",
      "name": "Send to Slack?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToSlack in Search Config to enable/disable.",
      "position": [
        2784,
        448
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s4",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.jobs[0].slackChannel }}",
              "rightValue": "YOUR_SLACK_CHANNEL"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7569f1c0-ea5b-411c-a68e-a10d976c333c",
      "name": "Send to Telegram?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToTelegram in Search Config to enable/disable.",
      "position": [
        2784,
        640
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s5",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.jobs[0].telegramChatId }}",
              "rightValue": "YOUR_TELEGRAM_CHAT_ID"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "95251e6c-751e-4743-bde1-c260414dccb7",
      "name": "Send to Email?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToEmail in Search Config to enable/disable.",
      "position": [
        2784,
        848
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s6",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.jobs[0].emailTo }}",
              "rightValue": "YOUR_EMAIL_ADDRESS"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "0ac38cca-f958-4d76-a04c-8c1bf7309910",
      "name": "Send to Discord?",
      "type": "n8n-nodes-base.if",
      "notes": "Toggle sendToDiscord in Search Config to enable/disable.",
      "position": [
        2784,
        1040
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "s7",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.jobs[0].discordWebhookUrl }}",
              "rightValue": "YOUR_DISCORD_WEBHOOK_URL"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2204f9f0-76ff-4773-b69d-d9901a45c855",
      "name": "Aggregate: All Jobs",
      "type": "n8n-nodes-base.aggregate",
      "notes": "Collects all new jobs into one item before routing.\nRuns exactly once per execution \u2014 prevents duplicate messages when multiple destinations are enabled.",
      "position": [
        2192,
        288
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "jobs"
      },
      "typeVersion": 1
    },
    {
      "id": "8d7e51e1-79be-4bae-a5e6-7df423747d91",
      "name": "Split Out: Jobs",
      "type": "n8n-nodes-base.splitOut",
      "notes": "Re-expands aggregated jobs back to one item per job for storage destinations (Sheets, Webhook, Airtable).",
      "position": [
        2480,
        80
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "jobs"
      },
      "typeVersion": 1
    },
    {
      "id": "9395151a-01e9-4ce2-b250-177e424f2c33",
      "name": "Collect Enabled Channels",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges all enabled messaging outputs into one stream.\nEnsures Format Digest runs exactly once per execution regardless of how many channels are enabled.",
      "position": [
        3200,
        752
      ],
      "parameters": {
        "numberInputs": 4
      },
      "typeVersion": 3.1
    },
    {
      "id": "cf8a115f-8b93-4201-9ae2-e2f817a45df2",
      "name": "Strip Config Fields",
      "type": "n8n-nodes-base.code",
      "notes": "Removes config passthrough fields before writing to Airtable.\nAirtable rejects field names that don't exist in the table.",
      "position": [
        3056,
        240
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const cfg=['sheetId','sheetName','webhookUrl','airtableBase','airtableTable','slackChannel','telegramChatId','emailTo','discordWebhookUrl','notifyUrl'];\nconst out=Object.assign({},$input.item.json);\ncfg.forEach(k=>delete out[k]);\nreturn{json:out};"
      },
      "typeVersion": 2
    },
    {
      "id": "058a9d34-eec1-42ed-86d7-0c6defc261f4",
      "name": "\ud83d\udd0d Run a Search",
      "type": "n8n-nodes-base.formTrigger",
      "notes": "Users fill in this form to run an instant search.\nOpen the form URL from the node panel to trigger on demand.",
      "position": [
        -320,
        240
      ],
      "parameters": {
        "options": {
          "respondWithOptions": {
            "values": {}
          }
        },
        "formTitle": "\ud83e\udd98 SEEK Job Search",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Job title or keywords",
              "placeholder": "e.g. software engineer, nurse, project manager",
              "requiredField": true
            },
            {
              "fieldLabel": "Location",
              "placeholder": "e.g. Sydney NSW, Melbourne VIC",
              "requiredField": true
            },
            {
              "fieldLabel": "Apify token",
              "placeholder": "apify_api_...",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Work type",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Any"
                  },
                  {
                    "option": "Full time"
                  },
                  {
                    "option": "Part time"
                  },
                  {
                    "option": "Contract/Temp"
                  },
                  {
                    "option": "Casual/Vacation"
                  }
                ]
              }
            },
            {
              "fieldType": "number",
              "fieldLabel": "How many days back to search",
              "placeholder": "7"
            },
            {
              "fieldType": "number",
              "fieldLabel": "Max results",
              "placeholder": "50"
            },
            {
              "fieldType": "email",
              "fieldLabel": "Email address (leave blank to skip)",
              "placeholder": "you@example.com"
            },
            {
              "fieldLabel": "Discord webhook URL (leave blank to skip)",
              "placeholder": "https://discord.com/api/webhooks/..."
            },
            {
              "fieldLabel": "Slack channel (leave blank to skip)",
              "placeholder": "#jobs"
            },
            {
              "fieldLabel": "Telegram chat ID (leave blank to skip)",
              "placeholder": "e.g. 6976256290"
            },
            {
              "fieldLabel": "Google Sheet ID (leave blank to skip)",
              "placeholder": "e.g. 1BxiMVs0XRA..."
            },
            {
              "fieldLabel": "Google Sheet tab name",
              "placeholder": "e.g. Sheet1"
            },
            {
              "fieldLabel": "Airtable base ID (leave blank to skip)",
              "placeholder": "e.g. appXXXXXXXXXXXXXX"
            },
            {
              "fieldLabel": "Airtable table ID (leave blank to skip)",
              "placeholder": "e.g. tblXXXXXXXXXXXXXX"
            },
            {
              "fieldLabel": "Webhook URL (leave blank to skip)",
              "placeholder": "https://your-endpoint.com/hook"
            }
          ]
        },
        "formDescription": "Search SEEK.com.au for jobs and get results delivered to your inbox, Discord, Slack, Telegram, or saved to a spreadsheet or database."
      },
      "typeVersion": 2.2
    },
    {
      "id": "f4ea2570-8b29-489f-b474-f43a472c8335",
      "name": "Daily Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -320,
        480
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "76321ae5-bfc8-4830-9bc5-c4ecdc5d316c",
      "name": "Scheduled Defaults",
      "type": "n8n-nodes-base.set",
      "notes": "\u2699\ufe0f EDIT THIS NODE for the daily scheduled run.\nSet your search terms, location, and which destinations to use.\nLeave a destination value as YOUR_XXX to skip it.",
      "position": [
        -320,
        720
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "sd-001",
              "name": "searchQuery",
              "type": "string",
              "value": "software engineer"
            },
            {
              "id": "sd-002",
              "name": "location",
              "type": "string",
              "value": "Sydney NSW"
            },
            {
              "id": "sd-003",
              "name": "daysOld",
              "type": "number",
              "value": 7
            },
            {
              "id": "sd-004",
              "name": "maxItems",
              "type": "number",
              "value": 50
            },
            {
              "id": "sd-005",
              "name": "workType",
              "type": "string",
              "value": ""
            },
            {
              "id": "sd-006",
              "name": "fetchDetails",
              "type": "boolean",
              "value": false
            },
            {
              "id": "sd-007",
              "name": "skipReposts",
              "type": "boolean",
              "value": false
            },
            {
              "id": "sd-008",
              "name": "emailTo",
              "type": "string",
              "value": "YOUR_EMAIL_ADDRESS"
            },
            {
              "id": "sd-009",
              "name": "discordWebhookUrl",
              "type": "string",
              "value": "YOUR_DISCORD_WEBHOOK_URL"
            },
            {
              "id": "sd-010",
              "name": "slackChannel",
              "type": "string",
              "value": "YOUR_SLACK_CHANNEL"
            },
            {
              "id": "sd-011",
              "name": "telegramChatId",
              "type": "string",
              "value": "YOUR_TELEGRAM_CHAT_ID"
            },
            {
              "id": "sd-012",
              "name": "sheetId",
              "type": "string",
              "value": "YOUR_GOOGLE_SHEET_ID"
            },
            {
              "id": "sd-013",
              "name": "sheetName",
              "type": "string",
              "value": "Sheet1"
            },
            {
              "id": "sd-014",
              "name": "webhookUrl",
              "type": "string",
              "value": "YOUR_WEBHOOK_URL"
            },
            {
              "id": "sd-015",
              "name": "airtableBase",
              "type": "string",
              "value": "YOUR_AIRTABLE_BASE_ID"
            },
            {
              "id": "sd-016",
              "name": "airtableTable",
              "type": "string",
              "value": "YOUR_AIRTABLE_TABLE_ID"
            },
            {
              "id": "sd-017",
              "name": "notifyUrl",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "06f93157-aac8-4b04-a077-74892e0fa574",
      "name": "Prepare Search",
      "type": "n8n-nodes-base.code",
      "notes": "Normalises inputs from both the form trigger and the schedule trigger into one consistent shape.\nAutodetects whether input came from the form or the schedule.",
      "position": [
        80,
        480
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const defaults = $input.item.json;\n\nlet formData = null;\ntry {\n  const f = $('\ud83d\udd0d Run a Search').first().json;\n  if (f && f['Job title or keywords']) formData = f;\n} catch(e) {}\n\nlet searchQuery, location, daysOld, maxItems, workType,\n    fetchDetails, skipReposts,\n    emailTo, discordWebhookUrl, slackChannel, telegramChatId,\n    sheetId, sheetName, webhookUrl, airtableBase, airtableTable, notifyUrl;\n\nif (formData) {\n  searchQuery       = formData['Job title or keywords'] || '';\n  location          = formData['Location'] || '';\n  daysOld           = parseInt(formData['How many days back to search']) || 7;\n  maxItems          = parseInt(formData['Max results']) || 50;\n  const wt          = formData['Work type'] || 'Any';\n  workType          = wt === 'Any' ? '' : wt;\n  fetchDetails      = false;\n  skipReposts       = false;\n  emailTo           = formData['Email address (leave blank to skip)'] || '';\n  discordWebhookUrl = formData['Discord webhook URL (leave blank to skip)'] || '';\n  slackChannel      = formData['Slack channel (leave blank to skip)'] || '';\n  telegramChatId    = formData['Telegram chat ID (leave blank to skip)'] || '';\n  sheetId           = formData['Google Sheet ID (leave blank to skip)'] || '';\n  sheetName         = formData['Google Sheet tab name'] || 'Sheet1';\n  airtableBase      = formData['Airtable base ID (leave blank to skip)'] || '';\n  airtableTable     = formData['Airtable table ID (leave blank to skip)'] || '';\n  webhookUrl        = formData['Webhook URL (leave blank to skip)'] || '';\n  notifyUrl         = '';\n} else {\n  searchQuery       = defaults.searchQuery       || '';\n  location          = defaults.location          || '';\n  daysOld           = defaults.daysOld           || 7;\n  maxItems          = defaults.maxItems          || 50;\n  workType          = defaults.workType          || '';\n  fetchDetails      = defaults.fetchDetails      || false;\n  skipReposts       = defaults.skipReposts       || false;\n  emailTo           = defaults.emailTo           || '';\n  discordWebhookUrl = defaults.discordWebhookUrl || '';\n  slackChannel      = defaults.slackChannel      || '';\n  telegramChatId    = defaults.telegramChatId    || '';\n  sheetId           = defaults.sheetId           || '';\n  sheetName         = defaults.sheetName         || 'Sheet1';\n  webhookUrl        = defaults.webhookUrl        || '';\n  airtableBase      = defaults.airtableBase      || '';\n  airtableTable     = defaults.airtableTable     || '';\n  notifyUrl         = defaults.notifyUrl         || '';\n}\n\nconst body = {\n  searchQuery, location,\n  maxResults: maxItems,\n  daysOld, fetchDetails, skipReposts,\n  sortMode: 'ListedDate',\n};\nif (workType) body.workType = workType;\n\nconst waitForFinish = maxItems <= 50 ? 120 : maxItems <= 200 ? 240 : 480;\n\nreturn { json: {\n  body, waitForFinish,\n  emailTo, discordWebhookUrl, slackChannel, telegramChatId,\n  sheetId, sheetName, webhookUrl, airtableBase, airtableTable, notifyUrl\n}};"
      },
      "typeVersion": 2
    },
    {
      "id": "821eaca0-6498-48b4-817a-4e874a3e8999",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        96
      ],
      "parameters": {
        "color": "#C6A23F",
        "width": 420,
        "height": 812,
        "content": "## \ud83e\udd98 SEEK.com.au Job Scraper\n\nScrapes SEEK.com.au and delivers new job listings to up to 7 destinations. Deduplication means you only ever receive listings you haven't seen before.\n\n### \u26a1 Instant search\nOpen the **\ud83d\udd0d Run a Search** form URL \u2192 fill in keywords, location, your Apify token, and destinations \u2192 submit. Results in ~2 minutes.\n\n### \u23f0 Daily alerts\nEdit **Scheduled Defaults** \u2192 set your search and destinations \u2192 activate the workflow. Runs at 7 AM daily.\n\n---\n\n### \u2699\ufe0f One-time setup\n\n1. **Install community node** \u2014 Canvas \u2192 + \u2192 search `Apify` \u2192 Install (`@apify/n8n-nodes-apify`)\n2. **Apify account** \u2014 Get a free token at `console.apify.com/settings/integrations` \u2192 connect on **Run SEEK Scraper**\n3. **Gmail** \u2014 Connect on **\ud83d\udce7 Email Output** (optional)\n4. **Slack** \u2014 Connect on **\ud83d\udcac Slack Output** (optional)\n5. **Telegram** \u2014 Connect on **\ud83d\udcec Telegram Output** (optional)\n\nDiscord, Sheets, Airtable, and Webhook only need a URL/ID \u2014 no OAuth required.\n\n---\n\n### \ud83d\udce4 How destinations work\n\nFill in the value \u2192 fires. Leave as `YOUR_XXX` \u2192 skips silently.\n\n| Destination | What to fill in |\n|---|---|\n| \ud83d\udcca Sheets | Google Sheet ID |\n| \ud83d\uddc2 Airtable | Base ID + Table ID |\n| \ud83d\udd17 Webhook | Any HTTP endpoint URL |\n| \ud83d\udcac Slack | Channel name (#jobs) |\n| \ud83d\udcec Telegram | Chat ID |\n| \ud83d\udce7 Email | Email address |\n| \ud83c\udfae Discord | Webhook URL |"
      },
      "typeVersion": 1
    },
    {
      "id": "cf2721b2-41ad-47f5-b8fa-e03429f8e3aa",
      "name": "Run SEEK Scraper",
      "type": "@apify/n8n-nodes-apify.apify",
      "notes": "Runs the SEEK actor and waits for results.\nAuthentication is handled via the Apify credential \u2014 no token needed here.",
      "position": [
        688,
        480
      ],
      "parameters": {
        "actorId": "unfenced-group~seek-com-au-scraper",
        "operation": "Run actor and get dataset"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3f36f21f-4181-4318-b58c-a16d62f6d045",
      "name": "Step 1: Configure",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        -192
      ],
      "parameters": {
        "width": 424,
        "height": 412,
        "content": "### \u2709\ufe0f Step 1 \u2014 Configure\n\nFor **daily scheduled alerts**, edit **Scheduled Defaults**:\n- Set your `searchQuery` and `location`\n- Fill in destinations (email, Slack, etc.)\n- Leave any destination as `YOUR_XXX` to skip it\n- Connect your **Apify credential** on the Run SEEK Scraper node\n\nFor **on-demand search**, just open the form URL from **\ud83d\udd0d Run a Search** \u2014 no node editing needed.\n\n**Daily Schedule** \u2014 Fires at 7 AM every day. Edit **Scheduled Defaults** with your search terms and destinations. Only new jobs (not seen in previous runs) are delivered."
      },
      "typeVersion": 1
    },
    {
      "id": "f3551300-8f4d-43d4-81dd-52027a0acf3e",
      "name": "Step 2: Scrape and Deduplicate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        176
      ],
      "parameters": {
        "width": 360,
        "height": 292,
        "content": "### \ud83d\udd0d Step 2 \u2014 Scrape & Deduplicate\n\n**Run SEEK Scraper** calls the Apify actor and returns matching jobs.\n\n**Dedup: Same Run** removes duplicate listings within the same run.\n\n**Dedup: New Only** filters out jobs already seen in previous runs \u2014 so you only get fresh listings every time."
      },
      "typeVersion": 1
    },
    {
      "id": "d45e2fc8-d755-4d99-9039-c0e4c406fcd4",
      "name": "Step 3: Route to Destinations",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2064,
        832
      ],
      "parameters": {
        "width": 360,
        "height": 336,
        "content": "### \ud83d\udce4 Step 3 \u2014 Route to Destinations\n\nEach destination fires only when its value is filled in.\nLeave as `YOUR_XXX` \u2192 silently skips.\n\n**Per-job storage** (one row per listing):\n\ud83d\udcca Google Sheets \u00b7 \ud83d\uddc2 Airtable \u00b7 \ud83d\udd17 Webhook\n\n**Digest messages** (one message per run):\n\ud83d\udce7 Email \u00b7 \ud83d\udcac Slack \u00b7 \ud83d\udcec Telegram \u00b7 \ud83c\udfae Discord"
      },
      "typeVersion": 1
    },
    {
      "id": "3a217b49-9908-4167-bda4-b80b97df8931",
      "name": "\ud83d\udce7 Email Output",
      "type": "n8n-nodes-base.gmail",
      "notes": "\u2699\ufe0f Connect your Gmail account. emailTo is read from the form or Scheduled Defaults.",
      "onError": "continueRegularOutput",
      "position": [
        3808,
        944
      ],
      "parameters": {
        "sendTo": "={{ $json.emailTo }}",
        "message": "={{ $json.emailHtml }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.emailSubject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "aecd0a92-b714-4305-933b-c1f2ed4a58f2",
      "name": "BG: Prepare",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        624
      ],
      "parameters": {
        "color": 4,
        "width": 352,
        "height": 276,
        "content": "## \ud83d\udd00 Prepare Search\n\nDetects whether the run came from the **form** or the **schedule** using try/catch on the form node.\n\nBuilds the Apify actor input body and carries all destination config (email, Slack, Sheet ID, etc.) forward as passthrough fields on every item."
      },
      "typeVersion": 1
    },
    {
      "id": "71f661fa-1766-43e9-bc16-b80e09ddaa46",
      "name": "BG: Scraper",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        624
      ],
      "parameters": {
        "color": 4,
        "width": 420,
        "height": 260,
        "content": "## \ud83d\udd77\ufe0f Run SEEK Scraper\n\nCalls **unfenced-group/seek-com-au-scraper** via Apify and waits for results.\n\n- **output[0]** \u2192 job results (success)\n- **output[1]** \u2192 failure \u2192 optional alert\n\nEach user connects their own Apify account \u2014 billed to their compute credits."
      },
      "typeVersion": 1
    },
    {
      "id": "7423d6d9-59fe-47a7-b95e-168400d3fbd9",
      "name": "BG: Map and Dedup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        48
      ],
      "parameters": {
        "color": 4,
        "width": 1080,
        "height": 260,
        "content": "## \ud83d\uddc2\ufe0f Map, Normalise & Deduplicate\n\n**Map & Normalise** \u2014 Renames raw scraper fields to clean column names and computes `Salary Annual` (AU standard 38hr \u00d7 52wk). Passes destination config as passthrough on every job item.\n\n**Dedup: Same Run** \u2014 Removes duplicate URLs within this run. SEEK sometimes returns the same listing in featured and organic positions.\n\n**Dedup: New Only** \u2014 Filters out job URLs already seen in previous executions. Stored in n8n's built-in key-value store (up to 10,000 URLs)."
      },
      "typeVersion": 1
    },
    {
      "id": "d7580015-6c17-4c71-b484-116040a3e08a",
      "name": "BG: Failure Alert",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        848
      ],
      "parameters": {
        "color": 6,
        "width": 600,
        "height": 244,
        "content": "## \u26a0\ufe0f Optional Failure Alert\n\n**Alert URL Set?** \u2014 Checks whether `notifyUrl` is filled in.\n\n**Notify Failure** \u2014 POSTs a JSON error payload to that URL when the scraper returns no data. Works with Slack incoming webhooks, Make, PagerDuty, or any HTTP endpoint.\n\nLeave `notifyUrl` empty in Scheduled Defaults to skip silently."
      },
      "typeVersion": 1
    },
    {
      "id": "4c594d7f-44e1-45cc-845f-437665a122d2",
      "name": "BG: Aggregate Split",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        -240
      ],
      "parameters": {
        "color": 4,
        "width": 660,
        "height": 280,
        "content": "## \ud83d\udce6 Aggregate & Route\n\n**Aggregate: All Jobs** \u2014 Collects all new jobs into a single item. Ensures messaging channels each receive exactly **one digest per run**, not one per job.\n\n**Split Out: Jobs** \u2014 Re-expands the array to individual items for storage destinations (Sheets, Airtable, Webhook) which need one record per job.\n\nBoth paths then fan out in parallel to all enabled destinations."
      },
      "typeVersion": 1
    },
    {
      "id": "d5c87357-fbe4-43f9-a533-375dbd3a5587",
      "name": "BG: Storage",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2672,
        -480
      ],
      "parameters": {
        "color": 5,
        "width": 900,
        "height": 296,
        "content": "## \ud83d\udcca Storage Destinations\n\nOne record written **per job**. Fill in the value \u2192 fires. Leave as `YOUR_XXX` \u2192 skips silently.\n\n**Send to Sheets?** \u2192 \ud83d\udcca Google Sheets\nAppends/updates one row per job matched on URL.\n\n**Send to Webhook?** \u2192 \ud83d\udd17 Webhook POST\nPOSTs each job as JSON to any HTTP endpoint \u2014 Make, Zapier, Notion API, custom backends.\n\n**Send to Airtable?** \u2192 \ud83d\uddc2 Airtable\nCreates one record per job. Strip Config Fields removes routing metadata before the write."
      },
      "typeVersion": 1
    },
    {
      "id": "be3e5a40-8cad-479e-845c-93754afebfd0",
      "name": "BG: Messaging",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2784,
        1312
      ],
      "parameters": {
        "color": 5,
        "width": 1148,
        "height": 372,
        "content": "## \ud83d\udcac Messaging Destinations\n\nOne **digest message** sent per run (all new jobs in one message). Fill in the value \u2192 fires. Leave as `YOUR_XXX` \u2192 skips.\n\n**Collect Enabled Channels** \u2014 Merges all four gate outputs so Format Digest runs exactly once, regardless of how many channels are enabled.\n\n**Format Digest** \u2014 Builds formatted messages for all channels in one pass: mrkdwn for Slack, HTML for Telegram and Email, rich embeds for Discord.\n\n---\n\n**\ud83d\udcac Slack** \u2014 Requires Slack OAuth2 credential\n**\ud83d\udcec Telegram** \u2014 Requires Telegram Bot credential\n**\ud83d\udce7 Email** \u2014 Requires Gmail OAuth2 credential\n**\ud83c\udfae Discord** \u2014 No credential needed, uses webhook URL\n\nAll outputs use `continueRegularOutput` \u2014 one failing channel never blocks others."
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "76e1f6d7-e523-4ef0-aa36-87d15cef3ca5",
  "nodeGroups": [],
  "connections": {
    "Format Digest": {
      "main": [
        [
          {
            "node": "\ud83d\udcac Slack Output",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udcec Telegram Output",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83c\udfae Discord Output",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udce7 Email Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert URL Set?": {
      "main": [
        [
          {
            "node": "Notify Failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Schedule": {
      "main": [
        [
          {
            "node": "Scheduled Defaults",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Search": {
      "main": [
        [
          {
            "node": "Run SEEK Scraper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Email?": {
      "main": [
        [
          {
            "node": "Collect Enabled Channels",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Send to Slack?": {
      "main": [
        [
          {
            "node": "Collect Enabled Channels",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dedup: New Only": {
      "main": [
        [
          {
            "node": "Aggregate: All Jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dedup: Same Run": {
      "main": [
        [
          {
            "node": "Dedup: New Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map & Normalise": {
      "main": [
        [
          {
            "node": "Dedup: Same Run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Sheets?": {
      "main": [
        [
          {
            "node": "\ud83d\udcca Google Sheets Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out: Jobs": {
      "main": [
        [
          {
            "node": "Send to Sheets?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Webhook?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Airtable?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run SEEK Scraper": {
      "main": [
        [
          {
            "node": "Map & Normalise",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Alert URL Set?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Discord?": {
      "main": [
        [
          {
            "node": "Collect Enabled Channels",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Send to Webhook?": {
      "main": [
        [
          {
            "node": "\ud83d\udd17 Webhook POST",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Airtable?": {
      "main": [
        [
          {
            "node": "Strip Config Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Telegram?": {
      "main": [
        [
          {
            "node": "Collect Enabled Channels",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udd0d Run a Search": {
      "main": [
        [
          {
            "node": "Scheduled Defaults",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scheduled Defaults": {
      "main": [
        [
          {
            "node": "Prepare Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate: All Jobs": {
      "main": [
        [
          {
            "node": "Split Out: Jobs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Slack?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Telegram?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Email?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send to Discord?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Strip Config Fields": {
      "main": [
        [
          {
            "node": "\ud83d\uddc2 Airtable Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect Enabled Channels": {
      "main": [
        [
          {
            "node": "Format Digest",
            "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 workflow runs a SEEK.com.au job search via Apify on a daily schedule or on-demand form submission, deduplicates new listings, and routes results to Google Sheets, Airtable, a webhook endpoint, and digest notifications to Slack, Telegram, Discord, and Gmail. Runs daily at 7…

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

This workflow collects patient symptoms via an n8n Form, uses OpenAI (GPT-4o Mini) to draft a SOAP note, and sends it to a doctor for email approval in Gmail. Approved notes are saved to Google Sheets

Form Trigger, OpenAI, Gmail +4
Slack & Telegram

This workflow collects a blog brief via an n8n form, uses Anthropic Claude to generate an outline and write each section, saves both outline and article as formatted Google Docs in Google Drive, then

Form Trigger, Google Sheets, HTTP Request +2
Slack & Telegram

Vendorbot Form Filler. Uses executeCommand, gmail, telegram, slack. Event-driven trigger; 39 nodes.

Execute Command, Gmail, Telegram +6
Slack & Telegram

This workflow is an AI-powered roto matte generation and first-pass compositing pipeline designed for VFX production. It transforms structured roto requests into multiple high-precision matte passes u

HTTP Request, Slack, Error Trigger +4
Slack & Telegram

Automatically transform any website URL into a complete portfolio entry with professional screenshots and AI-generated Upwork project descriptions. Freelancers building their Upwork/portfolio from pas

HTTP Request, Google Drive, Google Sheets +2