AutomationFlowsAI & RAG › Claude AI LinkedIn Job Search & Applications

Claude AI LinkedIn Job Search & Applications

Original n8n title: Automate Linkedin Job Search and Applications with Claude AI and Google Sheets

ByOneclick AI Squad @oneclick-ai on n8n.io

This AI-powered workflow automatically searches LinkedIn for relevant jobs, scores them using Claude AI based on your profile, sends personalized applications or connection requests, and logs everything to a Google Sheet for tracking. Trigger - Runs on a schedule or via webhook

Webhook trigger★★★★☆ complexityAI-powered22 nodesHTTP RequestGoogle SheetsAgentAnthropic Chat
AI & RAG Trigger: Webhook Nodes: 22 Complexity: ★★★★☆ AI nodes: yes Added:
Claude AI LinkedIn Job Search & Applications — n8n workflow card showing HTTP Request, Google Sheets, Agent integration

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

This workflow follows the Agent → 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": "22HogRsAuRyWszhC",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "LinkedIn Job Search Automation with Claude AI",
  "tags": [],
  "nodes": [
    {
      "id": "98cfe668-e941-41b0-81a9-9adf9effedc8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -112
      ],
      "parameters": {
        "width": 760,
        "height": 1100,
        "content": "## LinkedIn Job Search Automation with Claude AI\n\nThis AI-powered workflow automatically searches LinkedIn for relevant jobs, scores them using Claude AI based on your profile, sends personalized applications or connection requests, and logs everything to a Google Sheet for tracking.\n\n### How it works\n\n1. **Trigger** - Runs on a schedule or via webhook to start a new job search\n2. **Search LinkedIn** - Fetches job listings based on keywords, location, and filters\n3. **Filter & Deduplicate** - Removes already-applied or seen jobs\n4. **Analyze with Claude AI** - Scores each job against your resume/profile\n5. **Decision Gate** - Only proceeds with jobs above your score threshold\n6. **Apply or Connect** - Sends Easy Apply or connection request to recruiter\n7. **Log Results** - Records all actions in Google Sheets for tracking\n\n### Setup Steps\n\n1. Import this workflow into your n8n instance\n2. Configure credentials:\n   - **LinkedIn OAuth2** - LinkedIn Developer Portal\n   - **Anthropic API** - For Claude AI job scoring\n   - **Google Sheets** - To track applications\n3. Update your profile/resume text in the `Build Search Context` node\n4. Set your job keywords and location preferences\n5. Activate the workflow\n\n### Sample Trigger Payload\n```json\n{\n  \"keywords\": \"Product Manager\",\n  \"location\": \"Bangalore, India\",\n  \"experienceLevel\": \"mid-senior\",\n  \"jobType\": \"full-time\",\n  \"scoreThreshold\": 70\n}\n```\n\n### Features\n\n- **AI-powered job scoring** based on your skills and experience\n- **Duplicate prevention** - tracks seen and applied jobs\n- **Auto Easy Apply** for matching jobs\n- **Recruiter outreach** with personalized messages\n- **Full audit log** in Google Sheets"
      },
      "typeVersion": 1
    },
    {
      "id": "dc1eda1a-5166-4963-abbf-c1ba32330c2e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        348,
        296
      ],
      "parameters": {
        "color": 4,
        "width": 456,
        "height": 328,
        "content": "## 1. Trigger & Input Validation"
      },
      "typeVersion": 1
    },
    {
      "id": "82414155-40a9-4cf6-97b2-a25f19d334a9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        844,
        -60
      ],
      "parameters": {
        "color": 4,
        "width": 808,
        "height": 684,
        "content": "## 2. Fetch & Filter Jobs"
      },
      "typeVersion": 1
    },
    {
      "id": "e02d5cdb-6bab-463a-a56e-8b5a390cd04e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        320
      ],
      "parameters": {
        "color": 4,
        "width": 712,
        "height": 284,
        "content": "## 3. AI Scoring & Decision"
      },
      "typeVersion": 1
    },
    {
      "id": "b9260824-9aa7-40fa-bd3b-e1f4efd6b841",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2480,
        208
      ],
      "parameters": {
        "color": 4,
        "width": 1200,
        "height": 492,
        "content": "## 4. Apply, Outreach & Log"
      },
      "typeVersion": 1
    },
    {
      "id": "496796ff-6f97-4271-9140-5123c088f695",
      "name": "Receive Job Search Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        416,
        464
      ],
      "parameters": {
        "path": "linkedin-job-search",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "9410eb78-deb5-46bf-80fb-9e5da83fa6dc",
      "name": "Validate Input and Build Search Params",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        464
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Extract search parameters from request\nconst body = $input.item.json.body || $input.item.json;\n\n// Required fields\nconst required = ['keywords', 'location'];\nconst missing = required.filter(f => !body[f]);\nif (missing.length > 0) {\n  throw new Error(`Missing required fields: ${missing.join(', ')}`);\n}\n\n// Default values and normalization\nconst searchParams = {\n  keywords: body.keywords.trim(),\n  location: body.location.trim(),\n  experienceLevel: body.experienceLevel || 'mid-senior',\n  jobType: body.jobType || 'full-time',\n  datePosted: body.datePosted || 'past-week',\n  remote: body.remote || false,\n  scoreThreshold: parseInt(body.scoreThreshold) || 70,\n  maxApplications: parseInt(body.maxApplications) || 10,\n  sendConnectionRequest: Boolean(body.sendConnectionRequest),\n  easyApplyOnly: Boolean(body.easyApplyOnly !== false)\n};\n\n// Candidate profile (customize with your own details)\nconst candidateProfile = {\n  name: body.candidateName || 'YOUR_NAME',\n  currentTitle: body.currentTitle || 'YOUR_CURRENT_TITLE',\n  yearsExperience: body.yearsExperience || 5,\n  skills: body.skills || ['JavaScript', 'Python', 'Product Management', 'Data Analysis', 'Agile'],\n  education: body.education || 'B.Tech Computer Science',\n  summary: body.profileSummary || 'Experienced professional seeking new opportunities in the tech industry.'\n};\n\n// Experience level mapping to LinkedIn API codes\nconst expLevelMap = {\n  'internship': '1',\n  'entry': '2',\n  'associate': '3',\n  'mid-senior': '4',\n  'director': '5',\n  'executive': '6'\n};\n\n// Job type mapping\nconst jobTypeMap = {\n  'full-time': 'F',\n  'part-time': 'P',\n  'contract': 'C',\n  'temporary': 'T',\n  'internship': 'I',\n  'volunteer': 'V'\n};\n\nreturn {\n  json: {\n    searchParams,\n    candidateProfile,\n    linkedInFilters: {\n      f_E: expLevelMap[searchParams.experienceLevel] || '4',\n      f_JT: jobTypeMap[searchParams.jobType] || 'F',\n      f_TPR: 'r604800',\n      f_LF: searchParams.remote ? '2' : undefined,\n      f_EA: searchParams.easyApplyOnly ? 'true' : undefined\n    },\n    metadata: {\n      requestId: `LJSR-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n      startedAt: new Date().toISOString(),\n      applicationsCount: 0\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "7af17870-28d8-410f-b0ce-e04e4ca72ac1",
      "name": "Fetch LinkedIn Job Listings",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        864,
        272
      ],
      "parameters": {
        "url": "https://api.linkedin.com/v2/jobSearch",
        "options": {
          "timeout": 15000
        },
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "keywords",
              "value": "={{ $json.searchParams.keywords }}"
            },
            {
              "name": "location",
              "value": "={{ $json.searchParams.location }}"
            },
            {
              "name": "f_E",
              "value": "={{ $json.linkedInFilters.f_E }}"
            },
            {
              "name": "f_JT",
              "value": "={{ $json.linkedInFilters.f_JT }}"
            },
            {
              "name": "f_TPR",
              "value": "={{ $json.linkedInFilters.f_TPR }}"
            },
            {
              "name": "count",
              "value": "25"
            },
            {
              "name": "start",
              "value": "0"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Restli-Protocol-Version",
              "value": "2.0.0"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "linkedInOAuth2Api"
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "a3773374-7fcf-4761-be73-799cc11094f7",
      "name": "Fetch Individual Job Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        864,
        464
      ],
      "parameters": {
        "url": "=https://api.linkedin.com/v2/jobs/{{ $json.jobId }}",
        "options": {
          "timeout": 10000
        },
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Restli-Protocol-Version",
              "value": "2.0.0"
            }
          ]
        },
        "nodeCredentialType": "linkedInOAuth2Api"
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "2db8558d-1baa-4e0f-9ad3-33b719f8a0e3",
      "name": "Parse and Normalize Job Listings",
      "type": "n8n-nodes-base.code",
      "position": [
        1088,
        440
      ],
      "parameters": {
        "jsCode": "// Get raw LinkedIn job response\nconst jobsResponse = $('Fetch LinkedIn Job Listings').first().json;\nconst searchContext = $('Validate Input and Build Search Params').first().json;\n\nconst jobs = [];\n\n// Handle LinkedIn API response structure\nconst rawJobs = jobsResponse.elements || jobsResponse.jobs || jobsResponse.data || [];\n\nfor (const job of rawJobs) {\n  try {\n    const parsed = {\n      jobId: job.entityUrn?.replace('urn:li:jobPosting:', '') || job.id || '',\n      title: job.title || job.jobPostingTitle || 'Unknown Title',\n      companyName: job.companyDetails?.company?.name || job.formattedEmployerName || 'Unknown Company',\n      companyId: job.companyDetails?.company?.entityUrn?.replace('urn:li:company:', '') || '',\n      location: job.formattedLocation || job.workplaceTypes?.[0] || searchContext.searchParams.location,\n      description: job.description?.text || job.jobDescription || '',\n      descriptionSnippet: (job.description?.text || '').substring(0, 500),\n      isEasyApply: Boolean(job.easyApplyEnabled || job.applyMethod?.easyApplyJobApplicationFormCommon),\n      jobUrl: `https://www.linkedin.com/jobs/view/${job.entityUrn?.replace('urn:li:jobPosting:', '') || job.id}/`,\n      postedAt: job.listedAt ? new Date(job.listedAt).toISOString() : new Date().toISOString(),\n      applicantsCount: job.applies || 0,\n      salary: job.salaryInsights?.salaryRange?.min\n        ? `${job.salaryInsights.salaryRange.min}-${job.salaryInsights.salaryRange.max} ${job.salaryInsights.salaryRange.currencyCode}`\n        : 'Not disclosed',\n      skills: job.skills?.map(s => s.name) || [],\n      seniorityLevel: job.expLevelId || searchContext.searchParams.experienceLevel,\n      employmentType: job.employmentStatus || searchContext.searchParams.jobType,\n      remote: job.workplaceTypes?.includes('REMOTE') || false\n    };\n\n    if (parsed.jobId && parsed.title) {\n      jobs.push({ json: { job: parsed, searchContext } });\n    }\n  } catch (err) {\n    console.log('Error parsing job:', err.message);\n  }\n}\n\nif (jobs.length === 0) {\n  throw new Error('No valid job listings found. Check LinkedIn API credentials and search parameters.');\n}\n\nconsole.log(`Parsed ${jobs.length} jobs from LinkedIn`);\nreturn jobs;"
      },
      "typeVersion": 2
    },
    {
      "id": "aedb66a1-564f-4425-a9f0-8e398d474621",
      "name": "Check Already Applied (Google Sheets)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1312,
        440
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "5b625a70-7933-4c0a-8f6e-7ad9f2249d52",
      "name": "Skip Already Seen Jobs",
      "type": "n8n-nodes-base.if",
      "position": [
        1536,
        440
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.length || 0 }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b8080a67-de60-4ec8-a7fc-bd3119b536e4",
      "name": "Score Job with Claude AI",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1760,
        440
      ],
      "parameters": {
        "text": "=You are an expert career coach and resume analyst. Score the following job posting against the candidate profile and return a JSON evaluation.\n\n**Candidate Profile:**\n- Name: {{ $json.searchContext.candidateProfile.name }}\n- Current Title: {{ $json.searchContext.candidateProfile.currentTitle }}\n- Years of Experience: {{ $json.searchContext.candidateProfile.yearsExperience }}\n- Skills: {{ $json.searchContext.candidateProfile.skills.join(', ') }}\n- Education: {{ $json.searchContext.candidateProfile.education }}\n- Summary: {{ $json.searchContext.candidateProfile.summary }}\n\n**Job Posting:**\n- Title: {{ $json.job.title }}\n- Company: {{ $json.job.companyName }}\n- Location: {{ $json.job.location }}\n- Description: {{ $json.job.descriptionSnippet }}\n- Required Skills: {{ $json.job.skills.join(', ') }}\n- Seniority: {{ $json.job.seniorityLevel }}\n- Remote: {{ $json.job.remote }}\n- Salary: {{ $json.job.salary }}\n\n**Scoring Criteria:**\n1. Skills match (0-30 points) - How well candidate skills align with job requirements\n2. Experience level fit (0-25 points) - Years of experience vs role expectations\n3. Title relevance (0-20 points) - How closely current/target title matches\n4. Location/remote compatibility (0-15 points)\n5. Company fit (0-10 points) - Company size, industry, reputation\n\n**Response Format (JSON only, no markdown):**\n{\n  \"totalScore\": 82,\n  \"breakdown\": {\n    \"skillsMatch\": 25,\n    \"experienceFit\": 20,\n    \"titleRelevance\": 18,\n    \"locationFit\": 12,\n    \"companyFit\": 7\n  },\n  \"matchedSkills\": [\"list of matching skills\"],\n  \"missingSkills\": [\"list of skills candidate lacks\"],\n  \"pros\": [\"top reasons this is a good fit\"],\n  \"cons\": [\"main concerns or gaps\"],\n  \"shouldApply\": true,\n  \"coverLetterHook\": \"One compelling opening sentence for a cover letter\",\n  \"connectionMessage\": \"A short personalized LinkedIn connection message (under 300 chars)\"\n}",
        "options": {
          "systemMessage": "You are a career coach that evaluates job-candidate fit and responds in JSON format only. Never include markdown code blocks or additional text outside the JSON."
        },
        "promptType": "define"
      },
      "typeVersion": 1.6
    },
    {
      "id": "32fdfbf9-f7f0-4f47-a93a-b8a03aabbf88",
      "name": "Claude AI Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1832,
        664
      ],
      "parameters": {
        "model": "=claude-sonnet-4-20250514",
        "options": {
          "temperature": 0.3
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "955d64a8-f686-4b5f-8a50-d6bf20621288",
      "name": "Parse AI Score and Decide",
      "type": "n8n-nodes-base.code",
      "position": [
        2112,
        440
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const aiResponse = $input.item.json;\nlet aiText = aiResponse.response || aiResponse.output || aiResponse.text || '';\n\n// Handle content array format from Anthropic\nif (aiResponse.content && Array.isArray(aiResponse.content)) {\n  aiText = aiResponse.content[0]?.text || '';\n}\n\n// Clean JSON from any markdown code blocks\nconst cleanText = aiText\n  .replace(/```json\\s*/g, '')\n  .replace(/```\\s*/g, '')\n  .trim();\n\nlet aiScore;\ntry {\n  aiScore = JSON.parse(cleanText);\n} catch (error) {\n  throw new Error(`Failed to parse AI response: ${error.message}. Response was: ${cleanText}`);\n}\n\n// Pull job and search context from upstream\nconst jobData = $('Skip Already Seen Jobs').item.json;\nconst scoreThreshold = jobData.searchContext?.searchParams?.scoreThreshold || 70;\n\nreturn {\n  json: {\n    job: jobData.job,\n    searchContext: jobData.searchContext,\n    aiScore,\n    scoreThreshold,\n    meetsThreshold: (aiScore.totalScore || 0) >= scoreThreshold,\n    processedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8b09e7f3-9810-4606-bf72-59bf12213427",
      "name": "Check Score Threshold",
      "type": "n8n-nodes-base.if",
      "position": [
        2336,
        440
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.meetsThreshold }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "1ebcd2fe-afc0-415e-91b3-93d0b0c2f7b7",
      "name": "Submit Easy Apply Application",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2560,
        344
      ],
      "parameters": {
        "url": "https://api.linkedin.com/v2/jobs/{{ $json.job.jobId }}/apply",
        "method": "POST",
        "options": {
          "timeout": 15000
        },
        "jsonBody": "={\n  \"jobPostingUrn\": \"urn:li:jobPosting:{{ $json.job.jobId }}\",\n  \"applicationData\": {\n    \"resumeText\": \"{{ $json.searchContext.candidateProfile.summary }}\",\n    \"coverLetter\": \"{{ $json.aiScore.coverLetterHook }} I am excited to apply for the {{ $json.job.title }} position at {{ $json.job.companyName }}.\",\n    \"contactInfo\": {\n      \"name\": \"{{ $json.searchContext.candidateProfile.name }}\"\n    }\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Restli-Protocol-Version",
              "value": "2.0.0"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "linkedInOAuth2Api"
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "1d2c0f66-06f1-45f4-a26f-f0e93ad96246",
      "name": "Send Recruiter Connection Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2784,
        352
      ],
      "parameters": {
        "url": "https://api.linkedin.com/v2/invitations",
        "method": "POST",
        "options": {
          "timeout": 10000
        },
        "jsonBody": "={\n  \"invitee\": {\n    \"com.linkedin.voyager.growth.invitation.InviteeProfile\": {\n      \"profileId\": \"{{ $json.job.companyId }}\"\n    }\n  },\n  \"message\": \"{{ $json.aiScore.connectionMessage }}\",\n  \"trackingId\": \"{{ $json.searchContext.metadata.requestId }}\"\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Restli-Protocol-Version",
              "value": "2.0.0"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "linkedInOAuth2Api"
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "2d335fe0-355b-4d83-a9e6-9ca8a3840a98",
      "name": "Format Applied Job Result",
      "type": "n8n-nodes-base.code",
      "position": [
        3008,
        344
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const jobData = $('Parse AI Score and Decide').item.json;\nconst applyResponse = $('Submit Easy Apply Application').item.json;\nconst connectionResponse = $('Send Recruiter Connection Request').item.json;\n\nconst applicationSuccess = !applyResponse.error && (applyResponse.status === 200 || applyResponse.id);\nconst connectionSuccess = !connectionResponse.error && (connectionResponse.id || connectionResponse.createdAt);\n\nreturn {\n  json: {\n    status: 'APPLIED',\n    jobId: jobData.job.jobId,\n    jobTitle: jobData.job.title,\n    company: jobData.job.companyName,\n    location: jobData.job.location,\n    jobUrl: jobData.job.jobUrl,\n    salary: jobData.job.salary,\n    aiScore: jobData.aiScore.totalScore,\n    matchedSkills: jobData.aiScore.matchedSkills,\n    missingSkills: jobData.aiScore.missingSkills,\n    pros: jobData.aiScore.pros,\n    cons: jobData.aiScore.cons,\n    applicationSubmitted: applicationSuccess,\n    connectionRequestSent: connectionSuccess,\n    appliedAt: new Date().toISOString(),\n    requestId: jobData.searchContext.metadata.requestId\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "7da61876-fc9e-41a6-abad-ee3e0512fcb6",
      "name": "Format Skipped Job Result",
      "type": "n8n-nodes-base.code",
      "position": [
        3008,
        536
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const jobData = $input.item.json;\n\nreturn {\n  json: {\n    status: 'SKIPPED_LOW_SCORE',\n    jobId: jobData.job.jobId,\n    jobTitle: jobData.job.title,\n    company: jobData.job.companyName,\n    location: jobData.job.location,\n    jobUrl: jobData.job.jobUrl,\n    salary: jobData.job.salary,\n    aiScore: jobData.aiScore.totalScore,\n    scoreThreshold: jobData.scoreThreshold,\n    matchedSkills: jobData.aiScore.matchedSkills,\n    missingSkills: jobData.aiScore.missingSkills,\n    reason: `Score ${jobData.aiScore.totalScore} below threshold of ${jobData.scoreThreshold}`,\n    processedAt: new Date().toISOString(),\n    requestId: jobData.searchContext.metadata.requestId\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b9bf9f93-e782-41e1-9816-be4cbcb3b8fa",
      "name": "Log All Results to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3232,
        440
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "="
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "="
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "fe51ad52-a980-4eee-b9d5-4c3bf4da9b7e",
      "name": "Send Summary Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3456,
        440
      ],
      "parameters": {
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json, null, 2) }}"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b9ca1fac-36b1-46a2-ae5e-8996211179a8",
  "connections": {
    "Claude AI Model": {
      "ai_languageModel": [
        [
          {
            "node": "Score Job with Claude AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Check Score Threshold": {
      "main": [
        [
          {
            "node": "Submit Easy Apply Application",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Skipped Job Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip Already Seen Jobs": {
      "main": [
        [
          {
            "node": "Score Job with Claude AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score Job with Claude AI": {
      "main": [
        [
          {
            "node": "Parse AI Score and Decide",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Applied Job Result": {
      "main": [
        [
          {
            "node": "Log All Results to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Skipped Job Result": {
      "main": [
        [
          {
            "node": "Log All Results to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Score and Decide": {
      "main": [
        [
          {
            "node": "Check Score Threshold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Job Search Request": {
      "main": [
        [
          {
            "node": "Validate Input and Build Search Params",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch LinkedIn Job Listings": {
      "main": [
        [
          {
            "node": "Parse and Normalize Job Listings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Easy Apply Application": {
      "main": [
        [
          {
            "node": "Send Recruiter Connection Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log All Results to Google Sheets": {
      "main": [
        [
          {
            "node": "Send Summary Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse and Normalize Job Listings": {
      "main": [
        [
          {
            "node": "Check Already Applied (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Recruiter Connection Request": {
      "main": [
        [
          {
            "node": "Format Applied Job Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Already Applied (Google Sheets)": {
      "main": [
        [
          {
            "node": "Skip Already Seen Jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input and Build Search Params": {
      "main": [
        [
          {
            "node": "Fetch LinkedIn Job Listings",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Individual Job Details",
            "type": "main",
            "index": 0
          },
          {
            "node": "Parse and Normalize Job Listings",
            "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 AI-powered workflow automatically searches LinkedIn for relevant jobs, scores them using Claude AI based on your profile, sends personalized applications or connection requests, and logs everything to a Google Sheet for tracking. Trigger - Runs on a schedule or via webhook…

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

⏺ 🚀 How it works

Agent, Anthropic Chat, Output Parser Structured +6
AI & RAG

Fully automates your service order pipeline from incoming booking to supplier confirmation — with built-in SLA enforcement and automatic escalation if a supplier goes silent. 📥 Receives orders via web

HTTP Request, Google Sheets, Agent +4
AI & RAG

Tired of grinding out YouTube content? This n8n workflow turns AI into your personal video factory—creating engaging, faceless shorts on autopilot. Perfect for creators, marketers, or side-hustlers lo

HTTP Request, Google Drive, Google Sheets +6
AI & RAG

Faceless YouTube Generator. Uses httpRequest, limit, googleDrive, googleSheets. Webhook trigger; 49 nodes.

HTTP Request, Google Drive, Google Sheets +7
AI & RAG

This workflow turns your WhatsApp Business number into a 24/7 AI-powered customer assistant — without any third-party chatbot platform. It receives incoming WhatsApp messages via Evolution API, unders

OpenAI, Information Extractor, Anthropic Chat +7