Greenhouse, Lever, Workday
ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday)
Give it a company domain, get every open job from the ATS behind its career page — Greenhouse, Lever, Ashby, Workday and SmartRecruiters in one schema.
Verification
Output fields
Authoritative field set from the dataset schema.
| Field | Type |
|---|---|
company | string|null |
company_name | string|null |
ats | string|null |
ats_slug | string|null |
detected_by | string|null |
job_id | string|null |
title | string|null |
department | string|null |
team | string|null |
location | string|null |
locations | array|null |
remote | boolean|null |
employment_type | string|null |
posted_at | string|null |
posted_text | string|null |
updated_at | string|null |
apply_url | string|null |
requisition_id | string|null |
description | string|null |
notice | string|null |
notice_type | string|null |
source_url | string|null |
scraped_at | string|null |
Sample row
{
"source_url": "https://job-boards.greenhouse.io/vercel/jobs/6136160004",
"company": "vercel.com",
"company_name": "Vercel",
"ats": "greenhouse",
"ats_slug": "vercel",
"detected_by": "slug_match",
"job_id": "6136160004",
"title": "Account Executive, Commercial",
"department": "Account Executive",
"team": null,
"location": "Hybrid - London",
"locations": [
"Office - London"
],
"remote": null,
"employment_type": null,
"posted_at": "2026-08-06T12:50:10-04:00",
"posted_text": null,
"updated_at": "2026-08-18T18:06:19-04:00",
"apply_url": "https://job-boards.greenhouse.io/vercel/jobs/6136160004",
"requisition_id": null,
"description": null
} Inputs
| Field | Type | Req | Default | Description |
|---|---|---|---|---|
company | string | no | "stripe.com" | A company domain (acme.com), a careers URL, or an explicit board such as 'greenhouse:stripe' or 'lever:gopuff'. The Actor works out which applicant-tracking system the company uses. Kept forever alongside 'companies' — saved tasks and API callers send it. |
companies | array | no | ["stripe.com","notion.so","greenhouse:figma"] | Look up many companies in ONE run instead of starting a run per company. Takes the same values as 'Company'. Combined with 'Company' if you fill both, and duplicates are removed. Billing is unchanged: you are charged per job returned, not per company submitted. |
maxResults | integer | no | 1000 | Cap on jobs returned PER COMPANY, not per run — so a batch cannot silently return only the first rows overall and read as 'these companies aren't hiring'. When a board holds more, the run log states the board's own total next to what was returned. |
postedAfter | string | no | — | Keep only jobs published on or after this date (YYYY-MM-DD) — this is what turns the Actor into a weekly new-openings feed. Jobs whose board states no publish date (Workday says 'Posted Today' rather than a date) are KEPT, because dropping them would hide every Workday job and read as 'not hiring'. |
includeDescription | boolean | no | false | Off by default: descriptions are the bulk of the payload (one large board is ~16 KB per job) and most buyers filter on title, team and location first. Turn it on when you need the text. |
proxyConfiguration | object | no | {"useApifyProxy":false} | Optional. These are public vendor APIs and the plain path is the fastest one, so a proxy is genuinely not needed for the boards themselves. Enable it only if a company's own careers page blocks the detection step. |
Pricing
Pay per result (job-posting) — no charge for empty runs.
Example: 1000 job postings at $0.00125/result ≈ $1.25.
FAQ
Which applicant-tracking systems are supported?
Greenhouse, Lever, Ashby, SmartRecruiters and Workday. Each is read from that vendor's own public job-board endpoint, so there is no login, no API key and no browser rendering involved.
How does it know which ATS a company uses?
Three ways, tried in that order. If you name the board — 'greenhouse:stripe', or a careers URL — that wins. Otherwise it looks for an ATS link on the company's own careers page, which proves the board belongs to them. Failing that it derives a likely board name from the domain and accepts it only if the vendor states a company name that matches. Every row records which of the three applied, in `detected_by`.
What happens when a company cannot be resolved?
You get one free, unbilled row explaining why and naming the input that would work, for example 'lever:acme'. It is never a silent empty result, because 'we could not find the board' and 'this company is not hiring' are different answers and only one of them is our fault. On a 14-company test on 2026-09-06, 11 resolved from the domain alone and the three that did not were companies whose careers page is entirely JavaScript.
Why is posted_at empty on some rows?
Workday publishes a relative phrase — 'Posted Today' — rather than a date. Rather than invent a timestamp, those rows leave `posted_at` null and keep the board's own wording in `posted_text`. The other four systems publish a real timestamp. For the same reason, the 'Posted on or after' filter keeps undated rows instead of dropping them, which would hide every Workday job.
Can I get only jobs posted since my last run?
Yes. Set 'Posted on or after' to a date and schedule the Actor; each run returns the roles opened since then. Rows carry the board's own stable job ID, so de-duplicating across runs is exact rather than title matching.
Do I pay per company or per job?
Per job returned. Submitting 50 companies that collectively have 1,000 open roles costs the same as one company with 1,000 roles. Companies that resolve to nothing, and boards with no open jobs, are free.
How many jobs can one company return?
Whole boards, and they get large — on 2026-09-06 the boards in the example input held 617, 132 and 765 open roles, and one Workday tenant tested held 2,000. Use 'Maximum jobs per company' to cap it; the cap applies per company, not per run, and the run log always states the board's own total next to what was returned so a cap can never read as completeness.
Why is `remote` sometimes null instead of false?
Because the board did not say. Ashby and SmartRecruiters publish a real remote flag; Greenhouse and Workday publish none, so for those the value is read from the board's own wording — 'Remote - US' gives true, 'Hybrid - London' gives false. A posting that just says 'Dublin' says nothing about remote work, and this Actor returns null there rather than asserting false. Filtering for remote roles gives the same answer either way; the difference only shows when you filter for non-remote, and there null is the honest value.
What is not in the output?
Salary, skills, requirements and seniority. Not an oversight: on 2026-09-06 the three boards checked published pay data on 0 of 617 Greenhouse jobs, 0 of 132 Ashby jobs and 0 of 40 Lever jobs. Those columns would be present and empty, so this Actor does not carry them rather than implying data it cannot get. Everything returned comes from the board; nothing here is inferred by a model.
Is a proxy needed?
No. These are public vendor endpoints and the direct path is the fastest one, so the proxy input is off by default. Turn it on only if a particular company's own careers page blocks the detection step.
Guides & use cases
Related actors