ATS Jobs Scraper — Greenhouse + Lever + Ashby (Unified) avatar

ATS Jobs Scraper — Greenhouse + Lever + Ashby (Unified)

Pricing

from $2.00 / 1,000 results

Go to Apify Store
ATS Jobs Scraper — Greenhouse + Lever + Ashby (Unified)

ATS Jobs Scraper — Greenhouse + Lever + Ashby (Unified)

Scrapes public job postings from Greenhouse, Lever, and Ashby company boards and normalizes them into one consistent schema.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

Conor G

Conor G

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 hours ago

Last modified

Share

ATS Jobs Scraper — Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Personio, BambooHR

Scrape live job postings from any company that publishes its careers page on Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Personio, or BambooHR — nine of the most common applicant tracking systems — and get them back in one consistent, normalized schema. Give it a list of company names or career page URLs; it figures out which ATS (or ATSes) each company uses and pulls every open role.

Why this actor

Most job-board scrapers on the Store are built for a single ATS. A real target list — especially outside big US tech — spans several of these platforms, and stitching together different output shapes from separate actors gets old fast. This actor:

  • Covers nine platforms in one run, one schema, one dataset.
  • Talks only to each platform's public, unauthenticated JSON (or XML, for Personio) API — no browser rendering, no HTML scraping, no cookies. That means it's fast, cheap to run, and far less likely to break when a company redesigns its careers page.
  • Auto-detects which platform a company is on when you give it a bare name, or trusts your input outright when you give it a direct board URL.
  • De-duplicates postings (by platform + job ID, so a company that happens to be found on two platforms never produces duplicate rows) and gives you a clear per-company status report (found where, how many jobs, and why a company came back empty) so you're never left guessing.

What it scrapes

PlatformEndpoint usedBare-slug auto-detect
Greenhouseboards-api.greenhouse.io/v1/boards/{slug}/jobsYes
Leverapi.lever.co/v0/postings/{slug}Yes
Ashbyapi.ashbyhq.com/posting-api/job-board/{slug}Yes
SmartRecruitersapi.smartrecruiters.com/v1/companies/{slug}/postingsYes
Workableapply.workable.com/api/v1/widget/accounts/{slug}Yes
Recruitee{slug}.recruitee.com/api/offers/Yes
Personio{slug}.jobs.personio.de/xmlYes
BambooHR{slug}.bamboohr.com/careers/listYes
Workday{tenant}.{shard}.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobsNo — paste a board URL

These are the same public feeds each platform's own embeddable job widget uses — they're meant to be read programmatically, are not authentication-gated, and are stable across a company's own page redesigns.

Workday has no guessable bare-slug shape. A Workday board URL encodes a tenant, a site name, and a shard (wd1, wd3, wd5, ...) that are all independent of each other and of the company's name, so there's nothing to probe from a bare company name. Paste the board URL instead (e.g. https://intel.wd1.myworkdayjobs.com/External) and the actor extracts all three parts automatically.

Deliberately not supported

Teamtailor. Its public careers-page data is served through an endpoint that requires an API key/token rather than being openly readable, unlike the platforms above. Since this actor only talks to genuinely public, unauthenticated endpoints — no accounts, no keys, no per-customer credentials — Teamtailor is out of scope rather than half-supported.

JazzHR. Its public board ({slug}.applytojob.com/apply) is server-rendered HTML with the job list baked directly into the page markup — there is no accompanying JSON or XML endpoint behind it at a guessable URL. JazzHR does offer a "Listings XML feed" and a REST API, but both are opt-in per customer and gated behind a customer-specific API key, not something reachable from a bare company slug the way the platforms above are. Scraping the HTML itself would mean parsing markup rather than a stable data feed — the same reason this actor doesn't touch iCIMS — so JazzHR is out of scope.

iCIMS. Investigated and rejected. iCIMS career sites (e.g. {company}.icims.com) don't expose a stable, guessable, unauthenticated JSON endpoint: requests to their job-search pages come back with a 302 into a session-bootstrapping servlet and a fresh JSESSIONID cookie, and whatever JSON eventually loads client-side is undocumented, varies by iCIMS module (Recruit/Onboard/Connect/Apply) and by customer, and changes between iCIMS platform releases. That's session-dependent, effectively browser-rendered territory, not a public API this actor can rely on — so iCIMS is out of scope.

Input

FieldTypeDescription
companiesarray of stringsRequired. Each entry is either a bare slug (e.g. "stripe") — every bare-slug-capable platform is probed automatically — or a full board URL naming one platform explicitly (e.g. "https://boards.greenhouse.io/stripe", "https://jobs.lever.co/palantir", "https://jobs.ashbyhq.com/ramp", "https://jobs.smartrecruiters.com/Visa", "https://apply.workable.com/huggingface", "https://helloprint.recruitee.com", "https://personio.jobs.personio.de", "https://flyio.bamboohr.com/careers/list", "https://intel.wd1.myworkdayjobs.com/External").
includeDescriptionbooleanWhen true, each item includes the full plain-text job description (not available for SmartRecruiters or BambooHR — see limitations). Off by default to keep runs fast and cheap when you only need title/location/link.
maxJobsPerCompanyintegerCaps how many postings are pulled per company, per platform it's found on. Default 200.

Example input — bare slugs (auto-detect across 8 platforms)

{
"companies": ["stripe", "plaid", "huggingface", "helloprint"],
"includeDescription": false,
"maxJobsPerCompany": 100
}

Example input — mixed, including a Workday board URL

{
"companies": [
"stripe",
"https://jobs.lever.co/palantir",
"https://jobs.ashbyhq.com/ramp",
"https://jobs.smartrecruiters.com/Visa",
"https://intel.wd1.myworkdayjobs.com/External",
"https://personio.jobs.personio.de",
"https://flyio.bamboohr.com/careers/list"
],
"includeDescription": true,
"maxJobsPerCompany": 100
}

Output — normalized schema

Every item in the dataset — regardless of which platform it came from — has this shape:

FieldTypeNotes
platformstring"greenhouse", "lever", "ashby", "workday", "smartrecruiters", "workable", "recruitee", "personio", or "bamboohr"
companySlugstringThe slug used to query the ATS ({tenant}/{site} for Workday)
companyNamestring | nullHuman-readable company name, when the platform exposes it (Greenhouse and Workable do; the others generally don't)
jobIdstringPlatform-native job/posting ID
titlestringJob title
departmentstring | nullDepartment/function, when available
teamstring | nullSub-team, when available
locationsarray of stringsAll listed locations for the posting
isRemoteboolean | nullBest-effort: platform's own remote flag when present, else inferred from location text (e.g. contains "Remote")
employmentTypestring | nulle.g. "Full-time", "FullTime", when the platform reports it
applyUrlstringAbsolute URL to the live application page
postedAtstring | nullISO timestamp, when the platform reports it (always null for Workday and BambooHR — see limitations)
updatedAtstring | nullISO timestamp, when the platform reports it
descriptionstring | nullFull plain-text description, only when includeDescription: true (never populated for SmartRecruiters or BambooHR)
scrapedAtstringISO timestamp of when this actor fetched the item

Sample output item

{
"platform": "ashby",
"companySlug": "ramp",
"companyName": null,
"jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
"title": "Security Engineer, Cloud",
"department": "Engineering",
"team": "Backend",
"locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
"isRemote": true,
"employmentType": "FullTime",
"applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
"postedAt": "2026-04-07T17:12:35.753+00:00",
"updatedAt": null,
"description": null,
"scrapedAt": "2026-07-29T07:49:48.333Z"
}

Run summary

At the end of a run, a per-company status summary is written to the default key-value store under the key COMPANY_SUMMARY — which platform(s) each company was found on, how many jobs came back from each, and a clear message when a company wasn't found on any platform (e.g.

Company not found on greenhouse (tried slug "plaid")
). The run only fails (non-zero exit) when every company in your list failed to resolve on any platform — a single bad slug in a long list won't sink the run.

Use cases

  • Recruiting intel / competitive hiring analysis — track which teams and roles a set of companies is actively hiring for, and how that shifts over time, across a company list that spans more than one region's dominant ATS (Workday and SmartRecruiters skew toward enterprise/EU employers that Greenhouse/Lever/Ashby lists usually miss).
  • Job aggregation — build a niche job board or newsletter by pulling live postings from a curated list of companies without maintaining scrapers for each ATS separately.
  • Sales signals ("who's hiring") — open roles are a well-known proxy for growth, new initiatives, and budget — useful firmographic signal for sales and market research.

Pricing

This actor is billed pay-per-result: one dataset item = one job posting. Enabling includeDescription does not change pricing, only the amount of data returned per item.

Limitations (please read)

  • Only the nine platforms listed above are supported. Teamtailor, JazzHR, and iCIMS are deliberately excluded (see above — none of them expose a genuinely public, unauthenticated JSON/XML endpoint at a guessable URL). LinkedIn-only postings and custom in-house career pages are also out of scope and will simply come back "not found."
  • Bare-slug auto-detection relies on the slug matching across platforms. A company's slug is sometimes a different string on different platforms. If auto-detection misses a platform you know a company uses, pass the direct board URL instead.
  • Workday requires a board URL, not a bare slug. See above for why.
  • companyName is often null. Only Greenhouse and Workable reliably return a company display name; the others' public APIs generally don't expose one, so those items fall back to the slug you supplied.
  • Workday multi-location jobs report a placeholder, not the locations. When a Workday posting spans more than one site, Workday's list endpoint returns its own summary string (for example "2 Locations") instead of the individual cities, so that's what lands in locations. Single-location Workday jobs are exact. If you need the individual sites for those postings, say so in the Issues tab — resolving them means an extra request per job, which costs you more per run, so it isn't on by default.
  • isRemote is best-effort. It uses the platform's own remote flag when present, otherwise infers from location text — this can misclassify unusual location strings.
  • An empty result for a platform doesn't always mean "not on that platform." Several platforms (Lever, Ashby, SmartRecruiters) return an empty list both when a company isn't there and when a company is there but currently has zero open roles; this actor can't fully distinguish the two from an empty response.
  • postedAt is always null for Workday. Workday's job feed only exposes a relative string ("Posted Yesterday", "Posted 30+ Days Ago"), never a real timestamp, so there's nothing reliable to normalize into ISO 8601.
  • description is never populated for SmartRecruiters or BambooHR, even with includeDescription: true. Neither platform's list endpoint returns one, and fetching per-job detail would multiply request volume by job count.
  • postedAt is always null for BambooHR, for the same reason — BambooHR's list endpoint doesn't report a posting date; it's only present behind the same per-job detail call that also holds the description.
  • BambooHR locations can be sparse or missing. Its list endpoint frequently reports null city/state for jobs that do have a location set in the company's BambooHR account — this is a gap in what BambooHR's own public feed exposes, not something this actor can recover without the same per-job detail call mentioned above.
  • Data reflects a single point-in-time snapshot of each ATS's public feed at the moment the actor ran — postings can close or change immediately after.