Greenhouse, Lever, Ashby & Workday Jobs Scraper (Multi-ATS)
Pricing
from $1.50 / 1,000 jobs
Greenhouse, Lever, Ashby & Workday Jobs Scraper (Multi-ATS)
[From $1.50 / 1K jobs] Greenhouse jobs scraper, Lever jobs API and Workday jobs scraper in one: plus Ashby, SmartRecruiters & Workable. Paste company names or careers URLs. Salary parsing, remote/country filters, new/removed tracking. No login, no proxies.
Pricing
from $1.50 / 1,000 jobs
Rating
0.0
(0)
Developer
Victor Verpooten
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
Greenhouse Jobs Scraper, Lever Jobs API & Workday Jobs Scraper: Multi-ATS Job Feed (Ashby, SmartRecruiters, Workable)
One Actor, one clean schema, six applicant-tracking systems. Give it company names, ATS board links or a plain careers-page URL. It returns every open job in the same format, with parsed salary ranges, country and remote flags, and optional "what changed since last run" tracking.
Everything comes from the ATS vendors' own public job-board endpoints. No browser, no proxies, no login. Runs are fast and cheap: from $1.50 per 1,000 jobs (pay per event, no monthly rental).
Try it in 30 seconds: press Start with the prefilled input (Figma on Greenhouse, Spotify on Lever, Ramp on Ashby and Hugging Face on Workable, at most 40 jobs, about 6 cents) or start with an empty input for a smaller 25-job demo. Then replace companies with your own list.
What you get
- Six ATSs in one schema. Greenhouse, Lever (global and EU), Ashby, SmartRecruiters, Workable and Workday (the career sites of many large employers,
*.myworkdayjobs.com). - Paste anything. Accepts
greenhouse:figma,https://boards.greenhouse.io/figma,https://jobs.lever.co/spotify,https://apply.workable.com/huggingface/,https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, or a company careers URL such ashttps://www.figma.com/careers/. The Actor finds the ATS behind the careers page. A bare name such asrampis tried against every ATS except Workday (Workday needs its URL or full slug, see below). - Salary extraction. Structured pay data is used where the ATS provides it: Ashby, Lever, and Greenhouse (opt-in). Otherwise salary ranges are parsed from the posting text ("$120,000-$150,000 USD", "€70.000 - €90.000", "$55-$65/hour"). Each salary has min, max, currency, period and an annualised value.
sourcetells you whether it isstructuredortext. - Filters. Keywords (any-of), exclude keywords, keyword scope (title only, or title and description), countries (ISO codes or names), remote only, departments, and posted within N days.
- Change tracking. Turn on
sinceLastRunand you only getnew,updatedandremovedjobs. Ideal for scheduled runs, alerts and job-board syncs. - Built-in company directory. About 3,100 verified boards (Greenhouse ~720, Ashby ~970, Workable ~700, Lever ~460, SmartRecruiters ~75, Workday ~215 large employers). Turn on
useSeedListto scan them without supplying a list. The Workday directory is opt-in: add"workday"toseedAts, because Workday boards are big and slower to read. - Polite and resilient. Per-host concurrency limits, pacing, retries with backoff, and
Retry-Aftersupport. One failing company never aborts the run.
One Actor instead of four: Greenhouse, Lever, Ashby and Workday
- Greenhouse jobs scraper: every open job on any
boards.greenhouse.ioboard, with optional official pay ranges. - Lever jobs API: any
jobs.lever.coboard (global and EU) as clean JSON, CSV or Excel. - Workday jobs scraper: large employers'
*.myworkdayjobs.comcareer sites (opt-in, with a directory of 217 verified tenants). - Ashby, SmartRecruiters and Workable jobs in the same schema, so you write your pipeline once.
Typical uses
-
Scrape every open job from a list of target companies (startups on Greenhouse, Lever and Ashby, large employers on Workday)
-
Job boards and aggregators that need fresh, normalised listings
-
Salary benchmarking and compensation research (see the
salariesview) -
Recruiting and sales intelligence: "who is hiring a Head of Data in Germany?"
-
Hiring-signal alerts for competitors or target accounts (schedule with
sinceLastRun) -
Feeding LLM/RAG pipelines with structured job data (read the safety note below)
Input
| Field | Meaning |
|---|---|
companies | Company identifiers: ats:slug, a board URL, a careers-page URL, or a bare slug. |
useSeedList, seedAts, seedLimit | Also scan the built-in directory (largest boards first). |
keywords, excludeKeywords, keywordScope | Keyword filters. Scope is title or title_and_description. |
countries, includeUnknownCountry | Country filter. Jobs with an unknown country are dropped unless you opt in. |
remoteOnly, departments, postedWithinDays | Remote, department and recency filters. Jobs with no posting date are kept. |
sinceLastRun, stateKey, includeRemoved | Change tracking. stateKey lets you keep independent watch-lists. |
descriptionFormat | text, html, both or none. |
parseSalary, fetchGreenhousePayRanges | Salary options. Greenhouse's official pay ranges need one extra request per job. |
maxJobs, maxJobsPerCompany | Hard caps. Use these to bound your cost. |
maxConcurrency, perHostConcurrency | Throughput controls. The defaults are polite. |
Example input
{"companies": ["greenhouse:figma", "lever:spotify", "ashby:ramp", "smartrecruiters:Equinox", "https://apply.workable.com/huggingface/"],"keywords": ["engineer", "manager"],"fetchGreenhousePayRanges": true,"maxJobsPerCompany": 25,"maxJobs": 100}
Example: weekly "what's new" feed for a watch-list
{"useSeedList": true,"seedAts": ["greenhouse", "ashby"],"seedLimit": 300,"keywords": ["data engineer", "machine learning"],"countries": ["US", "CA"],"sinceLastRun": true,"stateKey": "weekly-data-roles"}
Workday
Workday career sites live at https://<tenant>.<wdN>.myworkdayjobs.com/<site>. Give the Actor that URL (a localised /en-US/ part or a link to a single job is fine) or the explicit form workday:<tenant>.<wdN>.<site>:
{"companies": ["workday:nvidia.wd5.NVIDIAExternalCareerSite","https://salesforce.wd12.myworkdayjobs.com/en-US/External_Career_Site"],"countries": ["US"],"maxJobsPerCompany": 100}
Or scan the bundled directory of about 215 verified Workday employers: {"useSeedList": true, "seedAts": ["workday"], "seedLimit": 20}.
What to know:
- Slug format. A Workday slug is
tenant.wdN.site, for examplenvidia.wd5.NVIDIAExternalCareerSite. The site name is case-sensitive. The easiest way to get it is to open the company's careers page and paste its URL. - Bare names are not guessed.
nvidiaon its own is never tried against Workday, because Workday needs the data-centre and site name too. - More than 2,000 jobs. Workday returns at most 2,000 results per query. For bigger tenants the Actor splits the search by job family, time type and similar filters, so it can return, for example, 2,700 NVIDIA jobs. If a tenant is over the cap and offers nothing to split on, you get the first 2,000, and
sinceLastRundoes not infer removals for it. - Dates. The list only says "Posted 3 Days Ago". The Actor reads the exact start date from each job's detail page.
- Locations. Where the list says "2 Locations", the real locations are read from the job's detail page when you use the
countriesfilter. - Department and team are not published in the list, so they are empty for Workday jobs. A
departmentsfilter therefore excludes Workday jobs; usekeywordsinstead. - Change tracking ignores description edits for Workday (as for SmartRecruiters), because descriptions are fetched per job. Title, location and similar changes are tracked.
- Not covered: career sites on
myworkdaysite.comand employers that run their own login-only Workday. - Be gentle. Requests are paced, Workday's throttling replies (403/429) are retried with backoff, and a failing tenant never stops the run. The paging approach for Workday's 2,000-result cap follows kalil0321/ats-scrapers (MIT licence). The code is original.
Output
One item per job. See samples/output_sample.json for real examples from the original five systems. Workday jobs use the same fields.
{"id": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245","ats": "ashby","companySlug": "ramp","companyName": "Ramp","jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245","title": "Security Engineer, Cloud","url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245","applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application","department": "Engineering","team": "Backend","employmentType": "full_time","workplaceType": "hybrid","isRemote": false,"locations": ["New York, NY (HQ)","Remote (Canada)","Remote (US)","Miami, FL"],"primaryLocation": "New York, NY (HQ)","countryCodes": ["US","CA"],"postedAt": "2026-04-07T17:12:35Z","updatedAt": null,"salary": {"min": 211400,"max": 290600,"currency": "USD","period": "year","source": "structured","text": "$211.4K - $290.6K","annualMin": 211400,"annualMax": 290600},"changeType": "current","firstSeenAt": null,"scrapedAt": "2026-10-27T20:49:52Z","contentHash": "34e27a814cf94819","descriptionText": "About Ramp\n\nRamp is building the smart infrastructure for finance teams, embedded in the transaction flow of every dolla…"}
employmentTypeis one offull_time,part_time,contract,temporary,intern,other(or null).changeTypeiscurrent(no tracking), ornew,updated,removed(tracking on).removedrecords carry only identity fields (id, title, url, firstSeenAt).firstSeenAtis only filled when change tracking is on.contentHashchanges when the job's meaningful content changes. Timestamps are ignored.- Export as JSON, CSV, Excel, XML or via API. The dataset has two views, Overview and Salaries.
Pricing (pay per event)
You pay only for results. There is no monthly rental.
| Event | Price | When |
|---|---|---|
| Actor start | $0.00005 | once per run |
| Job | $0.0015 (i.e. $1.50 per 1,000) | each job delivered |
| Salary parsed | $0.0005 | each job where a salary range was found (optional, parseSalary) |
| Removed job | $0.0005 | each "removed" record (only with change tracking) |
Platform usage (compute) is included. Rough example: 1,000 jobs from Ashby and Greenhouse boards, about half with a salary, cost about $1.50 + $0.25 = $1.75. A weekly change-tracking run over 300 boards usually delivers only the few hundred jobs that changed.
Tip: set maxJobs to cap spend. The Actor stops cleanly when your per-run spending limit is reached.
How change tracking works
With sinceLastRun: true, the Actor keeps a compact fingerprint of each company's jobs in a named key-value store (multi-ats-jobs-state, under your stateKey). On the next run it compares fingerprints and outputs only:
new: not seen beforeupdated: title, location, department, type or description changedremoved: was listed last time and is gone now
A company that fails to load in a run is skipped without touching its state, so a temporary error never creates false "removed" records. If a company is cut off by maxJobsPerCompany, removals are not inferred for it.
FAQ
How much does it cost? About $1.50 per 1,000 jobs, plus $0.50 per 1,000 jobs where a salary range was parsed, and a $0.00005 start fee. Example: 25 jobs cost under $0.05. Set maxJobs to cap spend.
Do I need to know which ATS a company uses? No. Paste the company's careers-page URL and the Actor detects the ATS behind it. If you know it, greenhouse:figma style entries are faster.
Can I get only new jobs? Yes. Turn on sinceLastRun and schedule the Actor. You get new, updated and removed jobs only.
Is this allowed? It reads the public job-board endpoints that Greenhouse, Lever, Ashby, SmartRecruiters, Workable and Workday publish so that companies can show jobs on their own sites. It does not log in, bypass protections, or touch private data. You are responsible for how you use the data. Respect the terms of the employers and platforms, and applicable data-protection law. Job postings are published by the employer, and the data contains no candidate information.
Why is a company missing or "not_found"? The slug is wrong, the company doesn't use that ATS, or its board is empty. Try the careers-page URL and the Actor will detect the ATS. The built-in directory is community-sourced and can go stale. Stale entries are reported, not fatal.
Is salary always present? No. Many postings don't publish pay. Where they do, we extract it. Currency is taken from the symbol or code next to the numbers. A bare $ is reported as USD even for CAD/AUD postings unless a code is written next to the number. No FX conversion is done.
Which countries? Country codes are inferred from the location text (US states and Canadian provinces, country names, common cities) and from ATS fields where available. This is best effort. Filter with includeUnknownCountry if you don't want to lose jobs where it can't be inferred.
What about Recruitee, Personio, iCIMS, etc.? Not covered yet.
Speed? Greenhouse, Ashby and Workable return a whole board in one request. SmartRecruiters needs one extra request per job for the description. Lever can be slower on large boards. Workday lists 20 jobs per request and needs one extra request per delivered job for the description and exact date, so a 1,500-job tenant takes about 15 s to list and about 2.5 minutes with descriptions (Cisco, 1,529 jobs: 162 s). Use maxJobsPerCompany or descriptionFormat: none for quick runs. In our tests, 100 boards (up to 25 jobs each) took 13 to 47 seconds, and SmartRecruiters took about 90 seconds because of the per-job requests.
Important: job text is untrusted data
Descriptions are written by third parties. The Actor strips scripts, iframes, event handlers and unsafe links from HTML, and converts to plain text by default. But if you feed the output to an LLM or an autonomous agent, treat every description as data, never as instructions. A posting could contain text such as "ignore previous instructions". Keep it out of your system prompt, and don't give an agent that reads this data tool access you wouldn't give an anonymous stranger.
Run locally
python -m venv .venv && . .venv/bin/activatepip install -r requirements.txt pytest pytest-asynciopython -m pytest # offline tests against recorded ATS responsesmkdir -p storage/key_value_stores/defaultcp samples/input.json storage/key_value_stores/default/INPUT.jsonACTOR_TEST_PAY_PER_EVENT=true apify run # apify-cli; results land in ./storage
ACTOR_TEST_PAY_PER_EVENT=true logs charge events to a local charging-log dataset instead of billing.
To refresh the directory: python -m tools.verify_slugs <ats> candidates.json out.json, then python -m tools.build_seed (see tools/).