ATS Jobs Scraper — Greenhouse, Lever, Ashby, Workday & more
Pricing
from $1.30 / 1,000 jobs
ATS Jobs Scraper — Greenhouse, Lever, Ashby, Workday & more
[💵 $2.00 / 1K] Scrape open jobs across 11 ATS platforms — Greenhouse, Lever, Ashby, Workday & more — in one unified schema. Auto-detects the ATS from a plain company domain. Monitoring mode returns only new jobs since your last run. For n8n, Make, Zapier & MCP. Official public APIs only.
Pricing
from $1.30 / 1,000 jobs
Rating
0.0
(0)
Developer
Dataloft Studio
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
5 days ago
Last modified
Categories
Share
ATS jobs scraper for Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor, BambooHR and Rippling — every posting pulled through the platform's own public API, normalised into one schema. Give it a board URL, or just a company website and it finds the board for you. Works with n8n, Make, Zapier, the Apify API and as an MCP tool for AI agents.
What is the ATS Jobs Scraper?
Most job data on the internet is second-hand: aggregated, re-listed, days stale. This scraper goes to the source. Every posting comes from the applicant tracking system the company actually publishes to, which means you get the role when the source API exposes it, with the real requisition ID and the real apply link.
It reads 11 ATS platforms through their official public endpoints. No login, no cookies, no browser automation, no proxies needed, no personal data — job postings only.
What data can you extract from Greenhouse, Lever, Ashby and Workday?
Every posting is normalised into one flat schema, so a Greenhouse role and a Workday role look identical to your code.
Output fields
| Field | Notes |
|---|---|
title, company, companySlug | |
atsPlatform | which system it came from |
department, team, employmentType, seniority | when the platform exposes them |
location, locations[], country, isRemote | isRemote is inferred when the ATS has no explicit flag |
compensation | {min, max, currency, interval} — structured where published, parsed from text otherwise |
descriptionHtml, descriptionText | full posting, both formats |
applyUrl, jobUrl, companyCareerUrl | |
postedAt, updatedAt, scrapedAt | ISO 8601 |
source, sourceUrl | exact endpoint the row came from |
Example output JSON
{"title": "Senior / Staff Fullstack Engineer","company": "Linear","atsPlatform": "ashby","department": "Product","team": "Engineering","employmentType": "FullTime","location": "Europe","isRemote": true,"compensation": null,"descriptionText": "At Linear, we're building the product development system for teams…","applyUrl": "https://jobs.ashbyhq.com/linear/d3bc1ced-…/application","postedAt": "2026-04-27T20:13:45.158Z","scrapedAt": "2026-08-25T19:14:15.176Z"}
Which ATS platforms are supported?
| Platform | Board looks like | Notes |
|---|---|---|
| Greenhouse | job-boards.greenhouse.io/acme | full description included |
| Lever | jobs.lever.co/acme | structured salary when published |
| Ashby | jobs.ashbyhq.com/acme | structured compensation tiers |
| Workday | acme.wd5.myworkdayjobs.com/SiteName | site ID optional — it is probed for you |
| SmartRecruiters | careers.smartrecruiters.com/Acme | company ID is case-sensitive |
| Workable | apply.workable.com/acme | |
| Recruitee | acme.recruitee.com | |
| Personio | acme.jobs.personio.de | .de and .com both handled |
| Teamtailor | acme.teamtailor.com | RSS feed, capped at 100 by the platform |
| BambooHR | acme.bamboohr.com/careers | |
| Rippling | ats.rippling.com/acme/jobs |
A valid board with no open roles returns zero rows rather than an error — that is the platform's answer, not a failure.
Why JazzHR is not supported
JazzHR's feed endpoint returns HTTP 200 with a "page not found" HTML body, and its sibling feed paths answer 410 Gone. A scraper that trusts the status code turns that into rows of nothing. It was tested across 180 tenants and removed rather than shipped as a silent data leak. If you need JazzHR, it has to be HTML parsing with real maintenance — open an issue and say so.
How to scrape jobs from a company domain (no board URL needed)
The part people usually have to do by hand is finding the board. You do not.
Put stripe.com in Company websites and the scraper reads the careers page, spots the ATS behind it, verifies the board actually serves jobs, and pulls everything. If no link is visible it falls back to probing each platform's public API with the obvious slug. In testing, plain domains resolved for 8 of 10 well-known companies — including one that had been acquired and moved onto its parent's board. A target list of 200 companies is a single run instead of 200 manual lookups.
Step-by-step
- Paste board URLs into Job board URLs, company websites into Company websites, or both.
- Add filters if you want a slice rather than everything — title, location, department, keyword, posted-after, remote-only.
- Set Max jobs in total on your first run so you can see the shape of the output before scraping at scale.
- Run it, then export as JSON, CSV or Excel, or pull it from the API.
API target requirement
API callers must supply boards or companyDomains (or their supported aliases). The Console prefilled form is an example, not an implicit target list for an empty API request. A raw POST with no target is rejected with a clear input error and no job-result event; the small Actor-start fee may still apply. In the 2026-09-05 cloud check, the runtime did not substitute the saved exampleRunInput for a missing request body. Copy the complete JSON example when integrating.
Example input JSON
{"boards": ["https://job-boards.greenhouse.io/airbnb","https://jobs.ashbyhq.com/openai","https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],"companyDomains": ["stripe.com", "figma.com"],"titleIncludes": ["engineer", "developer"],"locationIncludes": ["remote", "berlin"],"postedAfter": "2026-08-01","maxTotalJobs": 500}
Board URLs work in whatever form you copied them — job-boards.greenhouse.io/acme, boards.greenhouse.io/embed/job_board?for=acme, jobs.lever.co/acme, acme.recruitee.com, acme.jobs.personio.de, a Workday URL with or without the site ID. You can also write greenhouse:acme if you already know the slug.
Input aliases from other ATS scrapers
Input copied from another ATS actor runs here unchanged: companies, companyUrls, startUrls and queries are accepted as aliases and merged into the board and domain lists. Switching costs you nothing.
Monitoring mode: get only new jobs since your last run
The first successful run delivers a baseline of the matching postings within your scan limits. Later runs with Only new jobs since last run skip previously delivered identities. This is an unseen-record feed, not proof that a job was first published yesterday, changed, or closed.
Use a distinct Seen-jobs store name per watchlist and run only one task at a time against that store. Named key-value storage has no atomic cross-run lock; do not overlap schedules. Scan/output caps can limit coverage. If history cannot be read or persisted, or a previous delivery is unresolved, monitoring fails visibly instead of silently treating everything as new. Inspect RUN_SUMMARY and the saved pending-delivery record before retrying; do not delete history to bypass a reconciliation error.
How much does it cost to scrape ATS job boards?
$2.00 per 1,000 jobs. You are charged per job actually saved to your dataset, so filtered-out postings, duplicates and previously-seen postings in monitoring mode cost nothing. A run that scans 5,000 listings and matches 40 charges for 40. No matching result incurs a job event, but the configured Actor-start fee is $0.00005 per GB of memory, including on an empty run (one event at the 1 GB default).
Cost examples
Illustrative result-event charges at the base tier; not measured demand or recurring revenue. Add the small Actor-start fee described above. Actual available matches vary.
| What you run | Rows charged | Cost |
|---|---|---|
| 20 companies, everything open, ~40 roles each | 800 | $1.60 |
| Same 20 companies daily in monitoring mode, ~2% churn | ~16 per day | ~$0.03 per day, ~$1.00 per month |
| Engineering roles only across 200 companies, ~10 matches each | 2,000 | $4.00 |
| Full inventory of one large Workday board with descriptions | 1,500 | $3.00 |
Two ways to keep a first run cheap: set Max jobs in total, and turn Include full job descriptions off — descriptions are the slow part on Workday, which needs one extra request per posting.
Integrations: n8n, Make, Zapier, MCP and the API
Use with AI agents (MCP server)
Add the scraper as a tool in Claude Desktop, Cursor, or any MCP client through Apify's hosted MCP server:
$npx -y @apify/actors-mcp-server --actors dataloft/ats-jobs-scraper
Or point your client at https://mcp.apify.com with your Apify token and enable this actor. An agent can then answer "which of these 30 companies opened a senior data role this week?" directly.
n8n, Make and Zapier
Use the official Apify node (n8n), the Apify app (Make) or the Apify integration (Zapier): pick Run Actor, choose dataloft/ats-jobs-scraper, paste the input JSON above, and read the dataset items in the next step. Combined with monitoring mode this gives you a "new roles at my watchlist → Slack / Sheets / CRM" workflow in three nodes.
JavaScript, Python and REST
const { ApifyClient } = require('apify-client');const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('dataloft/ats-jobs-scraper').call({companyDomains: ['stripe.com', 'figma.com'],titleIncludes: ['engineer'],maxTotalJobs: 200,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(token=os.environ["APIFY_TOKEN"])run = client.actor("dataloft/ats-jobs-scraper").call(run_input={"companyDomains": ["stripe.com", "figma.com"],"maxTotalJobs": 200,})items = client.dataset(run["defaultDatasetId"]).list_items().items
REST: POST https://api.apify.com/v2/acts/dataloft~ats-jobs-scraper/run-sync-get-dataset-items with an Authorization: Bearer <APIFY_TOKEN> header with the input JSON as the body.
What this Actor does and does not do
| Does | Does not |
|---|---|
| Pull live postings from 11 ATS platforms via their public APIs | Scrape LinkedIn, Indeed or any site that forbids it |
| Find a company's board from a plain domain | Log in, solve CAPTCHAs, or bypass anti-bot systems |
| Normalise 11 response shapes into one schema | Collect candidate, recruiter or any personal data |
| Parse structured salary where published | Guess salaries that are not published |
| Return only new postings in monitoring mode | Apply to jobs on your behalf |
Limits and known caveats
- Teamtailor publishes an RSS feed capped at 100 postings per board by the platform.
- SmartRecruiters company IDs are case-sensitive; a wrong case returns an empty board, not an error.
- Workday reports the board total only on the first page; this scraper holds that total, but a Workday tenant with a fully custom site ID may need the full URL pasted in.
- Domain detection resolves most well-known companies (8 of 10 in testing). When it cannot, the run names the input it could not resolve instead of skipping it silently.
- Descriptions on Workday cost one extra request per posting — expect longer runs when Include full job descriptions is on for large boards.
- Rate limits are the platforms' own; the scraper retries with backoff and does not need a proxy for normal volumes.
Example tasks
Ready-made configurations — competitor hiring watchlists, daily new-role alerts, remote engineering roles from Greenhouse and Lever — are on the Example tasks tab of this actor: https://apify.com/dataloft/ats-jobs-scraper/examples
Is it legal to scrape ATS job boards?
This actor only calls endpoints the ATS platforms publish for public consumption — the same JSON your browser fetches when you open a company's careers page, and in several cases documented integration APIs. It collects job postings, which are company information, not personal data: no candidate records, no recruiter contact details, no email harvesting.
You are still responsible for how you use the output, including under GDPR and each platform's terms. If you plan to redistribute the data commercially, read those terms first.
Frequently asked questions
Can I scrape a company if I do not know its ATS? Yes — put the plain website in Company websites. If detection fails the run tells you which inputs it could not resolve instead of quietly skipping them.
Why did a board return zero jobs? Almost always because the company genuinely has no openings. Every supported platform answers 200 with an empty list for a valid-but-dormant board.
Does it work with Workday if I only have the company name? Yes. Workday site IDs like NVIDIAExternalCareerSite are probed from a list of naming patterns, so nvidia.wd5.myworkdayjobs.com alone is enough.
How fresh is the data? As fresh as the company's own careers page — you are reading the same source it renders from.
Can I run this on a schedule? Yes, use Apify Schedules. With Only new jobs since last run on, each run returns only what appeared since the previous one; with it off, deduplication still gives you a clean current snapshot.
Does monitoring mode cost extra? No. Previously-seen postings are skipped before anything is charged, so a stable watchlist costs a few cents a day.
Can I use it from n8n or as an MCP tool? Yes — see the Integrations section above. No code is needed for n8n, Make or Zapier.
What happens when a filter matches nothing? The log reports scanned N → matched 0 for that board, so you can tell the difference between "no matches" and "something broke".
Other job scrapers by Dataloft Studio
- Workday Jobs Scraper — the same Workday support, but deeper: search terms passed to Workday's own engine, site-ID discovery from a plain company website.
- Remote Jobs Aggregator — 7 remote-only job boards merged into one deduplicated feed.
Changelog
-
0.3 — 2026-09-05: monitoring fails visibly on history/delivery errors; budget-aware result charging and delivery reconciliation; published examples corrected and bounded.
-
0.2 — 2026-09-02: monitoring mode (only new jobs since last run, named seen-jobs store); input aliases
companies/companyUrls/startUrls/queries; memory capped at 1 GB (lower per-run platform cost); dataset schema and output schema aligned; changelog added. -
0.1.4 — 2026-08-25: fixed a concurrency race where Max jobs in total could be exceeded across parallel boards.
-
0.1.2 — 2026-08-25: output schema added; first-run prefill capped so daily automated tests finish under 5 minutes.
-
0.1 — 2026-08-25: initial release, 11 ATS platforms, domain-to-board detection.
Support and feedback
Issues and feature requests go in the Issues tab. Bug reports that include the input JSON get fixed fastest.