Greenhouse, Lever, Ashby, Workable, SmartRecruiters Job Scraper
Pricing
from $1.00 / 1,000 delivered jobs
Greenhouse, Lever, Ashby, Workable, SmartRecruiters Job Scraper
ATS jobs scraper: paste a Greenhouse, Lever, Ashby, Workable or SmartRecruiters job-board URL (boards.greenhouse.io/stripe) or a board slug and get up to the whole board as clean rows, with new/changed/removed tracking. From $1 per 1,000 jobs; descriptions and change rows $0.0005 each. No run fee.
Pricing
from $1.00 / 1,000 delivered jobs
Rating
0.0
(0)
Developer
David Brooks
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
11 hours ago
Last modified
Categories
Share
ATS jobs scraper for Greenhouse jobs, Lever jobs, Ashby, Workable and SmartRecruiters — paste a job-board URL or slug, get up to the whole board as rows. From $1 per 1,000 jobs, no run fee.
Greenhouse, Lever, Ashby, Workable and SmartRecruiters are the applicant tracking systems behind a large share of company careers pages, and this actor reads all five from the same input. Paste the job-board URL the careers page links to — boards.greenhouse.io/stripe, jobs.lever.co/spotify, jobs.ashbyhq.com/openai, apply.workable.com/rockstar-3, careers.smartrecruiters.com/BoschGroup — or the short form greenhouse:stripe, and up to the whole board (maxItems caps it, 50 by default) comes back in one flat schema. Every row carries the title, the company (the board's display name, or its slug where the board publishes none), the posting URL and an apply URL; location, city, region and ISO country code, remote or hybrid or onsite, work type, department, salary and the posted date are filled wherever the board publishes them, and Known limits says which board leaves out what. Switch on change tracking and each run also tells you which postings are new, which changed and which have come down since the last run.
What you get
- Five applicant tracking systems behind one input, so a run can mix boards from all five — and up to 200 boards in a single run
- One schema for all five: the same keys, the same
sourceIdformat and aschemaVersionthat never changes under you, whichever ATS a row came from trackChangesgives every row achangeStatusof new, changed or unchanged against the previous run of that board, and postings that have come down arrive as rows withchangeStatus: removed— a job-feed monitor with no diffing of your own- Location parsed into
city,regionand an ISO-3166countrycode, even where the board publishes a country name ('United States') or a lower-case code ('mx') instead - Salary as numbers —
salaryMin,salaryMax,salaryCurrency,salaryPeriod— on the boards that publish compensation, plus the board's own summary text insalaryText - Full descriptions are optional, so a list-only monitoring run stays cheap and pays nothing for payloads it does not want
- A job-board URL or
ats:slugwith no board behind it is named in the run summary, and a run in which every board is missing fails with a typed error instead of succeeding with zero rows
Sample row:
{"sourceId": "ashby:openai:8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3","sourceUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3","source": "ashby","schemaVersion": 1,"title": "Technical Program Manager, Compute Infrastructure","company": "openai","companyId": "openai","location": "San Francisco","city": "San Francisco","region": "California","country": "US","remote": "unknown","workType": "full-time","category": "Technical Program Management","subcategory": "Technical Program Management","salaryText": "$257K – $335K • Offers Equity","salaryMin": 257000,"salaryMax": 335000,"salaryCurrency": "USD","salaryPeriod": "year","postedAt": "2026-03-12T16:38:15.322Z","expiresAt": null,"applyUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3/application","changeStatus": null}
Input
| Field | Description |
|---|---|
boards | One entry per company: a job-board URL (https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/openai, https://apply.workable.com/rockstar-3, https://careers.smartrecruiters.com/BoschGroup) or the short form ats:slug. Up to 200 per run; anything else is rejected before the run starts, with the accepted forms listed |
includeDescription | Fetch the full description (HTML and plain text). Charged per row that carries one |
since | ISO date. Postings first published before it are skipped and never charged. A date filter only |
trackChanges | Compare each board against its previous run: rows carry changeStatus, and postings that have come down are delivered as removed |
maxItems | Hard cap on delivered jobs (default 50), enforced before the request that would exceed it |
maxCostUsd | Hard stop on spend, enforced before each request |
proxyConfiguration | Datacenter Apify Proxy by default; switch it off for small runs |
outputFormat | flat (default) or nested |
Pricing
Pay per event. You are charged only for delivered, validated results — never for empty pages, blocked requests, or duplicates. maxCostUsd is a hard stop enforced before each request.
| Event | Price | Unit |
|---|---|---|
job | $0.001 | per delivered job — $1.00 per 1,000 |
job-description | $0.0005 | per row with a full description — only with includeDescription |
company-diff | $0.0005 | per new, changed or removed posting — only with trackChanges, and never on a board's first run |
- 1,000 jobs ≈ $1.00
- 1,000 jobs with full descriptions ≈ $1.50
- A daily monitor over 40 boards returning 200 postings with 20 changes ≈ $0.21 per run, about $6.30 a month
- There is no per-run fee: a run pays only for the rows it delivers, so a run over boards that return no rows costs nothing at all
Why this actor
- One actor covers Greenhouse, Lever, Ashby, Workable and SmartRecruiters: paste each board URL as the careers page links to it and the actor reads the system from the host, so a run can mix all five
- No per-run start fee. Scheduled monitoring pays for the rows it delivers and nothing else, which matters when you run the same 40 boards every morning
- A job-board URL or
ats:slugwith no board behind it is named in the run summary undermeta.missingBoards, and a run in which every board is missing fails with a typedBoardNotFoundError, rather than finishing successfully with zero rows and letting a broken monitor look healthy for weeks maxItemsandmaxCostUsdare enforced before the request that would exceed them, and the run summary says which cap stopped it- Change detection is stored per board and is only updated after a complete pass over that board's feed, so a run stopped by a cap never makes the next run report postings it simply never reached as 'new' or 'removed'. A board whose posting count happens to equal
maxItemsexactly still counts as a complete pass, and a removal a cap left no room for is kept and reported on the next run rather than dropped - Descriptions are priced separately and off by default, so a list-only feed watcher is not charged for payloads ten times the size it needs
- No AI 'enrichment' and no inferred fields priced as data: every value is the board's own, and anything the board does not publish is null rather than guessed (the two fallbacks are
company, which is the board slug where the board publishes no display name, andapplyUrl, which is the posting page where it publishes no separate apply link)
Known limits
- Five systems only — Greenhouse, Lever, Ashby, Workable and SmartRecruiters. Workday, iCIMS, Recruitee, Personio, Teamtailor and company career sites on their own software are not supported, and the actor does not guess a company's ATS from its name or domain: you give it the job-board URL (e.g. boards.greenhouse.io/stripe) or
ats:slug - Greenhouse publishes no salary on its public job board API: none of the boards checked carried a pay range, so
salaryMin,salaryMaxandsalaryTextare null on Greenhouse rows.category,subcategoryandcountrycome from fields Greenhouse sends only with the full description, so they fill in withincludeDescription— and for that reasoncategoryis left out of the Greenhouse change-detection hash, so turning descriptions on or off never reports a board as changed. The same holds on SmartRecruiters, whose own apply URL only comes with the full posting (without it,applyUrlis the posting page) and is excluded from the hash for that reason - Greenhouse also has no workplace field, so
remoteon a Greenhouse row is read from the location label ('Remote - Japan') and isunknownwhen the label does not say - Lever and Ashby publish no employer display name, so
companyon those rows is the board slug. Workable and SmartRecruiters do publish one, and Greenhouse sends it with every posting - Workable's API carries no work type and no salary, so
workType,salaryMinandsalaryMaxare null on Workable rows - Ashby returns an entire board in a single response — 830 postings measured 14.5 MB, with the compensation fields this actor always requests — so
maxItemslimits what you are charged for, not how much is downloaded. The same is true of Greenhouse, which has no pagination either - Because of that, the actor asks the platform for at least 1 GB of memory and refuses a single response larger than 64 MB. Both numbers come from the same measurement — parsing a 14.5 MB board peaked at 168 MB resident, and the cost scales at roughly 6.9 MB of memory per MB of response on top of a 74 MB baseline, so a response at the 64 MB ceiling needs about 500 MB before a single row is mapped. Run it with less and the largest boards are killed by the container rather than reported. Raise the memory rather than the ceiling if you ever see a board refused for size
- Workable and SmartRecruiters descriptions need one extra request per job, so
includeDescriptionruns on those two boards are slower (Greenhouse, Lever and Ashby send the description with the listing) - SmartRecruiters' Posting API answers identically for a company id that does not exist and a company with no live postings, so the actor checks where the public careers page ends up to tell them apart. A company id it cannot confirm is reported as an error rather than as an empty board, because a silently empty monitor is worse than a loud one. Requests to that host are kept to one per second
- Salary appears only where the board publishes it. Most do not: expect it on Ashby boards that display compensation, and rarely elsewhere
- Change detection needs
trackChangesand a complete pass over the board: a run in whichmaxItemsormaxCostUsdcut a board's feed short deliberately leaves that board's stored baseline alone and reports no removals for it, so give a monitored board amaxItemsabove its posting count. Removal rows count againstmaxItemslike any other row, and removals the cap had no room for stay in the baseline and are reported on the next run —meta.deferredRemovalssays how many are still waiting.sinceis a posted-date filter and nothing else, the same as in every other actor in this account. If the platform restarts a run part-way through, the rows it had already delivered are counted as delivered: they are not billed again and they stay in the baseline - A board that is missing or empty is reported, not silently dropped: each one is logged as a warning while the run continues, and the run's
RUN_SUMMARYrecord in the key-value store lists them undermeta.missingBoardsandmeta.emptyBoards, alongsidemeta.requested,meta.delivered,meta.skipped,meta.diffMode, the per-board breakdown inmeta.boards, and — intrackChangesruns —meta.newPostings,meta.changedPostings,meta.unchangedPostings,meta.removedPostings,meta.deferredRemovalsandmeta.removalOnlyBoards. A board that went quiet is listed undermeta.removalOnlyBoardsrather thanmeta.emptyBoards: its feed is empty, but every posting it used to carry was delivered as a removal row and charged, which is the opposite of nothing happening. Read that record to find out which of a longboardslist actually produced rows. The run fails with aBoardNotFoundErroronly when every board is missing - Employer job postings only. No candidate, applicant or recruiter personal data is collected from any of the five systems
Use from an AI agent (MCP)
Add the actor as an MCP tool in Claude Desktop / Cursor via the Apify MCP server:
{ "mcpServers": { "ats-jobs": { "url": "https://mcp.apify.com?actors=<your-username>/ats-jobs", "headers": { "Authorization": "Bearer <APIFY_TOKEN>" } } } }
The tool accepts exactly the input fields above and returns the same rows, so an agent can ask for a
company's open roles by passing the job-board URL (e.g. boards.greenhouse.io/stripe) or ats:slug it
already found.
Use from n8n / Make
Use the Apify node → "Run actor" with actor <your-username>/ats-jobs on a daily schedule and a JSON
input such as
{"boards":["greenhouse:stripe","lever:spotify","ashby:openai"],"trackChanges":true,"maxItems":500},
then "Get dataset items" and filter on changeStatus to act only on what moved since yesterday.
FAQ
How do I find a company's board slug?
You do not need it. Open the company's careers page, and if it links to (or the address bar shows) one of the five ATS hosts, paste that job-board URL, e.g. boards.greenhouse.io/stripe. The actor takes the slug out of it, including from a single job's URL. A careers page on the company's own domain is not accepted.
What happens if a company moves to a different ATS?
The old board starts answering "not found" and that board is reported as missing in the run summary, with nothing charged for it. Add the new job-board URL (e.g. boards.greenhouse.io/stripe) or ats:slug and the rows continue under a new source value.
How does change detection know what changed?
After a complete pass over a board it stores a hash of the fields a feed watcher cares about — title, location, work type, remote arrangement, salary, department, posted date and apply URL — per posting. Descriptions are deliberately excluded, because boards re-render their HTML without the job changing. So is department on Greenhouse, which publishes it only alongside the full description — hashing it would have reported a whole board as changed the first time you turned includeDescription on. The apply URL on SmartRecruiters is left out for the same reason.
Why is salary null on most rows?
Because most boards do not publish it. The actor reports what the board sends and leaves the rest null rather than inventing a figure or inferring one from the job title.
Do I need a proxy?
Not for small runs. All five APIs answer datacenter and plain IPs today. The default is datacenter Apify Proxy with session rotation because each host rate-limits per address, which matters once you monitor dozens of boards on a schedule.
Legal and data posture
This actor reads five documented, public, keyless job board APIs: the Greenhouse Job Board API, the Lever Postings API, the Ashby Posting API, Workable's public careers widget API and the SmartRecruiters Posting API. It never logs in, never uses accounts or cookies from accounts, and never solves a challenge. It collects employer job advertisements only, and no personal data about candidates, applicants or recruiters. Request rates are conservative — one request per second per host, which honours Lever's published crawl delay and SmartRecruiters' documented API guidance — and 429 responses fail the run with a typed error instead of being retried in a loop. SmartRecruiters' robots.txt disallows crawling the API host even though the Posting API is published and documented for exactly this use; the rate limit above is our answer to that, and it is stated here rather than buried. Data is delivered to you for your own use; no corpus is built or resold.
Support
Open an issue on the Issues tab; first response within 6 hours on business days. Every run writes a RUN_SUMMARY record to the key-value store with items delivered, events charged, and the stop reason.