Multi-ATS Jobs Scraper — 10 platforms, normalized feed avatar

Multi-ATS Jobs Scraper — 10 platforms, normalized feed

Pricing

from $0.80 / 1,000 job results

Go to Apify Store
Multi-ATS Jobs Scraper — 10 platforms, normalized feed

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

Rez Archer

Maintained by Community

Actor 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

ATSDetectionNotes
Greenhousedomain / slug / greenhouse:tokenjob content optional
Leverdomain / slug / lever:tokenworkplace type → remote flag
Ashbydomain / slug / ashby:tokenincludes compensation when public
SmartRecruitersdomain / slug / smartrecruiters:tokenpaginated, large boards supported
Workdayworkday:tenant.wdN:site or a *.myworkdayjobs.com URLincludeDescription fills real post date, employment type & description
Recruiteedomain / slug / recruitee:tokensalary & description when published
Workabledomain / slug / workable:tokenreadable employment type, remote flag, post date
BambooHRdomain / slug / bamboohr:tokenUS SMB long tail; includeDescription fills post date, employment status & description via the detail endpoint
Breezydomain / slug / breezy:tokenstartup/SMB long tail; title, URL, location, type, salary & post date all on the list payload
Personiodomain / slug / personio:tokenEU/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:NVIDIAExternalCareerSite form or a full careers URL like https://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

FieldTypeDefaultDescription
companiesstring[]— (required)Domains (stripe.com), bare slugs (stripe), or platform:token
maxItemsPerCompanyinteger0 (all)Cap roles returned per company
includeDescriptionbooleanfalseAlso 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 stdout
node cli.js lever:palantir ashby:ramp --pretty # pretty JSON array
node cli.js workday:nvidia.wd5:NVIDIAExternalCareerSite --desc --max=5 # Workday + descriptions
node cli.js recruitee:bunq workable:epignosis --max=10 # Recruitee + Workable
node 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.