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 →
{
"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.
anthropicApigoogleApigoogleSheetsOAuth2ApilinkedInOAuth2Api
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
⏺ 🚀 How it works
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
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
Faceless YouTube Generator. Uses httpRequest, limit, googleDrive, googleSheets. Webhook trigger; 49 nodes.
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