AutomationFlowsMarketing & Ads › Upwork Job Alert Workflow

Upwork Job Alert Workflow

Upwork Job Alert workflow. Uses whatsApp, @apify/n8n-nodes-apify, googleSheets, chatTrigger. Chat trigger; 11 nodes.

Chat trigger trigger★★★★☆ complexityAI-powered11 nodesWhatsApp@Apify/N8N Nodes ApifyGoogle SheetsChat Trigger
Marketing & Ads Trigger: Chat trigger Nodes: 11 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Apifyn8N Nodes Apify → Google Sheets 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": "2N6RJnwzjP8bVcFu",
  "meta": {
    "site": "https://github.com/zengfr/n8n-workflow-all-templates",
    "name": "Track freelance jobs from Apify and get instant WhatsApp alerts for new leads",
    "wechat": "youandme10086",
    "id": 9941,
    "update_time": "2025-11-10"
  },
  "name": "Upwork Job Alert workflow",
  "tags": [],
  "nodes": [
    {
      "id": "b5449656-57b5-40aa-8a83-b3279b11f734",
      "name": "Edit Fields1",
      "type": "n8n-nodes-base.set",
      "position": [
        4064,
        816
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f86d90d2-d03a-4553-9bc0-820da3f74b56",
              "name": "Title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "880e6f53-02c9-47f4-9d15-a2e9f086891f",
              "name": "Description",
              "type": "string",
              "value": "={{ $json.description }}"
            },
            {
              "id": "e098c4db-51f5-4038-811a-8f00c3924475",
              "name": "Status",
              "type": "string",
              "value": "New"
            },
            {
              "id": "e0b12de9-6e31-4405-8aed-82e90b85ed98",
              "name": "Payment Type",
              "type": "string",
              "value": "={{ $json.jobType }}"
            },
            {
              "id": "830a8fec-9b27-47d5-b933-eb0d5b0add9f",
              "name": "Experience",
              "type": "string",
              "value": "={{ $json.experienceLevel }}"
            },
            {
              "id": "8e733eaa-7592-4e86-b66b-5eeaa0e3fc97",
              "name": "Salary",
              "type": "string",
              "value": "={{ $json.budget }}"
            },
            {
              "id": "9e733eaa-7592-4e86-b66b-5eeaa0e3fc98",
              "name": "Location",
              "type": "string",
              "value": "={{ $json.clientLocation }}"
            },
            {
              "id": "ce733eaa-7592-4e86-b66b-5eeaa0e3fca1",
              "name": "URL",
              "type": "string",
              "value": "={{ $json.url }}"
            },
            {
              "id": "de733eaa-7592-4e86-b66b-5eeaa0e3fca2",
              "name": "Date",
              "type": "string",
              "value": "={{ $json.absoluteDate }}"
            },
            {
              "id": "ee733eaa-7592-4e86-b66b-5eeaa0e3fca3",
              "name": "Found",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "54646432-f8fe-4c14-9976-c151f16c9a86",
              "name": "hire_percentage",
              "type": "string",
              "value": "={{ $json.clientHireRatePercent }}"
            },
            {
              "id": "fae26632-6c73-42cc-b7da-90ae8c757d4d",
              "name": "spending_history",
              "type": "string",
              "value": "={{ $json.clientTotalSpent }}"
            },
            {
              "id": "76f9d4ee-2a39-478d-9955-9cd1df47d8c4",
              "name": "rating",
              "type": "string",
              "value": "={{ $json.clientRating }}"
            },
            {
              "id": "492ee934-f629-4ffe-8f6f-63bed6cc4f9f",
              "name": "score",
              "type": "string",
              "value": "={{ $json.score }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9672eb74-4c5a-439b-aab5-4e06663a937f",
      "name": "Send message",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        4576,
        816
      ],
      "parameters": {
        "textBody": "=# New Job Alet make the Proposal ASAP\n\nName : \n\nJob Title : {{ $json['Job Tile'] }}\n\nPosted Date : {{ $json['job posted'] }}\n\nHourly Budget : {{ $json.budget }}\n\nPayment Type : {{ $json['Payment type'] }}\n",
        "operation": "send",
        "phoneNumberId": "745077835357667",
        "additionalFields": {
          "previewUrl": false
        },
        "recipientPhoneNumber": "Add your number"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c49b734d-ba70-41cf-bbe6-3b9ddc2b3472",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3408,
        624
      ],
      "parameters": {
        "color": 3,
        "width": 1376,
        "height": 400,
        "content": "# Freelance Job Tracker with WhatsApp Alerts"
      },
      "typeVersion": 1
    },
    {
      "id": "847030db-1bc7-424a-b73b-c736109da905",
      "name": "Run an Actor",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        3584,
        816
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "id",
          "value": "Add your Actor Id"
        },
        "timeout": {},
        "customBody": "={\n    \n    \"paymentVerified\": true,\n    \"query\": \"{{ $json.chatInput }}\"\n}"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dfb38ee0-cb7e-4c6a-ba72-9fc8fa592ec5",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        3904,
        816
      ],
      "parameters": {
        "jsCode": "// === INPUT ===\n// Expecting keywords already provided by the previous node (like Chat Trigger)\nconst inputData = $input.item.json;\nconst query = inputData.keywords || \"\"; // make sure this field exists\nconst keywords = Array.isArray(query)\n  ? query.map(k => k.toLowerCase())\n  : query.toLowerCase().split(/\\s+/).filter(k => k.length > 1);\n\n// === PROCESS EACH ITEM ===\nreturn items.map(item => {\n  const title = (item.json.title || \"\").toLowerCase();\n  const description = (item.json.description || \"\").toLowerCase();\n\n  // Combine both fields for scoring\n  const text = title + \" \" + description;\n\n  // Score relevance\n  let score = 0;\n  keywords.forEach(word => {\n    const regex = new RegExp(\"\\\\b\" + word + \"\\\\b\", \"gi\");\n    const matches = text.match(regex);\n    if (matches) score += matches.length * 20; // weight per keyword match\n  });\n\n  // Add extra weight if keyword appears in title\n  keywords.forEach(word => {\n    const regexTitle = new RegExp(\"\\\\b\" + word + \"\\\\b\", \"gi\");\n    const matchesInTitle = title.match(regexTitle);\n    if (matchesInTitle) score += matchesInTitle.length * 30;\n  });\n\n  // Normalize score\n  if (score > 100) score = 100;\n\n  // Attach score\n  item.json.score = score;\n\n  return item;\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "fc856cc0-beb8-4b31-89df-cd26bb295e49",
      "name": "Append or update row in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4224,
        816
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $json.URL }}",
            "Date": "={{ $json.Date }}",
            "Found": "={{ $json.Found }}",
            "Score": "={{ $json.score }}",
            "Title": "={{ $json.Title }}",
            "Salary": "={{ $json.Salary }}",
            "Status": "={{ $json.Status }}",
            "Location": "={{ $json.Location }}",
            "Experience": "={{ $json.Experience }}",
            "Description": "={{ $json.Description }}",
            "Payment Type": "={{ $json['Payment Type'] }}"
          },
          "schema": [
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Type",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Payment Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Experience",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Experience",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Salary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Salary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Found",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Found",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Title"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "Add your sheet url",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rBRKpiA2COarqpmYTAR1pl2pOtj4l3ftBEjoNc6lU_A",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rBRKpiA2COarqpmYTAR1pl2pOtj4l3ftBEjoNc6lU_A/edit?usp=drivesdk",
          "cachedResultName": "Upwork Whatsapp alert"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2e803289-97da-41b5-98cc-d91c985b7d1b",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        3440,
        816
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "9b24fdab-a2f2-4449-ac11-81cc3d84ba6d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2464,
        624
      ],
      "parameters": {
        "width": 880,
        "height": 1152,
        "content": "## \ud83d\udcbc Freelance Job Tracker with WhatsApp Alerts (Apify + n8n)\n\n## \ud83d\udfe8 Workflow Overview\n\nThis workflow automates freelance job tracking by using Apify Actors to scrape job listings (e.g., from Upwork or Fiverr) and sends real-time WhatsApp alerts when new opportunities are found.\nIt\u2019s designed for freelancers, agencies, and solopreneurs who want to stay updated without constantly checking job sites.\n\n\ud83e\udde9 Sticky Notes Summary\n\n\ud83d\udfe9 1. When Chat Message Received (Trigger)\n\nThis node listens for a message in WhatsApp (via the connected API or webhook).\nYou can also trigger it manually to start the workflow when needed.\n\n\ud83d\udfe9 2. Run Apify Actor\n\nRuns your Apify Actor that scrapes freelance job listings from platforms like Upwork, Freelancer, or Fiverr.\nMake sure your Apify API token is connected in credentials and that your actor ID matches the one from your Apify dashboard.\n\n\ud83d\udfe9 3. Get Dataset Items\n\nRetrieves the latest dataset items (scraped job listings) from the Apify run.\nEach dataset item usually contains job title, link, description, and price/rate.\n\n\ud83d\udfe9 4. Code (JavaScript)\n\nThis node filters and formats the dataset results.\nExample: Only include jobs that contain specific keywords like automation, Python, or n8n.\nIt also limits the number of alerts to avoid message spam.\n\n\ud83d\udfe9 5. Edit Fields\n\nMaps the cleaned data (title, budget, URL) into proper fields for further processing.\nThis ensures consistent message formatting for both Sheets and WhatsApp.\n\n\ud83d\udfe9 6. Append or Update Row in Google Sheet\n\nLogs each new job found into your Google Sheet for record-keeping.\nIf a job already exists (based on URL), it updates instead of duplicating \u2014 keeping your sheet clean.\n\n\ud83d\udfe9 7. Edit Fields (Prepare Message)\n\nPrepares the message text for WhatsApp.\nExample:\n\n\ud83d\udd14 New Job Alert!\n\ud83d\udcbc {{job_title}}\n\ud83d\udcb0 Budget: {{price}}\n\ud83d\udd17 Link: {{url}}\n\n\n\ud83d\udfe9 8. Send WhatsApp Message\n\nSends the formatted alert message directly to your WhatsApp using your WhatsApp API or Twilio integration.\nThis is the final step that keeps you instantly informed when new jobs are posted."
      },
      "typeVersion": 1
    },
    {
      "id": "256ef1af-d543-4bab-af85-6c6a9a891849",
      "name": "Edit Fields To send Specific Data",
      "type": "n8n-nodes-base.set",
      "position": [
        4400,
        816
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d78912c8-c63e-4f32-af19-60a568d02377",
              "name": "Job Tile",
              "type": "string",
              "value": "={{ $json.Title }}"
            },
            {
              "id": "7ade5447-cac2-4fc2-bff2-517a8583d11e",
              "name": "job posted",
              "type": "string",
              "value": "={{ $json.Date }}"
            },
            {
              "id": "caff77ba-6c86-4685-b752-bae8ed41e58f",
              "name": "Payment type",
              "type": "string",
              "value": "={{ $json['Payment Type'] }}"
            },
            {
              "id": "52215059-aa70-469b-8b09-f51ada9a5fa0",
              "name": "score",
              "type": "string",
              "value": "={{ $json.Score }}"
            },
            {
              "id": "89926694-3595-4d22-b6ea-00228fb38a11",
              "name": "budget",
              "type": "string",
              "value": "={{ $json.Salary }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "01b532f0-cf78-4ffc-8998-f01878224a45",
      "name": "Get dataset items",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        3744,
        816
      ],
      "parameters": {
        "resource": "Datasets",
        "datasetId": "={{ $json.defaultDatasetId }}"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5107bd3a-5ecd-4947-84e9-4435b5b53b50",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3440,
        1040
      ],
      "parameters": {
        "width": 1088,
        "height": 800,
        "content": "# \ud83e\udde0 Who It\u2019s For\n\n## 1-Freelancers and solopreneurs looking for instant job alerts\n\n## 2-Agencies monitoring job boards for leads\n\n## 3-Developers wanting to automate freelance opportunity tracking\n\n# \u2699\ufe0f Requirements\n\n## 1-Apify account (with an active Actor for job scraping)\n\n## 2-WhatsApp API / Twilio setup for message delivery\n\n## 3-Google Sheets account for tracking job logs\n\n## 4-n8n Cloud or self-hosted instance\n\n# \ud83d\udca1 Pro Tip\n\n## You can schedule this workflow to run every few hours using the Cron node \u2014 it will automatically check for new jobs and send alerts even when you\u2019re offline."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "47345b24-2f98-441d-b460-fcde3f1559ca",
  "connections": {
    "Edit Fields1": {
      "main": [
        [
          {
            "node": "Append or update row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run an Actor": {
      "main": [
        [
          {
            "node": "Get dataset items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get dataset items": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Edit Fields1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Run an Actor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append or update row in sheet1": {
      "main": [
        [
          {
            "node": "Edit Fields To send Specific Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields To send Specific Data": {
      "main": [
        [
          {
            "node": "Send message",
            "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

Upwork Job Alert workflow. Uses whatsApp, @apify/n8n-nodes-apify, googleSheets, chatTrigger. Chat trigger; 11 nodes.

Source: https://github.com/zengfr/n8n-workflow-all-templates/blob/6a3e60251e39ea8c87e061d82f52633e5d0debe6/n8n-workflow-all-templates/00/00/99/9941_Track_freelance_jobs_from_Apify_and_get_instant_WhatsApp_alerts_for_new_leads.json — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

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

Marketing & Ads

It acts as a powerful scraping agent that takes a simple chat query, scours both Google Search and Google Maps for relevant businesses, scrapes their websites for contact details, and compiles an enri

Chat Trigger, Google Sheets, HTTP Request
Marketing & Ads

Master Social Scraper (Google Sheets). Uses chatTrigger, textClassifier, lmChatOpenAi, httpRequest. Chat trigger; 36 nodes.

Chat Trigger, Text Classifier, OpenAI Chat +4
Marketing & Ads

This workflow acts as an instant SDR that replies to new inbound leads across multiple channels in real time. It first captures and normalizes all incoming lead data into a unified structure. The work

Google Sheets, HTTP Request, Gmail +1
Marketing & Ads

This workflow runs manually or on a schedule to pull search queries and excluded domains from Google Sheets, launches Apify’s Link Prospecting Tool, then uses an Apify “run succeeded” webhook to fetch

Google Sheets, @Apify/N8N Nodes Apify
Marketing & Ads

What Native n8n chat-operated AI employee for a single wellness SaaS brand Handles three intents: send campaign, report campaign, reactivate cold subscribers

Chat Trigger, OpenRouter Chat, Agent +4