Multi-ATS Jobs Scraper — 10 platforms, normalized feed
Pricing
from $0.80 / 1,000 job results
Multi-ATS Jobs Scraper — 10 platforms, normalized feed
Give company domains (stripe.com) and get normalized, deduped postings across 10 ATS platforms: Greenhouse, Lever, Ashby, SmartRecruiters, Workday, Recruitee, Workable, BambooHR, Breezy, Personio. Auto-detects each company's ATS — no board slugs. Keyless. Pay per event, priced per job.
Pricing
from $0.80 / 1,000 job results
Rating
0.0
(0)
Developer
Rez Archer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 hours ago
Last modified
Categories
Share
Multi-ATS Jobs Scraper — Greenhouse, Lever, Ashby, SmartRecruiters, Workday, Recruitee, Workable, BambooHR, Breezy & Personio
Give it company domains and get back normalized, deduplicated job postings across ten applicant-tracking systems — in one consistent schema. No board slugs to look up, no per-ATS integration to maintain on your side.
Input: ["stripe.com", "ramp.com", "lever:palantir"]Output: one clean row per open role, same fields regardless of which ATS the company uses
Why this instead of a single-ATS scraper
Every company hosts its careers page on a different ATS, and they migrate between vendors, rename boards, and the ATS APIs change shape without notice. This actor absorbs that churn for you:
- Auto-detects the ATS from a plain domain (
stripe.com→ Greenhouse) — you don't need to know or track which vendor each company uses. - One normalized schema across all platforms, so downstream code never branches per-ATS.
- Maintained adapters — when a platform changes its response, the adapter is updated centrally;
you don't re-write your scraper. This isn't a promise on a page: a built-in schema-drift
monitor (
npm run freshness) probes every adapter against a large known-good board on a schedule and flags the exact platform the moment a feed stops returning rows or drops a key field (title / URL / id) — so breakage is caught and patched upstream, usually before it reaches your runs.
Supported platforms
| ATS | Detection | Notes |
|---|---|---|
| Greenhouse | domain / slug / greenhouse:token | job content optional |
| Lever | domain / slug / lever:token | workplace type → remote flag |
| Ashby | domain / slug / ashby:token | includes compensation when public |
| SmartRecruiters | domain / slug / smartrecruiters:token | paginated, large boards supported |
| Workday | workday:tenant.wdN:site or a *.myworkdayjobs.com URL | includeDescription fills real post date, employment type & description |
| Recruitee | domain / slug / recruitee:token | salary & description when published |
| Workable | domain / slug / workable:token | readable employment type, remote flag, post date |
| BambooHR | domain / slug / bamboohr:token | US SMB long tail; includeDescription fills post date, employment status & description via the detail endpoint |
| Breezy | domain / slug / breezy:token | startup/SMB long tail; title, URL, location, type, salary & post date all on the list payload |
| Personio | domain / slug / personio:token | EU/DACH SMB long tail; deterministic /job/{id} URLs; .com host with .de fallback |
Workday target format. Workday boards are tenant-specific, so pass either the compact
workday:nvidia.wd5:NVIDIAExternalCareerSiteform or a full careers URL likehttps://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite— the actor parses the tenant, data-center (wdN) and site out of it automatically.Recruitee / Workable / BambooHR / Breezy / Personio take a plain company slug (
recruitee:bunq,workable:epignosis,bamboohr:greenhousejuice,breezy:there-is-talent,personio:merantix) and are also covered by domain auto-detection.
Input
| Field | Type | Default | Description |
|---|---|---|---|
companies | string[] | — (required) | Domains (stripe.com), bare slugs (stripe), or platform:token |
maxItemsPerCompany | integer | 0 (all) | Cap roles returned per company |
includeDescription | boolean | false | Also return plain-text job description |
Output (one row per role)
{"id": "8172510","title": "Abuse Investigator","company": "stripe","department": "Risk","team": null,"location": "Seattle, San Francisco, New York City","remote": null,"employment_type": "Full-time","salary": "$211.4K – $290.6K","url": "https://stripe.com/jobs/search?gh_jid=8172510","posted_at": "2026-09-09T14:50:29.000Z","updated_at": "2026-10-22T13:17:09.000Z","source_platform": "greenhouse","source_token": "stripe"}
Fields are identical across all ten ATS platforms. Dates are ISO-8601. A RESOLUTIONS record in
the run's key-value store shows which input resolved to which ATS (and any that didn't resolve).
Pricing
Pay per event — $0.80 per 1,000 jobs returned. You pay only for rows you receive; failed or unresolved companies cost nothing. (Comparable multi-ATS actors charge $1.00–$1.50 / 1,000.) Billing is event-based, so autonomous agents can call and pay for this actor per request.
Example
# via the Apify API (replace TOKEN)curl -X POST "https://api.apify.com/v2/acts/USERNAME~multi-ats-jobs-scraper/run-sync-get-dataset-items?token=TOKEN" \-H "Content-Type: application/json" \-d '{"companies":["stripe.com","ramp.com","lever:palantir"],"maxItemsPerCompany":50}'
Run it locally (no account needed)
The same engine ships as a standalone CLI — clone the repo and run it directly:
node cli.js stripe.com ramp.com --max=25 # NDJSON to stdoutnode cli.js lever:palantir ashby:ramp --pretty # pretty JSON arraynode cli.js workday:nvidia.wd5:NVIDIAExternalCareerSite --desc --max=5 # Workday + descriptionsnode cli.js recruitee:bunq workable:epignosis --max=10 # Recruitee + Workablenode cli.js bamboohr:greenhousejuice --desc --max=5 # BambooHR + descriptions
Flags: --max=N (cap per company), --desc (include description text), --pretty.
The same CLI is also published standalone (zero dependencies, zero API keys) and runnable without cloning this repo:
$npx github:rezearcher/ats-jobs-scraper-cli stripe.com ramp.com --max=25
Source: https://github.com/rezearcher/ats-jobs-scraper-cli
Reliability & self-maintenance
ATS feeds change shape without notice — a renamed field quietly makes a scraper return rows with blank titles or URLs; a moved endpoint makes it return nothing while still "succeeding." A plain "did it run?" check misses both. This actor ships a drift monitor that treats each adapter as a health signal:
$npm run freshness # probe every adapter against a known-good live board
For each platform it verifies the endpoint is reachable, the canary board is still
populated (≥1 row), and the rows still carry the key fields (id, title, url) above a 90%
presence threshold. It prints a verdict table (OK / DOWN / EMPTY / SCHEMA_DRIFT), writes a
machine-readable status file, and exits non-zero on any drift so a scheduler can open a maintenance
task automatically. That loop is why the adapters stay current — the upkeep is the product.
Notes
- Reads only public, keyless career-board endpoints that each company already publishes.
- Respects the cap you set; large boards are paginated safely.