ATS Jobs Scraper: Greenhouse Jobs, Lever Jobs & Workday Jobs
Pricing
from $1.20 / 1,000 job scrapeds
ATS Jobs Scraper: Greenhouse Jobs, Lever Jobs & Workday Jobs
Jobs from nine applicant tracking systems in one schema - Workday, Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Rippling and Breezy. Run it daily with onlyNewJobs and it returns, and bills for, only what is new. Descriptions as markdown, text or HTML.
Pricing
from $1.20 / 1,000 job scrapeds
Rating
0.0
(0)
Developer
Abhinav Gupta
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
ATS Jobs Scraper — 9 applicant tracking systems, one schema
Scrape job postings from Workday, Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Rippling and Breezy and get them back in one normalised schema, whichever system a company uses.
Most job scrapers cover one or two systems and hand back that system's raw field names. If you track 200 companies they will be spread across half a dozen ATSs, and you end up gluing different shapes together yourself, or silently missing the companies your scraper does not cover. This covers all nine and returns one shape.
What you get
- One schema across all nine systems.
title,department,location,isRemote,salaryMin/salaryMax,postedAt,url— same fields, same types, every source. Missing values arenull, never absent, so CSV columns stay aligned. - ATS auto-detection. Pass a bare slug like
databricksand it works out which of the eight systems the company is on. Force it withgreenhouse:stripewhen you already know, which is faster and avoids an ambiguous match. - Salary parsed into numbers. Ashby publishes salary as display text
(
$211.4K - $290.6K,SEK 55,000 - SEK 75,000). You getsalaryMin: 211400,salaryMax: 290600,salaryCurrency: "USD"— and the original string too. - A remote flag that is actually correct. Ashby marks Hybrid roles as
isRemote: true— on one board that is 107 hybrid roles wrongly flagged remote out of 135. This usesworkplaceType, soremoteOnlyreturns remote jobs. - Clean description text. Greenhouse double-encodes its HTML; naive scrapers
return
<h2>Who we are</h2>as visible text. This decodes, then strips. - Filters that run before you pay: title keywords, location, department, remote-only, and posted-within-N-days.
Only what changed
Set onlyNewJobs and a run returns — and bills for — only the jobs it has not
seen before. A daily watch on a fixed company list costs what is new, not the
whole board again.
Three details that decide whether this is useful or merely present:
- The filter runs before billing. Skipping after the charge would bill for rows that are then thrown away.
- Only delivered jobs are recorded as seen. If a run stops at your
maxTotalChargeUsdcap partway through, the jobs it did not reach stay unseen and arrive next run. They are never silently marked as already sent. - State lives in a named key-value store, which Apify keeps indefinitely on
every plan. Give separate watches separate
stateStoreNamevalues, or one company list will suppress jobs for another.
The first run returns everything and seeds the state. Entries not seen for 60 days are dropped, so a role that comes down and is re-posted counts as new again.
Input
{"companies": ["greenhouse:stripe", "lever:spotify", "workable:peoplecert","https://adobe.wd5.myworkdayjobs.com/external_experienced", "databricks"],"keywords": ["engineer", "data"],"locations": ["bengaluru", "remote"],"remoteOnly": false,"postedWithinDays": 30,"includeDescription": true,"descriptionFormat": "text","maxItemsPerCompany": 25,"maxItems": 1000}
The slug is the last path segment of a company's careers URL:
| System | Careers URL | Slug |
|---|---|---|
| Greenhouse | boards.greenhouse.io/stripe | stripe |
| Lever | jobs.lever.co/spotify | spotify |
| Ashby | jobs.ashbyhq.com/ramp | ramp |
| Workable | apply.workable.com/peoplecert | peoplecert |
| SmartRecruiters | jobs.smartrecruiters.com/BoschGroup | BoschGroup |
| Recruitee | effectory.recruitee.com | effectory |
| Rippling | ats.rippling.com/rippling | rippling |
| Breezy | breezy.breezy.hr | breezy |
| Workday | paste the full careers URL | https://adobe.wd5.myworkdayjobs.com/external_experienced |
SmartRecruiters slugs are case-sensitive. Workday has no short slug because every tenant lives on its own host, so paste the careers URL and it is parsed for you.
Output
One row per posting:
{"company": "Ramp","companySlug": "ramp","ats": "ashby","jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245","title": "Security Engineer, Cloud","department": "Engineering","team": "Backend","employmentType": "FullTime","location": "New York, NY (HQ)","locations": ["New York, NY (HQ)"],"isRemote": false,"workplaceType": "Hybrid","country": "United States","salaryText": "$211.4K - $290.6K","salaryMin": 211400,"salaryMax": 290600,"salaryCurrency": "USD","salaryInterval": null,"postedAt": "2026-04-07T17:12:35.753Z","updatedAt": null,"url": "https://jobs.ashbyhq.com/ramp/34413f8d-...","applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-.../application","descriptionText": "About Ramp\nRamp is building the smart infrastructure...","descriptionHtml": null,"scrapedAt": "2026-08-21T00:00:00.000Z"}
A RUN_SUMMARY record is written to the key-value store with per-company counts and
any slugs that could not be resolved, so a partial run is diagnosable.
Who this is for
- Recruiters and sourcers tracking hiring at a list of target companies.
- Job boards and aggregators that need a steady feed with a stable schema.
- Sales teams using open roles as a buying signal ("hiring 5 data engineers").
- Market researchers tracking headcount, salary bands and remote policy over time.
Notes
- Reads the public job board APIs that these systems publish for exactly this purpose. No login, no cookies, no CAPTCHA solving, no proxies required.
- Companies not on one of these eight systems will not resolve; they are reported in
RUN_SUMMARY.notFoundrather than failing the run. - Rippling and Workday publish only a title and location on their board listings, so
each posting is fetched individually to fill in dates, employment type and
description.
maxItemsPerCompanyis applied before those requests, so capping at 25 costs 25 requests rather than two thousand. - Workday does not expose a department on its public API, so
departmentis null for Workday rows. Every other system populates it. - Boards are fetched at a concurrency of 5 with retry-and-backoff on 429/5xx.
Run it locally
npm installmkdir -p storage/key_value_stores/default# put your input in storage/key_value_stores/default/INPUT.jsonnpm start