Workday, Greenhouse, Lever, Ashby and ATS Jobs Scraper
Pricing
$1.50 / 1,000 listed jobs
Workday, Greenhouse, Lever, Ashby and ATS Jobs Scraper
Workday jobs scraper plus Greenhouse, Lever, Ashby, Rippling, BambooHR, Jobvite and iCIMS careers page scraper. Give it companies, get one clean job feed row per opening.
Pricing
$1.50 / 1,000 listed jobs
Rating
0.0
(0)
Developer
Gerald Dobin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Give this Actor a list of companies and it returns every open job those companies are advertising,
as clean rows in one schema. It reads each company's applicant tracking system through that
system's own public job board endpoint, so the data is the same data the company publishes on its
careers page: no rendering, no guessing, no stale copies. Fourteen systems are covered today:
Workday, Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Personio, Teamtailor, Recruitee,
Rippling, Jobvite, Breezy HR, BambooHR and iCIMS. You can point it at a board link such as
https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite or https://jobs.lever.co/palantir,
at a company's own careers page such as https://vercel.com/careers (the Actor loads it once and
finds the board behind it), or at a short system:slug pair such as greenhouse:stripe. Titles,
departments, locations, employment type, posting dates, salary ranges where the company publishes
them, and the full job description in both HTML and plain text all come back in the same field
names no matter which system the job came from.
Who it is for
Job aggregators and job boards that need clean feeds. Point the Actor at a few thousand
employers, schedule it daily, and load the rows straight into your index. Every row carries a
stable jobId, so you can upsert on it and spot the jobs that disappeared since yesterday without
diffing free text.
Recruiters and sourcers tracking target companies. Keep a watch list of the twenty companies your candidates care about and see the moment a role opens, with the apply link and the pay range already in the row instead of buried three clicks into a careers site.
Sales teams using hiring signals as intent data. A company that just posted four data engineering roles is buying a data stack. Filter on job title keywords, push the results into your CRM, and let your reps work accounts that are visibly investing rather than accounts that merely match a firmographic filter.
What you get
One dataset row per unique job. Here is a real row from a test run against Ramp's Ashby board, with the two long description fields shortened for readability:
{"ats": "ashby","companySlug": "ramp","companyName": null,"jobId": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245","nativeId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245","title": "Security Engineer, Cloud","department": "Engineering","team": "Backend","location": "New York, NY (HQ)","city": "New York City","country": "United States","remote": false,"workplaceType": "hybrid","employmentType": "Full-time","seniority": null,"salaryMin": 211400,"salaryMax": 290600,"salaryCurrency": "USD","salaryPeriod": "year","descriptionHtml": "<div><p>Ramp is a financial operations platform ...</p></div>","descriptionText": "Ramp is a financial operations platform ...","postedAt": "2026-04-07T17:12:35.753Z","updatedAt": null,"applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application","sourceUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245","scrapedAt": "2026-09-07T23:03:29.062Z"}
Every field is present on every row. A field is null when the applicant tracking system does not
publish it, never missing and never an empty string. Dates are ISO 8601 in UTC. workplaceType is
one of remote, hybrid, onsite or null, and remote always agrees with it. Salary fields are
plain numbers plus a currency and a period, parsed out of whatever shape the board used.
How to use it
Inputs
| Input | What it does |
|---|---|
companies | One line per company: a board link, a careers page link, or a system:slug pair. Required. Workday boards are addressed by two names, so its pair carries both: workday:nvidia.wd5/NVIDIAExternalCareerSite. |
keywords | Keep only jobs whose title contains one of these words. Case does not matter. |
locations | Keep only jobs whose location, city or country contains one of these words. |
remoteOnly | Keep only jobs the company marks as remote. |
postedAfter | Keep only jobs posted on or after this date, written as YYYY-MM-DD. |
includeDescription | On by default. Turn it off for a faster, cheaper run when you only need titles and links; the two description columns stay in the output as nulls. |
maxJobsPerCompany | Stop after this many jobs per company. 0 means no limit. Worth setting on Workday boards, which often carry thousands of openings: the Actor stops paging as soon as it has this many. See the note below on how this interacts with filters. |
maxConcurrency | How many companies to work on at once. Lower it if a board starts rate limiting. |
How maxJobsPerCompany behaves when you also set a filter. You always get up to that many
jobs that actually match. On the boards that publish the whole job in the listing, that costs
nothing extra. On the boards that need a second request per job, some filters can only be judged
once that second request has happened: a Workday listing carries no posting date at all, and an
iCIMS job card may carry no location. When a filter of that kind is set, the Actor keeps reading
further down the board until it has enough matching jobs, rather than taking the first few and
then discarding most of them. That costs more requests than an unfiltered run of the same size,
and it stops at 2000 jobs examined per company, so a filter that matches almost nothing on a very
large board returns what it found by then rather than reading the whole board. Filtering on job
title keywords never costs extra on any board, because every listing carries the title.
A monitoring pattern that works. Schedule the Actor once a day against the same company list,
write every run into the same named dataset, and deduplicate on jobId on your side. A jobId you
have not seen before is a new opening. A jobId that stops appearing is a closed one. Because the
id is built from the ATS, the board slug and the system's own job id, it stays the same across runs
and across changes to the job title or location.
Calling it from the API
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~ats-jobs-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"companies": ["greenhouse:stripe", "workday:ww.wd1/careers", "https://vercel.com/careers"],"keywords": ["engineer"],"includeDescription": false}'
Add &format=csv to that URL for a spreadsheet instead of JSON. Results also stay in the run's
dataset, so you can page through them later with the standard dataset endpoints.
MCP. Apify exposes its Actors over the Model Context Protocol, so an assistant such as Claude can call this scraper as a tool and answer questions like "which of these fifteen companies is hiring platform engineers in Berlin right now" without you writing any glue code.
Coverage and limits
Covered. Workday, Greenhouse (including EU boards and embedded job boards), Lever, Ashby, Workable, SmartRecruiters, Personio, Teamtailor, Recruitee, Rippling, Jobvite, Breezy HR, BambooHR and iCIMS. Between them these cover most startups and mid-market employers, a good share of large European ones, and with Workday and iCIMS a large part of the enterprise market too.
Workday takes two names, not one. A Workday board lives at a tenant host and publishes one or
more career sites on it, so both halves are needed. Paste the board URL in any shape it comes in,
including the ones with /en-US/ or a /job/... path, and the Actor works out the pair. If you
prefer the short form, write it as workday:tenant.wdN/SiteName, for example
workday:nvidia.wd5/NVIDIAExternalCareerSite. Workday boards are often very large, so set
maxJobsPerCompany when you only want a sample: the Actor stops paging as soon as it has enough
instead of walking the whole board.
Not covered. SuccessFactors, Taleo, Oracle Recruiting and JazzHR are not supported. Those systems either have no public job board endpoint or gate it behind per-tenant credentials.
A company must expose a public board. If an employer has switched its board to private, or publishes jobs only inside a rendered careers page with no underlying system, there is nothing to read and the Actor says so.
Descriptions. Greenhouse, Lever, Ashby, Teamtailor and Recruitee return the job body in the
same call as the listing. Workday, SmartRecruiters, Workable, Rippling, BambooHR, Jobvite, iCIMS
and Breezy need one extra request per job, so those companies take longer and cost more compute;
turn includeDescription off when you do not need the body. Personio returns descriptions only
when the employer fills them in on the board.
Dates. postedAt and updatedAt are only filled in when the board publishes a date the Actor
can read exactly, in ISO 8601 or that system's documented format. A date it cannot read becomes
null rather than a guess. Workday is the clearest case: its board list dates a job only as "Posted
Today" or "Posted 5 Days Ago", which become real dates, while "Posted 30+ Days Ago" is a floor
rather than a date and becomes null instead of pretending to be exactly thirty days old. postedAfter is checked when the run starts, so a value the Actor cannot
parse stops the run with a message instead of quietly disabling your filter.
Salary. Ashby, Lever, Recruitee and Breezy publish structured pay ranges and the Actor passes
them through. BambooHR and Jobvite publish pay as a display string or a schema.org block, and the
Actor reads it when the numbers and the currency are unambiguous; a range it cannot read
confidently is left null rather than reported wrongly. Greenhouse, SmartRecruiters and Workday
usually do not publish a structured range, so salaryMin and salaryMax are null there even
when a range appears inside the description text.
Companies that fail. A company that resolves to no known system produces a single row with
error: "ATS not detected". A slug that no longer exists produces a row with
error: "board not found". If a board answers with something that is not the shape it documents,
you get error: "unexpected response from <system>" rather than a silent empty result, so a
changed endpoint cannot look like a company that stopped hiring. These rows are free.
Addresses the Actor will not fetch. Only plain public http and https URLs on the default
port are accepted. Links to an IP address, to localhost or a .internal name, or to any host that
resolves onto a private, loopback, link local or cloud metadata address are refused, and that check
is applied again on every redirect. Job descriptions are stripped down to ordinary formatting tags
before they reach you, so no scripts, styles, embeds or javascript: links come through.
Run size. Up to 5000 companies and 200000 jobs in one run. Split larger lists across runs.
Pricing
Pay per unique job delivered. You are charged once for each job row the Actor writes into the dataset, and nothing else. There is no monthly subscription and no minimum.
- Duplicate jobs inside a run are removed before they reach the dataset and are never charged.
- Error rows are never charged.
- Jobs removed by your
keywords,locations,remoteOnlyorpostedAfterfilters never reach the dataset, so they are never charged. On the systems that need a second request per job, those filters are applied before that request, so a narrow filter is a cheap run.
A run that finds nothing costs nothing. If you set a maximum spend on the run, the Actor stops fetching once it hits that ceiling and finishes cleanly with whatever it has already delivered, rather than failing.
Support
Something wrong with a row, or a company whose board the Actor cannot see? Open an issue on the
Actor's Issues tab with the exact companies entry you used and the run id. Requests for another
applicant tracking system are welcome; say which one and name a company that uses it, so the
endpoint can be checked against a real board.
Runs are stateless and store nothing beyond the dataset and the key value store record for the run itself. The Actor reads only public job board endpoints and sends no credentials anywhere.