ATS Job Scraper — Greenhouse, Lever, Ashby, Workday
Pricing
Pay per event
ATS Job Scraper — Greenhouse, Lever, Ashby, Workday
Scrape jobs from company career pages across Greenhouse, Lever, Ashby, Workday and SmartRecruiters. Unified schema, deduplication, delta mode and salary data. No cookies, no proxies, no login.
Pricing
Pay per event
Rating
0.0
(0)
Developer
JIGSAW
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
ATS Job Scraper — Greenhouse, Lever, Ashby, Workday & SmartRecruiters
Scrape job listings straight from company career pages across five applicant tracking systems, in one run and one unified schema. Give it a list of company domains — or pick a curated preset — and it works out which ATS each company uses, pulls every open role, and returns 46 clean, deduplicated, enriched fields per job.
No cookies. No logins. No proxies needed. No LinkedIn rate limits.
One HTTP request to Databricks returns 819 jobs. A 57-job run finishes in under 4 seconds.
Start in one click
Pick a preset and run it. No slugs to research, no configuration:
{ "presetLists": ["yc-and-ai"] }
| Preset | Companies | Open jobs |
|---|---|---|
yc-and-ai | 15 | ~2,500 |
fintech | 18 | ~2,300 |
data-infra | 13 | ~2,400 |
devtools | 17 | ~1,300 |
mobility-logistics | 9 | ~1,400 |
ecommerce-retail | 5 | ~1,200 |
security | 10 | ~1,000 |
bigtech-startups | 10 | ~900 |
enterprise-saas | 10 | ~760 |
gaming-media | 8 | ~570 |
healthtech | 3 | ~110 |
Every company in every list was probed live against its ATS and confirmed to return open jobs.
Why scrape the ATS instead of a job board
Most job scrapers hit aggregators — LinkedIn, Indeed, Glassdoor — where listings are stale, duplicated three times over, and wrapped in anti-bot defences that break weekly.
This one goes to the source: the company's own applicant tracking system. When a recruiter opens a role, it appears here first.
- Fresher. You see the posting the day it goes live, not when an aggregator indexes it.
- No anti-bot fight. These are public, documented APIs. Runs finish in seconds and don't silently degrade.
- Real salary numbers. Ashby and Lever publish structured pay ranges. You get numbers, not a string to parse.
- The apply link is the real one. Straight to the company's form, no redirect chain.
Four ways to say what you want
// 1. Curated preset — zero research{ "presetLists": ["fintech", "devtools"] }// 2. Company domains — the ATS is detected automatically{ "companies": ["stripe.com", "openai.com", "databricks.com"] }// 3. Career page URLs — pasted straight from the browser{ "boardUrls": ["https://boards.greenhouse.io/figma", "https://jobs.lever.co/shieldai"] }// 4. Exact boards, when you already know them{ "boards": [{ "ats": "ashby", "slug": "openai" },{ "ats": "workday", "tenant": "nvidia", "site": "NVIDIAExternalCareerSite" }] }
Mix them freely in one run. Duplicate boards are collapsed automatically.
What makes this one different
Remote flags you can actually trust
Ashby marks hybrid roles as isRemote: true. Any scraper that copies that flag reports 480 remote jobs at OpenAI — 448 of which are hybrid roles in San Francisco.
This Actor derives is_remote from the workplace type and location text, and exposes workplace_type as a clean remote / hybrid / onsite. Same company, same run: 37 genuinely remote roles. When you filter with remoteOnly, you get remote jobs.
Derived fields that don't invent things
Every job is enriched with rule-based extraction — no LLM, no per-job cost, no hallucinated salaries:
| Field | What it gives you |
|---|---|
seniority | intern / entry / mid / senior / lead / director / executive |
years_experience_min | Lowest explicitly stated requirement |
skills | Detected from a 150-technology taxonomy |
benefits | equity, retirement, health insurance, PTO, parental leave, relocation, learning budget, 4-day week… |
education_level | phd / master / bachelor / associate / high_school |
visa_sponsorship | true, false, or null when the posting says nothing |
requires_security_clearance | Boolean |
is_agency | Flags staffing and agency listings so you can exclude them |
salary_annual_min_usd | Every salary normalised to annual USD, comparable across 40 currencies |
country_code, continent | ISO-3166 codes derived even when the ATS only wrote a city |
These are read from the title, never guessed from body noise. A posting that mentions reporting to a "Senior Manager" is not a lead role; a Research Engineer asked to "partner with researchers" is not an executive. Where the title is silent, seniority falls back to the stated years of experience, and otherwise returns null. An honest null beats a confident wrong answer.
The same discipline applies everywhere: Excel is only detected as a skill when it appears as a tool, not in "a culture where everyone can excel". Go is not detected from "go-to-market". Salary is only read from description text when a currency symbol sits next to the numbers.
Delta mode — pay only for what changed
Set deltaMode: true and the Actor remembers what it saw last time. The next run returns only jobs that are new, updated or removed, tagged in delta_status.
| Run | Result | Billed |
|---|---|---|
| 1 — baseline | 27 jobs | 27 |
| 2 — nothing changed | 0 jobs | 0 |
| 3 — 3 posted, 2 edited | 5 jobs | 5 |
A daily watch over 500 companies returns the twelve postings that moved, not the 40,000 rows you already had. Removed jobs are never charged.
Deduplication that works
ATS boards publish the same role once per office — "Senior Engineer (Berlin)", "Senior Engineer (London)", "Senior Engineer (R4953)". The Actor normalises titles, stripping location suffixes, requisition numbers and bracketed noise, and keeps the richest copy. Every record carries a stable dedup_key so you can dedupe further against your own sources.
Alerts built in
Point slackWebhookUrl, discordWebhookUrl or your own webhookUrl at the run and get a digest when it finishes. Pair with delta mode and a daily schedule for a job alert that only fires on real changes.
Filters
Text — searchText, titleKeywords, excludeTitleKeywords, excludeKeywords, departments, skills
Location — locations, excludeLocations, countryCodes, remoteOnly, workplaceTypes
Attributes — seniorityLevels, employmentTypes, maxAgeDays, maxYearsExperience, visaSponsorshipOnly, excludeAgencies, excludeCompanies
Salary — requireSalary, minSalaryUsd, maxSalaryUsd (all normalised to annual USD first, so a €65/hour contract and a £90k salary sort correctly against each other)
A concrete example — senior backend roles in Europe paying over $120k, no agencies, posted this week:
{"presetLists": ["devtools", "data-infra"],"titleKeywords": ["backend", "platform", "infrastructure"],"excludeTitleKeywords": ["intern", "manager"],"seniorityLevels": ["senior", "lead"],"countryCodes": ["GB", "DE", "NL", "ES", "PL"],"minSalaryUsd": 120000,"excludeAgencies": true,"maxAgeDays": 7}
Output
46 fields per job, identical whichever ATS produced them, in a fixed column order so your CSV never shifts.
{"job_id": "2233810f44e4d892208708b0a40f904b","dedup_key": "369a657675e0fdb099258b220f3a32b9","title": "Android Engineer III","seniority": "senior","department": "Hinge","company_name": "Match Group","is_agency": false,"location_raw": "New York, New York","location_city": "New York","location_region": "New York","country_code": "US","continent": "North America","is_remote": false,"workplace_type": "hybrid","employment_type": "full_time","years_experience_min": 5,"education_level": "bachelor","skills": ["Kotlin", "Java", "Git", "Agile"],"benefits": ["health_insurance", "retirement", "equity", "paid_time_off"],"visa_sponsorship": null,"requires_security_clearance": false,"has_salary": true,"salary_min": 150000,"salary_max": 180000,"salary_currency": "USD","salary_interval": "year","salary_annual_min_usd": 150000,"salary_annual_max_usd": 180000,"salary_source": "ats","posted_at": "2026-05-19T20:38:11.267Z","scraped_at": "2026-08-08T04:15:06.701Z","age_days": 80,"apply_url": "https://jobs.lever.co/matchgroup/3414ba28.../apply","ats": "lever","external_id": "3414ba28-35f7-45d3-8e13-35c883959635","description_text": "…"}
Three output profiles: full, compact (drops the HTML description) and minimal (17 core fields for dashboards). Five ready-made dataset views: overview, salary benchmarking, requirements & benefits, changes, remote roles.
Coverage
| ATS | Targeting | Notes |
|---|---|---|
| Greenhouse | domain, slug, URL | Full descriptions, departments, offices |
| Lever | domain, slug, URL | Structured salary ranges, workplace type |
| Ashby | domain, slug, URL | Richest salary data of the five |
| Workday | URL, or tenant + site | Paginated; descriptions need one request per job |
| SmartRecruiters | domain, company ID, URL | Paginated, includes industry |
What people use it for
- Job boards and aggregators — a listing site fed from company sources, fresher than the aggregators you'd otherwise scrape.
- Recruiting intelligence — track which teams a competitor is growing and where. Delta mode plus a Slack webhook turns this into a daily digest.
- Salary benchmarking — structured pay ranges across hundreds of companies, normalised to annual USD so markets are comparable.
- Talent market research — hiring velocity by department, seniority, location or required skill.
- Staffing lead generation — spot companies opening roles in your specialism the day they post.
- Personal job hunting — watch a preset list, filter to your seniority and salary floor, get only what's new each morning.
Pricing
Pay per event. No charge for starting a run.
| Event | Price |
|---|---|
| Job scraped | $0.002 |
| Company resolved to its ATS | $0.005 (first time only — cached afterwards) |
Every open role at Databricks — 819 jobs with full descriptions and enrichment — costs $1.64. Running the same watchlist daily in delta mode costs a few cents once the baseline is set.
Jobs reported as removed are free. Enrichment is free — it's rule-based, not an LLM call.
Frequently asked questions
Do I need a proxy? No. These are public APIs and the Actor runs fine on Apify's default IPs.
Will it break when a site adds anti-bot protection? Far less often than a scraper that renders career pages in a browser. The Actor talks to documented JSON APIs these platforms maintain for their own job widgets.
How fresh is the data?
Fetched live at run time, straight from the ATS. Every record carries scraped_at, posted_at and age_days, so freshness is visible rather than assumed. This is not a cached index served back to you.
Why isn't there salary data on every job? Because most companies don't publish one. Ashby and Lever expose structured ranges when the employer fills them in; Greenhouse and Workday rarely do. Where nothing structured exists, the Actor looks for an explicit range in the description — but only next to a currency symbol. Otherwise the field stays null instead of guessing.
Why is seniority sometimes null?
Because the title didn't say and the description didn't state years of experience. Guessing from body text produced measurably wrong answers in testing, so the Actor returns null instead.
Can I scrape a company that isn't on these five systems? Not yet. Workable, Recruitee, Personio, Teamtailor and BambooHR are next. If a company you need is missing, open an issue and it'll be prioritised.
Is scraping this data legal? The Actor collects publicly available job listings that companies publish deliberately for candidates to find, and no personal data. How you use scraped data remains your responsibility — Apify's ethical scraping guide is a good starting point.
Integrations
Works with everything on the Apify platform: schedules, webhooks, the API, and integrations with Make, Zapier, Google Sheets, Slack, Airbyte and n8n. Built-in Slack, Discord and custom-webhook delivery means you often don't need a second tool at all.
Support
Found a bug, need another ATS, want a field that isn't there? Open an issue on the Actor's Issues tab. Reports are answered within 24 hours.