Linkedin Easy Apply Automation
by @ralyodio
Automate LinkedIn Easy Apply searches and applications with Puppeteer/Chromium, a verified resume PDF, remote/job-title filtering, stateful daily reruns, and...
clawhub install linkedin-easy-apply-automationπ About This Skill
name: linkedin-easy-apply description: Automate LinkedIn Easy Apply searches and applications with Puppeteer/Chromium, a verified resume PDF, remote/job-title filtering, stateful daily reruns, and conservative answer guardrails. when_to_use: Use when you need an AI agent to search LinkedIn jobs and submit LinkedIn Easy Apply applications from a verified resume PDF. license: MIT metadata: supported_agents: - claude-code - openclaw - hermes - codex - cursor - windsurf - goose - aider - roo-code - cline tags: [jobs, linkedin, automation, puppeteer, easy-apply]
LinkedIn Easy Apply Automation
This skill helps an AI coding/operations agent build and run a repeatable LinkedIn Easy Apply workflow.
It is intentionally public and credential-free. It contains no usernames, passwords, cookies, private profile paths, or user-specific secrets.
What it does
Safety rules
Environment variables
RESUME_PDF=/absolute/path/to/resume.pdf
CHROME_PROFILE=$HOME/.cache/linkedin-chrome
STATE_DIR=/tmp/linkedin-easyapply-daily
MAX_SCAN=80
MAX_APPLY=10
DRY_RUN=1
SEARCHES='Claude|OpenAI|Codex|LLM engineer|AI engineer|full stack engineer|software engineer'
LOCATION='United States'
REMOTE_ONLY=1
Puppeteer launch pattern
const puppeteer = require('puppeteer');const browser = await puppeteer.launch({
headless: false,
executablePath: process.env.CHROME_BIN || '/snap/bin/chromium',
userDataDir: process.env.CHROME_PROFILE || ${process.env.HOME}/.cache/linkedin-chrome,
defaultViewport: null,
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--start-maximized']
});
const page = await browser.newPage();
page.setDefaultTimeout(30000);
page.on('dialog', async d => {
try {
if (d.type() === 'beforeunload') await d.accept();
else await d.dismiss();
} catch {}
});
Search workflow
Build LinkedIn Jobs URLs using explicit filters:
f_AL=true for Easy Apply.United States when requested.Keep candidates only when the card/page supports the requested constraints and the title/description matches the target role family.
Direct Easy Apply URL
When a LinkedIn job ID is known, try the direct flow first:
const applyUrl = https://www.linkedin.com/jobs/view/${jobId}/apply/?openSDUIApplyFlow=true;
await page.goto(applyUrl, { waitUntil: 'domcontentloaded', timeout: 60000 });
If the modal does not open, fall back to clicking visible Easy Apply controls across buttons and links.
Conservative answer rules
Answer only facts that are verified by the resume, profile, or explicit operator instruction:
Skip:
Multi-step apply loop
1. Open the apply flow.
2. Detect already-submitted applications.
3. Upload/select the verified resume PDF if needed.
4. Inspect each step's visible inputs/selects/radios.
5. Fill only safe verified answers.
6. Click Next, Review, then Submit application only when no unknown required fields remain.
7. Log submitted/skipped state.
Suggested state
{
"seen": {},
"applied": {},
"skipped": {},
"alreadySubmitted": {}
}
Write state and logs to:
/tmp/linkedin-easyapply-daily/state.json
/tmp/linkedin-easyapply-daily/results.jsonl
Reporting
Report concise results:
Submitted:
Title β Company β URL Skipped:
Title β Company β URL β reason State: /tmp/linkedin-easyapply-daily/state.json
Log: /tmp/linkedin-easyapply-daily/results.jsonl
Pitfalls
United States or comfortable as approval.