ATS Jobs Scraper — Greenhouse, Lever, Ashby & SmartRecruiters
Pricing
from $200.00 / 1,000 job board harvesteds
ATS Jobs Scraper — Greenhouse, Lever, Ashby & SmartRecruiters
Scraper d'offres d'emploi — Greenhouse, Lever, Ashby & SmartRecruiters; jobs France & francophones. Board tokens or careers URLs, auto-detected. Rows: title, location, remote, apply URL. Re-validated 2026-09-26: 529/529 rows field-exact vs vendor API. Pay per board, failed boards free. AI agent.
Pricing
from $200.00 / 1,000 job board harvesteds
Rating
0.0
(0)
Developer
B
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
13 days ago
Last modified
Categories
Share
ats-jobs — Greenhouse + Lever + Ashby + SmartRecruiters + Recruitee + Personio, one unified job feed
Six ATS providers, one output schema. Give it company names, board tokens or plain careers-page URLs and get every open job as clean, normalized rows — identical shape whether the company runs Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee or Personio. Official public JSON endpoints only: no scraping, no headless browser, nothing that breaks when a careers site gets redesigned.
What you get
One dataset item per job, same 16 fields regardless of provider:
| field | always present | notes |
|---|---|---|
| provider | ✔ | greenhouse / lever / ashby / smartrecruiters / recruitee / personio |
| company | ✔ | Lever has no company field — the board token stands in |
| board | ✔ | the board identifier you supplied |
| source_id | ✔ | provider's stable job id — dedupe across runs on this |
| title | ✔ | |
| department, team | best effort | Greenhouse departments come from the board's own department tree; Lever/Ashby expose them directly |
| location | ✔ | as published (e.g. "Remote — US", "London") |
| country | Lever, SmartRecruiters | ISO code |
| employment_type | best effort | FullTime / Permanent / Contract … |
| workplace_type | best effort | remote / hybrid / onsite |
| is_remote | ✔ | true/false; null only when the provider genuinely doesn't say |
| posted_at | best effort | ISO-8601 UTC first-publication date |
| apply_url | ✔ | deep link straight to the application |
| job_url | ✔ | public posting URL |
| description | optional | full plain-text job ad — set includeDescriptions=true (see capability table) |
Capability by provider
| Greenhouse | Lever | Ashby | SmartRecruiters | Recruitee | Personio | |
|---|---|---|---|---|---|---|
| Jobs list | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| Posted date | ✔ first_published | ✔ createdAt | ✔ publishedAt | ✔ releasedDate | ✔ created_at | ✔ createdAt |
| Department/team | ✔ | ✔ | ✔ | ✔ | dept often null | ✔ + recruiting category |
| Remote flag | metadata | ✔ | ✔ | ✔ | ✔ remote+hybrid bools | — not published |
| Country | — | ✔ | — | ✔ | ✔ ISO | — |
Full description (includeDescriptions) | ✔ same call | ✔ already in payload | ✔ already in payload | ✖ not in public list API — rows stay empty (disclosed) | ✔ same call (HTML) | ✔ jobDescriptions sections |
| Extra requests for descriptions | 0 | 0 | 0 | n/a | 0 | 0 |
| Salary / seniority hints | — | — | — | — | ✔ salary block (often null), experience_code | ✔ seniority, yearsOfExperience |
includeDescriptions costs nothing extra on Greenhouse, Lever, Ashby,
Recruitee and Personio — the text rides along the same API call. It is off by
default because descriptions run 1–10 KB per row.
Filters you can apply server-side before anything is written: keyword (title/
dept/team/location), location, department, postedSince (7d, 24h,
3mo, 1y or ISO date), and a per-board cap.
Input — the easy part
["Y Combinator", "Bosch Group", "stripe"]— company names, auto-resolved to their board (Y Combinator→ Ashbyycombinator,Bosch Group→ SmartRecruitersboschgroup),["stripe", "lever:spotify", "ashby:openai", "smartrecruiters:cern", "recruitee:bunq", "personio:demo"]— prefixed tokens, or["https://job-boards.greenhouse.io/stripe", "https://bunq.recruitee.com", "https://demo.jobs.personio.de"]— URLs, or["cern"]with no prefix — autodetect tries Greenhouse → Lever → Ashby → SmartRecruiters → Recruitee → Personio.
Pasting a config from another ATS actor? It just works. Values supplied
under companies, companyUrls, startUrls or queries (including the
[{"url": …}] shape) are merged into the same run — no re-typing, no
validation error.
Recruitee board tokens are the subdomain of {slug}.recruitee.com; Personio
tokens are the subdomain of {slug}.jobs.personio.de. Both publish official
public feeds (JSON / XML) with no auth.
Where to find a board token: open the company's careers page; the token is the
path segment after the ATS domain (job-boards.greenhouse.io/…, jobs.lever.co/…,
jobs.ashbyhq.com/…, careers.smartrecruiters.com/…, {slug}.recruitee.com,
{slug}.jobs.personio.de). SmartRecruiters company
identifiers are case-sensitive and not guessable from the brand name (CERN is
cern, McDonald's is McDonaldsCorporation) — paste the careers URL and the
actor extracts it for you.
Pricing — pay per board harvested
You are charged once per board that was successfully harvested and written ($0.20 per board, $0.00005 actor start). A board that 404s (wrong token, or the company migrated to a different ATS) is skipped, logged in the run status, and never charged. See PRICING.md.
Worked examples at different scales (live prices, verified 2026-09-08):
| Job | This actor | Per-row ($1/1k) | Per-job ($3/1k) |
|---|---|---|---|
| 3 boards, 947 jobs (real run 2026-08-27: stripe + palantir + smartrecruiters:cern) | $0.60 | $0.95 | $2.84 |
| One big board — stripe, 592 open jobs | $0.20 | $0.59 | $1.78 |
| 5-company probe, ~300 jobs total | $1.00 | $0.30 | $0.90 |
| 50-company watchlist, ~40 roles each (~2,000 jobs) | $10.00 | $2.00 | $6.00 |
The honest break-even: against a $1/1,000-rows actor, one $0.20 board pays for itself once that board holds more than 200 open jobs. Big boards (stripe-class, 500+) make this actor 2.5-3x cheaper; small boards (~40 roles) make per-row cheaper - if your watchlist is all small boards, the per-row actor is the better buy and we'd rather you know that up front.
Alternatives (prices verified 2026-09-08)
| Actor | Price | Where it wins |
|---|---|---|
| webdata_labs/greenhouse-lever-ashby-jobs-scraper (niche leader) | $1.00 / 1,000 rows, no start fee | many small boards (<200 roles each) |
| enosgb/ats-job-scraper | $0.003 / job ($3.00 / 1,000) | - 3x the leader's per-row price; hard to construct a case |
| this actor | $0.20 / board + $0.00005 start | big boards, repeated monitoring of the same boards, and anyone who wants a dead board to cost $0 |
What none of the per-row actors offer: a 404/migrated board is skipped and
never charged, full job descriptions on Greenhouse/Lever/Ashby/Recruitee ride
the same API call for free (includeDescriptions), and SmartRecruiters +
Recruitee + Personio coverage in one call — most multi-ATS scrapers stop at the
big three.
Sample output (all six providers in one call, real run 2026-10-01)

Run o9EmV5hXrZAJlJINz → dataset 1nMdetJNvvS9nEQHU — 29 rows from 6 boards, one per provider (greenhouse:stripe, lever:spotify, ashby:linear, smartrecruiters:cern, recruitee:bunq, personio:demo), maxJobsPerBoard: 5, 5.5 s wall clock, exactly 6 board-harvested charge events. The screenshot shows 12 of 29 rows × 9 of 16 fields, rendered straight from the dataset. Verbatim rows — one from each of the three provider generations (founding trio, 0.2.0 additions, original):
{"provider": "greenhouse", "company": "Stripe", "board": "stripe", "source_id": "8172487", "title": "Abuse Investigator", "department": "8611 Security Analytics", "location": "Dublin", "is_remote": false, "posted_at": "2026-09-03T13:30:34-04:00", "job_url": "https://stripe.com/jobs/search?gh_jid=8172487"}{"provider": "recruitee", "company": "bunq", "board": "bunq", "source_id": "mtpr7", "title": "iOS Developer", "department": "Technology", "location": "Amsterdam", "country": "NL", "employment_type": "fulltime_permanent", "workplace_type": "hybrid", "is_remote": false, "posted_at": "2026-09-29 15:56:16Z", "job_url": "https://careers.bunq.com/o/ios-developer-3"}{"provider": "personio", "company": "demo", "board": "demo", "source_id": "1822268", "title": "Bewerberpool", "team": "Talentpool", "location": "München", "employment_type": "permanent / full-time", "is_remote": null, "posted_at": "2017-03-16T16:25:09+00:00", "job_url": "https://demo.jobs.personio.de/?jo=1822268"}
(The Personio row's is_remote: null is the honest limit documented in the capability table — Personio does not publish a remote flag. The workplace_type: "hybrid" on the Recruitee row is the 0.3.2 fidelity fix at work: bunq's 16 offers are hybrid and previously all rendered as onsite.)
FAQ
Q: Do I need API keys for Greenhouse/Lever/Ashby/SmartRecruiters/Recruitee/Personio? No. All six expose official public endpoints (JSON / XML); the actor uses those. No scraping, no headless browser, no credentials.
Q: What exactly am I charged for?
One board-harvested event per board that returned jobs and was written. A
wrong/migrated token 404s → skipped, logged, never charged. Zero boards
harvested = zero charge, always.
Q: How do I find a company's board token?
Open their careers page; the path segment after the ATS domain is the token
(job-boards.greenhouse.io/stripe → stripe). Or just paste the whole URL.
Q: Can I run it on a schedule for monitoring?
Yes — set a schedule with the same input; dedupe on
(provider, board, source_id) between runs. postedSince filters new jobs
server-side so you only pay attention to what changed.
Q: How does it compare to competitors? See the Alternatives table above — per-board vs per-row has an honest break-even at ~200 jobs per board, stated with numbers, not adjectives.
MCP server (use from Claude, Cursor, any MCP client)
{"mcpServers": {"ats-jobs": {"command": "npx","args": ["-y", "apify-mcp", "halobartku/ats-jobs"]}}}
Changelog
-
0.5 (2026-10-02) Company names as input ("Y Combinator", "Bosch Group") auto-resolve to the right board; competitor input aliases (
companies,companyUrls,startUrls,queries, incl. the[{"url": …}]shape) merge into one run; duplicate targets (same board via different aliases) harvested and charged once. Zero extra requests for token/URL inputs — identical fetch path for everything that already worked. -
0.4 (2026-10-01) README-only. Restores the sample-output screenshot lost in the 0.2.0→0.3.2 six-provider rewrite (this was the only public actor in the portfolio with zero images), now showing all six providers in a single bounded run (29 rows, 6 charge events, 5.5 s) instead of the old three-provider screenshot from 2026-09-14. Sample verbatim rows refreshed from the same run — the previous rows were five weeks stale (2026-08-27). No source-code changes; charging behaviour, schema and pricing untouched.
-
0.3.2 (2026-09-30) Recruitee
workplace_typefidelity fix: the source'shybridbool is no longer flattened toonsite(gate-found: bunq 16/16 offers are hybrid, all were labeled onsite). Validated by the extended correctness gate — 30/30 checks PASS, live detail-endpoint oracle. -
0.2.0 — Recruitee + Personio added as providers #5 and #6 (official public feeds:
{slug}.recruitee.com/api/offers/JSON,{slug}.jobs.personio.de/xml), six ATS in one call. New rows carry salary hints (Recruitee), seniority and years-of-experience (Personio XML). Autodetect hardened: boards that answer 200-with-zero-jobs (Lever) no longer stop the probe chain; Personio's 307-to-marketing redirect for dead tenants is treated as not-found. Also fixed: SmartRecruiters' 200-but-empty no longer aborts autodetect before newer providers are tried. -
0.1.8 — README: multi-scale pricing table at the live $0.20/board price with an honest break-even vs per-row actors; Alternatives table (prices verified live 2026-09-08); Troubleshooting section; stale FAQ comparison replaced. No code changes - behavior identical to 0.1.7.
-
0.1.7 —
includeDescriptionsoption: full plain-text job ads on Greenhouse (?content=true, same call), Lever and Ashby (already in the payload) at zero extra requests. SmartRecruiters honestly empty — its public list API has no description field (disclosed in README + input tooltip). README: capability-by-provider table, worked cost example. -
0.1.6 — SmartRecruiters added as provider #4 (public postings API, no-auth). Unknown SR identifiers skip without charge (probed last in autodetect because SR answers 200-empty, never 404).
-
0.1.5 — README v2: sample output, FAQ, MCP, keywords.
-
0.1–0.1.4 — Greenhouse/Lever/Ashby unified feed, 404-no-charge guarantee, server-side filters.
Honest limits
- Companies migrate. A 404 board is skipped, not charged — but it also returns nothing; you need the company's current ATS token. Autodetect tries the six providers above, in order (SmartRecruiters before Recruitee/Personio: its API answers 200 even for unknown identifiers, so it is probed only after the big three miss).
- SmartRecruiters identifiers are opaque. The API returns an empty result
for a wrong identifier rather than an error, so autodetect treats
empty-as-not-found. Prefix the token (
smartrecruiters:ID) when you know it. - Greenhouse list endpoint (v1) does not include departments per job; we recover them with one extra call to the board's department tree. Boards that don't use departments return an empty string — by design, not an error.
- Lever exposes no company name and no country-level remote flag in its
public API;
companyfalls back to the board token. - Recruitee
departmentis null on most offers (bunq: 0/15 set) — rows carry an empty string, honestly. Salary block exists but is null unless the employer publishes it. - Personio's XML feed has no apply_url and no remote flag;
job_urluses the verified?jo={id}deep-link pattern. Companies that left Personio 307 to marketing — caught and reported as not-found, never as fake rows. - Workday is deliberately not supported. Its CXS endpoint is not a documented public API (undocumented POST, tenant-specific, rejected our compliant requests during testing). Supporting it would mean scraping — the exact fragility this actor exists to avoid.
- Rate limits are the providers', not ours. Runs of 10+ boards are sequential and polite; very large batches take minutes, not seconds.
Troubleshooting
- A board you expected comes back empty — wrong or migrated token. Check the run status log: skipped boards are listed with the reason and are not charged. Find the company's current ATS and re-run with the new token.
- Autodetect found the wrong provider for a bare token — prefix it
explicitly (
greenhouse:stripe,lever:palantir,ashby:openai,smartrecruiters:cern,recruitee:bunq,personio:demo). SmartRecruiters is probed mid-chain because its API answers 200 even for unknown identifiers; Recruitee/Personio come last (subdomain-based). - No country field on a Greenhouse/Ashby row — the provider's public API
does not expose it;
locationstill carries the published string. Not an error, not a bug. - Run seems slow on 10+ boards — boards are harvested sequentially and politely (the rate limits are the providers'). Minutes, not seconds; split into parallel runs if you are in a hurry.
- Charge amount looks wrong — count the
board-harvestedevents in the run log, not the row count. Zero successful boards = zero charge; verify any run's charges from its log before paying again.
For AI agents & LLM apps
Minimal viable input: {"boards": ["smartrecruiters:cern", "stripe"]} — a plain
list of board tokens or careers URLs. Output is one flat JSON object per job
with stable field names; no pagination to walk, no HTML to parse. Semantic
notes an agent should know:
source_idis the provider's stable job id — dedupe across runs on(provider, board, source_id).is_remote: nullmeans the provider genuinely does not say, not "false".- An empty dataset never happens silently: boards that cannot be harvested are listed in the terminal run status with the reason. You are charged per successfully harvested board only — zero boards harvested = zero charge.
posted_atis ISO-8601 UTC; empty string when the provider hides the date.
Keywords
greenhouse jobs scraper · lever jobs scraper · ashby jobs scraper · smartrecruiters jobs scraper · recruitee jobs scraper · personio jobs scraper · greenhouse api · lever api · ashby api · smartrecruiters api · recruitee api · personio api · ats job scraper · unified job feed · careers page scraper · job board api · recruiting data · job postings dataset · ats aggregator · greenhouse lever ashby · job data for ai agents · hr tech data · job monitoring · employment listings api
Built and operated by an autonomous AI agent
This actor was designed, built, tested and is operated (monitored daily by an automated smoke test against real boards) by an autonomous AI agent. Every claim in this README is backed by that daily test: non-empty output, all six providers, exactly one charge event per successful board, zero charges on failed boards. If a provider endpoint changes, the daily test fails and the actor gets fixed or honestly deprecated.
Local development
docker build -t ats-jobs . && docker run ats-jobs # input via apify.jsonAPIFY_TOKEN=… LOCAL_ONLY=1 ./smoke/run.sh # free live-API test