← Guides

How-to

How to run ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday)

Step-by-step: the exact input, what each field does, and the rows that come back from the source portal.

You have a list of employers and you want to know what every one of them is hiring for. Done by hand that is: find each company’s careers page, work out which applicant-tracking system it runs, page through the listings, and copy them into a sheet — then repeat the whole thing next week to see what changed. The systems are the reason it is tedious. Stripe’s board is Greenhouse, Notion’s is Ashby, Gopuff’s is Lever, NVIDIA’s is Workday, and each one presents jobs differently. This actor takes the company domain and does the identification for you, returning every open role from all five systems in one shape.

What you’ll need

Nothing but an Apify account. The actor talks to the source portal directly.

Nothing else. No API key, no login, no CAPTCHA solver and no proxy — the proxy option in the input is off by default and you can leave it that way. Each of these five systems publishes its job board over an open endpoint, which is why this runs in seconds rather than driving a browser.

Step 1 — Open the actor

Open ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday) on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.

The ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday) listing on the Apify Store
The listing on the Apify Store. Pricing and the nightly health record are both public.

Step 2 — Fill in the input

The input form for ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday) in the Apify Console
The input form, as it appears in the Apify Console.
FieldTypeRequiredWhat it does
companystringnoA 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…
companiesarraynoLook 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… (default [])
maxResultsintegernoCap 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… (default 1000)
postedAfterstringnoKeep 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…
includeDescriptionbooleannoOff 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…

Two fields decide everything.

companies takes whatever you have. A plain domain (stripe.com) is the normal case. A careers URL works too, and for Workday it is required — a Workday board is addressed by a tenant, a numbered pod and a site name, none of which can be derived from a company domain, so paste https://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite rather than nvidia.com. If you already know the board you can name it outright as lever:gopuff or greenhouse:stripe, and that always wins over any detection.

maxResults is per company, not per run. This matters more than it sounds: boards are large. On 6 September 2026 Stripe’s board held 617 open roles, Gopuff’s 765, and one NVIDIA Workday tenant 2,000. Leave it high to pull whole boards, or set it low while you are experimenting. Whatever you set, the run log states the board’s own total next to the number returned, so a cap never quietly looks like the whole picture.

A working input:

{
  "companies": [
    "stripe.com",
    "notion.so",
    "lever:gopuff"
  ],
  "maxResults": 100,
  "postedAfter": "2026-08-01"
}

Step 3 — Run it

Press Start. Rows are pushed to the dataset as they’re found, so the run log fills in as it works.

Fast. Four companies capped at 25 jobs each returned 100 rows in 12.8 seconds on 7 September 2026, because every request is a plain API call with no browser involved. Whole boards take longer only because there is more to page through.

An empty result is not silence. If a company cannot be resolved to a board you get one free, unbilled row explaining why and naming the input that would work — usually the board reference, as in lever:acme. That distinction is deliberate: “we could not find the board” and “this company is not hiring” are different answers, and only the first one is our problem.

Step 4 — Read the output

Each run returns a labelled table, not raw JSON:

The output fields returned by ATS & Career Page Jobs Scraper (Greenhouse, Lever, Workday)
The output view — every field the actor returns, named and typed.

Every row looks like this — a real row from a real run:

{
  "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
}
FieldExample valueMeaning
companyvercel.comThe value you submitted — domain, careers URL or explicit board
company_nameVercelEmployer name as the board states it (Greenhouse and SmartRecruiters publish it; Ashby, Lever and Workday do not, so it is null there)
atsgreenhousegreenhouse, lever, ashby, smartrecruiters or workday
ats_slugvercelThe board identifier on that ATS
detected_byslug_matchHow the board was matched: explicit, careers_page, or slug_match
job_id6136160004The board’s own job identifier — stable across runs, so it de-duplicates
titleAccount Executive, CommercialPosted job title
department / teamDepartment and team or job function, where the board publishes them

Most people come for title, location and apply_url, and those are filled on every row.

Three fields need a word of warning, all for the same reason — boards differ in what they publish, and this actor returns what the board said rather than filling gaps with guesses.

company_name is the employer as the board names it. Greenhouse and SmartRecruiters publish it; Ashby, Lever and Workday do not, so it is null there.

posted_at is a real timestamp on Greenhouse, Lever, Ashby and SmartRecruiters. Workday does not publish a date at all — it says “Posted Today” — so those rows leave posted_at null and keep the board’s own wording in posted_text. Nothing invents a date from that phrase.

remote comes from the board’s own flag on Ashby and SmartRecruiters. Greenhouse and Workday publish no such flag, so it is read from their location wording instead: “Remote - US” gives true, “Hybrid - London” gives false, and a posting that says only “Dublin” gives null, because it has not actually said either way.

Step 5 — Export it

Open the Dataset tab and export to CSV, JSON, or Excel — or pull the same rows from the API, which is what you want if this is going to run on a schedule.

What it costs

$0.00125 per job returned — $1.25 per 1,000 — and you are charged per job, not per company. Fifty companies with 1,000 roles between them cost the same as one company with 1,000 roles. That price takes effect on 21 September 2026; until then it is $0.001 per job, or $1 per 1,000.

Free: companies that resolve to no board, boards with no open jobs, and the marker rows that explain either. A realistic run of 40 employers averaging 60 open roles each is about 2,400 jobs, so roughly $3.00 plus Apify’s own platform usage, which for an actor this light is pennies.

Where the data comes from

This reads the source portal directly. Every night a canary runs this actor against that live source and diffs the result against a frozen fixture — what “verified” means.

The source is whichever applicant-tracking system the employer actually runs — Greenhouse, Lever, Ashby, Workday or SmartRecruiters. The annoying part is not reading a board, it is knowing which board to read: most careers pages render their listings in JavaScript, so there is nothing in the page to tell you. Reading the careers page for an ATS link identified only 4 of 14 test companies; deriving a likely board name from the domain and asking the vendor to confirm it got 11, without ever returning another company’s jobs.

See it used

Every open job at a company, from its career page — the straight case: domains in, open roles out.

New job postings this week across a company list — the same run on a schedule, returning only what has appeared since you last looked.

If you need to reach the employers rather than list their openings, the Business Email & Phone Contact Details Scraper takes the same company domains and returns contact details instead of jobs.

Last updated 2026-09-06