Skip to content

Instantly share code, notes, and snippets.

@ralyodio
Last active April 30, 2026 06:56
Show Gist options
  • Select an option

  • Save ralyodio/a389c527a80ee6d1fdf935564d80124a to your computer and use it in GitHub Desktop.

Select an option

Save ralyodio/a389c527a80ee6d1fdf935564d80124a to your computer and use it in GitHub Desktop.
Public Easy Apply automation skills for Dice and LinkedIn
name dice-easy-apply
description Automate Dice.com Easy Apply searches and applications with Puppeteer/Chromium, resume and cover-letter uploads, remote-role filtering, and conservative application guardrails.
when_to_use Use when you need an AI agent to search Dice.com jobs and submit Dice Easy Apply applications from a verified resume and cover letter.
license MIT
metadata
supported_agents tags
claude-code
openclaw
hermes
codex
cursor
windsurf
goose
aider
roo-code
cline
jobs
dice
automation
puppeteer
easy-apply

Dice Easy Apply Automation

This skill helps an AI coding/operations agent build and run a repeatable Dice.com 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

  • Searches Dice jobs using the explicit Remote workplace filter.
  • Focuses on software, web, full-stack, frontend/backend, AI, GenAI, LLM, Claude/OpenAI/Codex-style roles.
  • Uses Dice in-site Easy Apply flows only, unless the operator explicitly approves external ATS applications.
  • Uploads a verified resume PDF and optional cover-letter PDF.
  • Uses a persistent Chromium profile so login can be performed manually once and reused safely.
  • Keeps state/log files so daily reruns avoid duplicates.
  • Skips roles with explicit onsite/hybrid/local/travel/clearance constraints or unknown required questions.

Safety rules

  • Do not store job-board credentials in scripts, skills, memory, logs, or reports.
  • Pass credentials only via one-off environment variables if absolutely necessary, or use a pre-authenticated browser profile.
  • Stop for CAPTCHA, MFA, suspicious-login checks, identity verification, or account-security prompts.
  • Do not fabricate answers. Skip forms requiring salary expectations, essays, custom cover letters, relocation preferences, travel, or unverifiable facts.
  • Treat Dice match percentages as advisory only. Do not skip a role solely because Dice reports a low match score if the role title is inside the resume's wheelhouse.
  • Gen AI / Generative AI Engineer should be treated as a software-engineering role when the resume supports web/software/AI work.

Recommended search URL

Use Dice's remote filter directly, not a radius search:

https://www.dice.com/jobs?filters.workplaceTypes=Remote&filters.easyApply=true&q=<QUERY>

For contract/direct-hire filtered searches, add Dice's employment and employer filters:

https://www.dice.com/jobs?filters.easyApply=true&filters.employmentType=CONTRACTS&filters.employerType=Direct+Hire&filters.workplaceTypes=Remote&q=<QUERY>

Useful query set:

gen ai engineer
generative ai engineer
llm engineer
ai full stack engineer
frontend ai engineer
web developer
full stack engineer
node react engineer
javascript engineer
typescript engineer
react developer
node.js developer
svelte developer
software engineer

Environment variables

RESUME_PDF=/absolute/path/to/resume.pdf
COVER_PDF=/absolute/path/to/cover.pdf
CHROME_PROFILE=$HOME/.cache/dice-chrome
STATE_DIR=/tmp/dice-easyapply-daily
MAX_SCAN=120
MAX_APPLY=15
DRY_RUN=1
SEARCHES='gen ai engineer|llm engineer|full stack engineer|react developer'
EMPLOYMENT_FILTER=CONTRACTS
EMPLOYER_TYPE='Direct Hire'

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/dice-chrome`,
  defaultViewport: null,
  args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--start-maximized']
});

let 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 {}
});

Core workflow

  1. Verify local files exist:
test -f "$RESUME_PDF"
test -f "$COVER_PDF"
  1. Open Dice with a persistent browser profile and verify login.
  2. Search remote Easy Apply roles using the query list.
  3. Extract Dice job IDs from /job-detail/<id> URLs.
  4. Open each job detail page and inspect only the main job description, not footer/recommended-job/sidebar text.
  5. Skip explicit onsite/hybrid/local/travel/clearance constraints.
  6. Open the wizard:
https://www.dice.com/job-applications/<job-id>/wizard
  1. Replace any stale/default resume with the verified resume PDF.
  2. Upload the cover-letter PDF where Dice supports it.
  3. Continue to the review screen.
  4. Confirm expected filenames and work authorization are visible.
  5. Submit only if no unknown required questions remain.
  6. Append a JSONL audit row and save state.

Suggested state

{
  "seen": {},
  "applied": {},
  "skipped": {},
  "alreadySubmitted": {}
}

Write state and logs to:

/tmp/dice-easyapply-daily/state.json
/tmp/dice-easyapply-daily/results.jsonl

Skip reasons

Common skip reasons:

  • not_remote_only_or_has_hybrid_location_text
  • outside_resume_wheelhouse
  • external_ats_not_approved
  • unknown_required_question
  • captcha_or_verification_required
  • could_not_attach_resume
  • could_not_attach_cover_letter
  • already_submitted

Reporting

Report concise results:

Submitted:
- Title — Company — URL

Skipped:
- Title — Company — URL — reason

State: /tmp/dice-easyapply-daily/state.json
Log: /tmp/dice-easyapply-daily/results.jsonl

Pitfalls

  • Dice may preselect an older profile resume. Always verify the filename before submitting.
  • Dice pages can fire native beforeunload dialogs; register a Puppeteer dialog handler and accept beforeunload dialogs.
  • Dice may close/detach a page after a submit attempt. If navigation reports Target closed, Session closed, or frame was detached, create a fresh page, re-register the dialog handler, and continue from state.
  • Do not let unrelated recommendation/sidebar/footer text cause false remote/hybrid skips.
  • Do not overfit to a single resume. Keep search queries and skip rules configurable.
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 tags
claude-code
openclaw
hermes
codex
cursor
windsurf
goose
aider
roo-code
cline
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

  • Searches LinkedIn Jobs with Easy Apply enabled.
  • Supports remote-only and location-constrained searches.
  • Focuses on configurable role keywords such as AI, LLM, Claude, OpenAI, Codex, full-stack, frontend, backend, web, software, JavaScript, TypeScript, Node, React, and Svelte.
  • Opens the LinkedIn Easy Apply flow reliably with a direct apply URL when possible.
  • Uploads a verified resume PDF.
  • Answers only verified applicant facts.
  • Skips unknown required questions, compensation questions, custom essays, or subjective fields.
  • Keeps state and JSONL logs so daily reruns avoid duplicates.

Safety rules

  • Do not store LinkedIn credentials in scripts, skills, memory, logs, or reports.
  • Prefer a persistent browser profile where the operator logs in manually once.
  • Stop for CAPTCHA, MFA, suspicious-login checks, identity verification, or account-security prompts.
  • Do not fabricate applicant facts.
  • Do not answer custom freeform questions or compensation expectations without operator-provided answers.
  • Re-check full job descriptions for hybrid/location constraints before submitting remote-only applications.

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.
  • Remote filter when remote-only is required.
  • Location such as United States when requested.
  • Configurable keywords matching the resume and target market.

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:

  • Work authorization / eligible to work: yes only if verified.
  • Visa sponsorship required: no only if verified.
  • Remote willingness: yes only for remote-only searches.
  • Years of experience: use resume-backed values or a user-approved mapping.
  • Email/phone/location: use existing profile/resume facts.
  • Middle name: blank if none provided.

Skip:

  • Salary/compensation expectations.
  • Cover-letter text prompts.
  • Custom essays.
  • Relocation/hybrid/travel if not approved.
  • Unclear required inputs, radios, or selects.

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

  • Built-in browser tools often time out on LinkedIn. Puppeteer with Chromium and Xvfb is usually more reliable.
  • LinkedIn search cards can say Remote while the description includes hybrid/local constraints. Inspect the full page before applying.
  • Broad keyword matching can create bad answers. Avoid treating generic words like United States or comfortable as approval.
  • Direct DOM value assignment may not update React forms. Prefer click/type and dispatch input/change events.
  • If a page detaches or a modal closes unexpectedly, create a new page and continue from the state file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment