AutomationFlowsAI & RAG › Job Post to Sales Lead Pipeline with Scrape.do, Apollo.io & Openai

Job Post to Sales Lead Pipeline with Scrape.do, Apollo.io & Openai

ByOnur @onurpolat05 on n8n.io

This n8n workflow automates the complete lead generation process by scraping job postings from Indeed, enriching company data via Apollo.io, identifying decision-makers, and generating personalized LinkedIn outreach messages using OpenAI. It integrates with Scrape.do for…

Event trigger★★★★☆ complexityAI-powered18 nodesForm TriggerHTTP RequestGoogle SheetsOpenAI
AI & RAG Trigger: Event Nodes: 18 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Form Trigger → 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
{
  "nodes": [
    {
      "id": "723a8fe4-824f-4a45-932b-3b31e246d34b",
      "name": "\ud83c\udfaf Input Options",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 392,
        "height": 464,
        "content": "## How it works\nThis workflow automates the lead sourcing process by scraping job listings from Indeed using Scrape.do. It enriches company data and finds decision-makers (e.g., CTOs, Founders) via Apollo.io. Finally, it uses OpenAI to generate personalized LinkedIn connection requests and saves all qualified leads to Google Sheets.\n\n## Setup steps\n1. **Credentials:** Configure your credentials for Scrape.do, Apollo.io, OpenAI, and Google Sheets.\n2. **Google Sheets:** Create a new sheet with two tabs named `Companies` and `Leads`.\n3. **Configuration:** Update the \"Set Search Parameters\" node with your target Job Title, Location, and search freshness (days).\n4. **Run:** Click \"Execute Workflow\" or use the Form URL to start the pipeline."
      },
      "typeVersion": 1
    },
    {
      "id": "5c1491b4-1896-4c1d-9afd-dda5caf9d4fe",
      "name": "\ud83d\udd0d Scrape.do Details",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        432
      ],
      "parameters": {
        "color": 2,
        "width": 1096,
        "height": 576,
        "content": "## 1. Job Scraping\nAccepts search criteria via Form or Manual trigger, fetches job postings from Indeed via Scrape.do, and parses the markdown output."
      },
      "typeVersion": 1
    },
    {
      "id": "d6064e7b-e510-4cad-83c9-77d90f9e151f",
      "name": "\ud83c\udfe2 Apollo Org Search",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        432
      ],
      "parameters": {
        "color": 3,
        "width": 1176,
        "height": 576,
        "content": "## 2. Data Enrichment\nLogs companies to Sheets to avoid duplicates, then uses Apollo.io to fetch detailed organization data and find key decision-makers."
      },
      "typeVersion": 1
    },
    {
      "id": "ddbf64fe-aff4-47a2-8771-f1eb2055f899",
      "name": "\ud83d\udc65 Apollo People",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3008,
        432
      ],
      "parameters": {
        "color": 5,
        "width": 1128,
        "height": 576,
        "content": "## 3. Personalization & Output\nFormats the lead data, uses OpenAI to write a custom LinkedIn connection message based on the job context, and saves the final lead list to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "ae5cd22b-868d-4ac1-9044-0eaff387b494",
      "name": "\ud83d\udd27 Troubleshooting",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4192,
        736
      ],
      "parameters": {
        "width": 424,
        "height": 256,
        "content": "# \ud83d\udd27 Troubleshooting\n\n- **Apollo error:** companyName may be empty\n- **No credentials:** Select credential in node\n- **Empty results:** Check Scrape.do output\n- **Rate limit:** Add Wait node\n\n\u2705 Test each node individually"
      },
      "typeVersion": 1
    },
    {
      "id": "28901e2c-cd7e-4adc-a7e0-9301c95fe370",
      "name": "Form Trigger (Optional)",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        560,
        832
      ],
      "parameters": {
        "options": {},
        "formTitle": "Indeed Job Search Configuration",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Job Title / Keywords",
              "placeholder": "web scraping, data engineer, python developer",
              "requiredField": true
            },
            {
              "fieldLabel": "Location",
              "placeholder": "United States, Remote, New York"
            },
            {
              "fieldType": "number",
              "fieldLabel": "Days Posted (1-30)",
              "placeholder": "14"
            }
          ]
        },
        "formDescription": "Enter your search criteria to find job postings and generate leads."
      },
      "typeVersion": 2.2
    },
    {
      "id": "87345ccf-303c-46fb-a1b4-b71861163ab7",
      "name": "Set Search Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        864,
        784
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "job-title",
              "name": "jobTitle",
              "type": "string",
              "value": "={{ $json['Job Title / Keywords'] || 'web scraping' }}"
            },
            {
              "id": "location",
              "name": "location",
              "type": "string",
              "value": "={{ $json['Location'] || 'United States' }}"
            },
            {
              "id": "days-posted",
              "name": "daysPosted",
              "type": "number",
              "value": "={{ $json['Days Posted (1-30)'] || 14 }}"
            },
            {
              "id": "indeed-url",
              "name": "indeedUrl",
              "type": "string",
              "value": "=https://www.indeed.com/jobs?q={{ encodeURIComponent($json['Job Title / Keywords'] || 'web scraping') }}&l={{ encodeURIComponent($json['Location'] || 'United States') }}&fromage={{ $json['Days Posted (1-30)'] || 14 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "091e1c17-98ab-406c-af3d-a887b77c92f2",
      "name": "Scrape.do Indeed API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1152,
        784
      ],
      "parameters": {
        "url": "https://api.scrape.do",
        "options": {
          "timeout": 60000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $json.indeedUrl }}"
            },
            {
              "name": "super",
              "value": "true"
            },
            {
              "name": "geoCode",
              "value": "us"
            },
            {
              "name": "render",
              "value": "true"
            },
            {
              "name": "blockResources",
              "value": "true"
            },
            {
              "name": "device",
              "value": "mobile"
            },
            {
              "name": "output",
              "value": "markdown"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "5261333a-c6fd-4c99-8f7d-a58ec8b75b8e",
      "name": "Parse Indeed Jobs",
      "type": "n8n-nodes-base.code",
      "position": [
        1504,
        784
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst markdown = input.data || input.body || (typeof input === 'string' ? input : JSON.stringify(input));\nconst today = new Date().toISOString().split('T')[0];\n\nconst jobs = [];\nconst lines = String(markdown).split('\\n');\n\nconst stopMarkers = ['People also searched', 'About these companies', 'Related to this search', 'Companies and locations', 'Jobs and locations', 'Salaries-', 'Resume Resources', 'Employer Resources'];\n\nlet currentJob = null;\nlet lineAfterTitle = 0;\n\nfor (let i = 0; i < lines.length; i++) {\n  const line = lines[i].trim();\n  \n  if (stopMarkers.some(marker => line.includes(marker))) {\n    break;\n  }\n  \n  const jobMatch = line.match(/^-?\\s*##\\s*\\[(.+?)\\]\\((https?:\\/\\/[^)]*viewjob\\?jk=([a-zA-Z0-9]+)[^)]*)\\)/);\n  \n  if (jobMatch) {\n    if (currentJob && currentJob.companyName) {\n      jobs.push({...currentJob});\n    }\n    \n    currentJob = {\n      jobTitle: jobMatch[1].trim(),\n      jobUrl: jobMatch[2].trim(),\n      jobId: jobMatch[3],\n      companyName: '',\n      location: '',\n      salary: '',\n      jobType: '',\n      source: 'Indeed',\n      dateFound: today\n    };\n    lineAfterTitle = 0;\n    continue;\n  }\n  \n  if (currentJob) {\n    if (!line || line === '-' || line.startsWith('![') || line.startsWith('- Title:')) continue;\n    if (line.includes('Company logo') || line.includes('cloudfront.net')) continue;\n    if (line === 'New' || line.includes('Often responds') || line === 'Easily apply' || line.includes('Transit information')) continue;\n    \n    lineAfterTitle++;\n    \n    if (line.startsWith('$') || line.match(/^\\$[\\d,]+/)) {\n      currentJob.salary = line;\n      continue;\n    }\n    \n    if (line.includes('Pay information not provided')) {\n      currentJob.salary = 'Not provided';\n      continue;\n    }\n    \n    if (line.match(/^(Full-time|Part-time|Contract|Temporary|Internship)$/i)) {\n      currentJob.jobType = line;\n      continue;\n    }\n    \n    if (line.match(/^(401\\(k\\)|Health insurance|Paid time off|Vision|Dental|Tuition|Employee discount|Paid parental)/i)) continue;\n    if (line.match(/hours per week|Monday to Friday|Day shift|Weekends/i)) continue;\n    \n    const locationMatch = line.match(/^(Remote in )?([A-Z][a-zA-Z\\s]+),\\s*([A-Z]{2})(\\s+\\d{5})?$/);\n    if (locationMatch) {\n      currentJob.location = line;\n      continue;\n    }\n    \n    if (line === 'Remote') {\n      currentJob.location = 'Remote';\n      continue;\n    }\n    \n    if (!currentJob.companyName && lineAfterTitle <= 5) {\n      if (!line.startsWith('[') && !line.startsWith('http') && line.length > 1 && line.length < 100) {\n        if (!line.includes('...') && !line.match(/experience|looking for|develop|collaborate|work with/i)) {\n          currentJob.companyName = line;\n          continue;\n        }\n      }\n    }\n  }\n}\n\nif (currentJob && currentJob.companyName) {\n  jobs.push(currentJob);\n}\n\nconst validJobs = jobs.filter(job => {\n  if (!job.companyName || job.companyName.length < 2) return false;\n  if (job.companyName.includes('chevron') || job.companyName.includes('Title:')) return false;\n  return true;\n});\n\nconst seen = new Set();\nconst uniqueJobs = validJobs.filter(job => {\n  const key = job.companyName.toLowerCase().trim();\n  if (seen.has(key)) return false;\n  seen.add(key);\n  return true;\n});\n\nif (uniqueJobs.length === 0) {\n  return [];\n}\n\nreturn uniqueJobs.map(job => ({ json: job }));"
      },
      "typeVersion": 2,
      "alwaysOutputData": false
    },
    {
      "id": "9c7f51f0-55f2-41b2-9e24-1422422f2ca2",
      "name": "Add New Company",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1824,
        784
      ],
      "parameters": {
        "columns": {
          "value": {
            "jobUrl": "={{ $json.jobUrl }}",
            "salary": "={{ $json.salary }}",
            "source": "={{ $json.source }}",
            "jobTitle": "={{ $json.jobTitle }}",
            "location": "={{ $json.location }}",
            "dateFound": "={{ $json.dateFound }}",
            "companyName": "={{ $json.companyName }}"
          },
          "schema": [
            {
              "id": "jobTitle",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "jobTitle",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "jobUrl",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "jobUrl",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "companyName",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "companyName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "salary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "salary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "postedAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "postedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "dateFound",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "dateFound",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1GCrag7CXehEs_BNKMv0Y4ihTeq7J2oMd-TYSLkXxL_U/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1GCrag7CXehEs_BNKMv0Y4ihTeq7J2oMd-TYSLkXxL_U",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1GCrag7CXehEs_BNKMv0Y4ihTeq7J2oMd-TYSLkXxL_U/edit?usp=drivesdk",
          "cachedResultName": "New Company"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "27a365b9-0ef9-475e-9c10-eb9edebe19b3",
      "name": "Apollo Organization Search",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2160,
        784
      ],
      "parameters": {
        "url": "https://api.apollo.io/v1/organizations/search",
        "method": "POST",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        },
        "jsonBody": "={\n  \"q_organization_name\": \"{{ $json.companyName }}\",\n  \"page\": 1,\n  \"per_page\": 1\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e8e1e95a-d11d-4591-933d-8c16467225c4",
      "name": "Extract Apollo Org Data",
      "type": "n8n-nodes-base.code",
      "position": [
        2528,
        784
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst results = items.map((item, index) => {\n  const response = item.json;\n  const body = response.body || response;\n  const organizations = body.organizations || [];\n  const org = organizations[0] || {};\n\n  let originalData = {};\n  try {\n    originalData = $('Add New Company').item(index).json;\n  } catch (e) {\n    originalData = {};\n  }\n\n  return {\n    json: {\n      companyName: originalData.companyName || '',\n      jobTitle: originalData.jobTitle || '',\n      jobUrl: originalData.jobUrl || '',\n      location: originalData.location || '',\n      dateFound: originalData.dateFound || '',\n      linkedinUrl: org.linkedin_url || null,\n      organizationId: org.id || null,\n      apolloOrganizationName: org.name || null,\n      websiteUrl: org.website_url || org.primary_domain || null,\n      industry: org.industry || null,\n      employeeCount: org.estimated_num_employees || null,\n      foundedYear: org.founded_year || null,\n      city: org.city || null,\n      state: org.state || null,\n      country: org.country || null,\n      description: org.short_description || null,\n      apolloEnriched: !!org.id,\n      enrichmentTimestamp: new Date().toISOString()\n    }\n  };\n});\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "2a98ba5c-f9a5-41a2-bc04-d42e6035dd35",
      "name": "Apollo People Search",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2832,
        784
      ],
      "parameters": {
        "url": "https://api.apollo.io/v1/mixed_people/search",
        "method": "POST",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        },
        "jsonBody": "={\n  \"organization_ids\": [\"{{ $json.organizationId }}\"],\n  \"person_titles\": [\"CTO\", \"Chief Technology Officer\", \"VP Engineering\", \"Head of Engineering\", \"Engineering Manager\", \"Technical Director\", \"CEO\", \"Founder\"],\n  \"page\": 1,\n  \"per_page\": 3\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "74407d73-6082-4708-9e66-3f7b41219e1f",
      "name": "Format Leads",
      "type": "n8n-nodes-base.code",
      "position": [
        3072,
        784
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nconst allLeads = [];\n\nitems.forEach((item, index) => {\n  const response = item.json;\n  const body = response.body || response;\n  const people = body.people || [];\n\n  if (people.length === 0) return;\n\n  let companyData = {};\n  try {\n    companyData = $('Extract Apollo Org Data').item(index).json;\n  } catch (e) {\n    companyData = {};\n  }\n\n  people.forEach(person => {\n    allLeads.push({\n      json: {\n        firstName: person.first_name || '',\n        lastName: person.last_name || '',\n        fullName: person.name || (person.first_name + ' ' + person.last_name).trim(),\n        title: person.title || person.headline || '',\n        email: person.email || '',\n        phone: person.phone_number || '',\n        linkedinUrl: person.linkedin_url || '',\n        companyName: companyData.companyName || companyData.apolloOrganizationName || '',\n        companyWebsite: companyData.websiteUrl || '',\n        companyLinkedIn: companyData.linkedinUrl || '',\n        country: companyData.country || person.country || '',\n        city: person.city || companyData.city || '',\n        industry: companyData.industry || '',\n        jobTitle: companyData.jobTitle || '',\n        jobUrl: companyData.jobUrl || '',\n        status: 'New',\n        dateAdded: new Date().toISOString().split('T')[0],\n        source: 'Indeed + Apollo',\n        apolloPersonId: person.id || ''\n      }\n    });\n  });\n});\n\nif (allLeads.length === 0) return [];\nreturn allLeads;"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "4b069297-0707-436d-9fbb-725e2b8e8c49",
      "name": "Generate Personalized Message",
      "type": "n8n-nodes-base.openAi",
      "position": [
        3408,
        784
      ],
      "parameters": {
        "prompt": {
          "messages": [
            {
              "role": "system",
              "content": "You are a professional outreach specialist. Write personalized LinkedIn connection request messages. Keep messages under 300 characters. Be friendly, professional, and mention a specific reason for connecting based on their role and company. Do not use generic templates. Write in English."
            },
            {
              "content": "=Write a personalized LinkedIn connection request message for:\n\nName: {{ $json.fullName }}\nTitle: {{ $json.title }}\nCompany: {{ $json.companyName }}\nIndustry: {{ $json.industry }}\nJob Posting Context: They are hiring for {{ $json.jobTitle }}\n\nMention that I noticed they are expanding their data/scraping team and I would love to connect to share insights about web scraping solutions."
            }
          ]
        },
        "options": {
          "maxTokens": 150,
          "temperature": 0.7
        },
        "resource": "chat",
        "requestOptions": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "01e00970-f643-4ffb-b9d4-18bd4b83a961",
      "name": "Merge Lead + Message",
      "type": "n8n-nodes-base.code",
      "position": [
        3712,
        784
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nreturn items.map((item, index) => {\n  const openAiResponse = item.json;\n  \n  let personalizedMessage = '';\n  if (openAiResponse.message && openAiResponse.message.content) {\n    personalizedMessage = openAiResponse.message.content;\n  } else if (openAiResponse.choices && openAiResponse.choices[0] && openAiResponse.choices[0].message) {\n    personalizedMessage = openAiResponse.choices[0].message.content;\n  } else if (typeof openAiResponse === 'string') {\n    personalizedMessage = openAiResponse;\n  }\n  \n  let leadData = {};\n  try {\n    leadData = $('Format Leads').item(index).json;\n  } catch (e) {\n    leadData = {};\n  }\n  \n  return {\n    json: {\n      firstName: leadData.firstName || '',\n      lastName: leadData.lastName || '',\n      fullName: leadData.fullName || '',\n      title: leadData.title || '',\n      email: leadData.email || '',\n      linkedinUrl: leadData.linkedinUrl || '',\n      companyName: leadData.companyName || '',\n      country: leadData.country || '',\n      city: leadData.city || '',\n      industry: leadData.industry || '',\n      dateAdded: leadData.dateAdded || '',\n      source: leadData.source || '',\n      personalizedMessage: personalizedMessage.trim(),\n      messageGeneratedAt: new Date().toISOString()\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "0428310e-637c-430d-bb0d-f33e0293b0c7",
      "name": "Save Leads to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3936,
        784
      ],
      "parameters": {
        "columns": {
          "value": {
            "Title": "={{ $json.title }}",
            "Source": "={{ $json.source }}",
            "Company": "={{ $json.companyName }}",
            "Country": "={{ $json.country }}",
            "Industry": "={{ $json.industry }}",
            "Last Name": "={{ $json.lastName }}",
            "Date Added": "={{ $json.dateAdded }}",
            "First Name": "={{ $json.firstName }}",
            "LinkedIn URL": "={{ $json.linkedinUrl }}",
            "Personalized Message": "={{ $json.personalizedMessage }}"
          },
          "schema": [
            {
              "id": "First Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "First Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Company",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "LinkedIn URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "LinkedIn URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Country",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Country",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Industry",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Industry",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date Added",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date Added",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Personalized Message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Personalized Message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1070709009,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1I42mxlJ_vJhigbnOK4OiSu09waldc-ggo78TJum-tlo/edit#gid=1070709009",
          "cachedResultName": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1I42mxlJ_vJhigbnOK4OiSu09waldc-ggo78TJum-tlo",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1I42mxlJ_vJhigbnOK4OiSu09waldc-ggo78TJum-tlo/edit?usp=drivesdk",
          "cachedResultName": "read existing"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "ed5a727c-d38e-4f58-bfeb-dcbe6134cdda",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        560,
        624
      ],
      "parameters": {},
      "typeVersion": 1
    }
  ],
  "connections": {
    "Format Leads": {
      "main": [
        [
          {
            "node": "Generate Personalized Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Set Search Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add New Company": {
      "main": [
        [
          {
            "node": "Apollo Organization Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Indeed Jobs": {
      "main": [
        [
          {
            "node": "Add New Company",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apollo People Search": {
      "main": [
        [
          {
            "node": "Format Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Lead + Message": {
      "main": [
        [
          {
            "node": "Save Leads to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape.do Indeed API": {
      "main": [
        [
          {
            "node": "Parse Indeed Jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Search Parameters": {
      "main": [
        [
          {
            "node": "Scrape.do Indeed API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Apollo Org Data": {
      "main": [
        [
          {
            "node": "Apollo People Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Form Trigger (Optional)": {
      "main": [
        [
          {
            "node": "Set Search Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apollo Organization Search": {
      "main": [
        [
          {
            "node": "Extract Apollo Org Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Personalized Message": {
      "main": [
        [
          {
            "node": "Merge Lead + 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

This n8n workflow automates the complete lead generation process by scraping job postings from Indeed, enriching company data via Apollo.io, identifying decision-makers, and generating personalized LinkedIn outreach messages using OpenAI. It integrates with Scrape.do for…

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

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Note: Now includes an Apify alternative for Rapid API (Some users can't create new accounts on Rapid API, so I have added an alternative for you. But immediately you are able to get access to Rapid AP

Form Trigger, Google Sheets Trigger, OpenAI +2
AI & RAG

This system automates LinkedIn lead generation and enrichment in six clear stages: Lead Collection (via Apollo.io) Automatically pulls leads based on keywords, roles, or industries using Apollo’s API.

Form Trigger, OpenAI, Google Sheets Trigger +2
AI & RAG

This workflow turns a user-submitted form with country or animal names into a cinematic video with animated scenes and immersive ambient audio. Using GPT-4 for prompt generation, Dumpling AI for visua

Form Trigger, OpenAI, HTTP Request +2
AI & RAG

Automatically generates, designs, stores, and logs complete Instagram carousel posts. It transforms a simple text prompt into a full post with copy, visuals, rendered images, Google Drive storage, and

Google Drive, Form Trigger, OpenAI +3
AI & RAG

This workflow automates the process of finding highly relevant job listings based on a user’s resume, career preferences, and custom filters. It scrapes fresh job data, evaluates relevance using OpenA

Google Sheets, HTTP Request, Form Trigger +1