Greenhouse Scraper · Lever, Ashby & Workable Jobs + Salary avatar

Greenhouse Scraper · Lever, Ashby & Workable Jobs + Salary

Pricing

from $3.00 / 1,000 job records

Go to Apify Store
Greenhouse Scraper · Lever, Ashby & Workable Jobs + Salary

Greenhouse Scraper · Lever, Ashby & Workable Jobs + Salary

Jobs straight from the official Greenhouse, Lever, Ashby, Workable, Recruitee and Personio job-board APIs, in one schema, with parsed salary min/max/currency/period. Keyword, location, remote, department and date filters. maxResults is a hard cap. Missing or empty boards are never charged.

Pricing

from $3.00 / 1,000 job records

Rating

0.0

(0)

Developer

TheQuietStack

TheQuietStack

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Greenhouse scraper, Lever scraper and Ashby/Workable job scraper in one: jobs straight from the company job boards, one schema, salary parsed into numbers.

Get every open job of the companies you care about straight from their applicant tracking system: Greenhouse, Lever, Ashby, Workable, Recruitee and Personio. One schema for all six, with the salary range parsed into numbers (salaryMin, salaryMax, salaryCurrency, salaryPeriod), filters for keywords, location, remote, department and posting date, and a hard result cap that really stops the run.

No login, no API key, no browser. The Actor reads the official public job-board APIs the companies themselves publish for their career pages:

ATSEndpoint used
Greenhouseboards-api.greenhouse.io/v1/boards/<slug>/jobs?content=true&pay_transparency=true
Leverapi.lever.co/v0/postings/<slug>?mode=json
Ashbyapi.ashbyhq.com/posting-api/job-board/<slug>?includeCompensation=true
Workableapply.workable.com/api/v1/widget/accounts/<slug>?details=true
Recruitee<slug>.recruitee.com/api/offers/
Personio<slug>.jobs.personio.de/xml?language=en (and ?language=de when a posting exists only in German)

What you get

  • Salary as numbers, with a receipt. First from the ATS's own pay fields (Greenhouse pay transparency ranges, Lever salaryRange, Ashby compensation tiers, Recruitee salary, Personio salaryInformation; Workable's public feed has no pay field, so there it is always the text). If the company only wrote the range into the posting text, it is parsed from there, and salaryText shows the exact sentence it came from. salarySource says which (structured or text). Equity, bonuses, welcome bonuses, relocation money, meal vouchers, learning budgets, "per session" rates and "$100B market" style numbers are ignored. Austrian-style minimums ("Mindestgehalt € 3.200,- brutto monatlich", "Minimum EUR 48,000 gross annually") fill salaryMin only, because the posting names no upper bound. Nothing is estimated: no range in the posting → the salary fields are null.
  • Pay zones kept. When a company lists several ranges (pay zones, tiers), salaryMin/salaryMax span them and every range is in salaryRanges with its label.
  • maxResults is a hard cap. Set 50 and you get 50 rows, even with several boards running in parallel. Each board is sorted newest first, so a small cap keeps the freshest jobs.
  • You pay for jobs, not for attempts. A board that does not exist (HTTP 404; on Personio a redirect away from the board), a board that exists but has 0 open jobs, a failed request, a filtered-out job or a job you already received (onlyNew) is listed in the run summary and never charged. Missing and empty boards are reported separately, so a typo in a slug never looks like "no openings".
  • Only new jobs, on a schedule. Turn on onlyNew and schedule the Actor daily: it remembers the job IDs it returned (per board, in a named key-value store in your own account) and next time returns only postings it has not shown you before.
  • Paste whatever you have. greenhouse:stripe, personio:prewave, a board URL (https://jobs.lever.co/zoox, https://jobs.ashbyhq.com/ramp, https://apply.workable.com/skroutz, https://channable.recruitee.com, https://prewave.jobs.personio.de, EU hosts), a company careers page (a linked board of any of the six is detected in its HTML), or just a slug (tried on Greenhouse, Lever, Ashby, Workable, Recruitee, then Personio).
  • Strong in Europe. Recruitee (Netherlands) and Personio (Germany, Austria) are where European companies post; both carry a structured pay field, and Austrian postings state a legal minimum salary that is parsed from the text.
  • Polite by design. At most one request per second per ATS service (all Recruitee and all Personio company subdomains count as one service each). One request returns a company's whole board (Personio: at most two, English and German).

Input example

{
"boards": [
"greenhouse:airbnb",
"https://jobs.lever.co/zoox",
"ashby:ramp",
"https://www.duolingo.com/careers",
"personio:prewave",
"recruitee:channable"
],
"keywords": ["engineer", "data"],
"locations": ["New York", "Remote"],
"remote": "any",
"newSinceDays": 14,
"onlyWithSalary": true,
"maxResults": 200
}

Watch list, only new postings, run daily:

{
"boards": ["ashby:openai", "greenhouse:anthropic", "lever:palantir"],
"departments": ["Engineering"],
"onlyNew": true,
"seenStoreName": "my-ai-labs-watchlist",
"includeDescription": false
}

Via the API you can pass objects and set the company name yourself:

{ "boards": [{ "ats": "lever", "slug": "palantir", "company": "Palantir" }] }

Output example (one row, shortened)

{
"ats": "ashby",
"companySlug": "ramp",
"jobId": "465799ed-c58b-4c6a-a290-2e95b52ef0bb",
"title": "Tech Lead and Manager (TLM), Production Engineering",
"company": "Ramp",
"url": "https://jobs.ashbyhq.com/ramp/465799ed-c58b-4c6a-a290-2e95b52ef0bb",
"location": "New York, NY (HQ)",
"locations": ["New York, NY (HQ)"],
"country": "USA",
"remote": true,
"workplaceType": "remote",
"department": "Engineering",
"team": "Engineering",
"employmentType": "FULL_TIME",
"postedAt": "2026-09-28T23:10:15.801Z",
"updatedAt": null,
"salaryMin": 240000,
"salaryMax": 330000,
"salaryCurrency": "USD",
"salaryPeriod": "YEAR",
"salarySource": "structured",
"salaryRanges": null,
"salaryText": null,
"descriptionText": "ABOUT RAMP\n\nRamp is building ...",
"descriptionHtml": null,
"applyUrl": "https://jobs.ashbyhq.com/ramp/465799ed-c58b-4c6a-a290-2e95b52ef0bb/application",
"hasSalary": true,
"scrapedAt": "2026-09-30T10:49:28.604Z"
}
FieldMeaning
jobId + atsStable ID of the posting in its ATS. Used for de-duplication within a run and across runs (onlyNew).
salaryMin / salaryMaxNumbers in the posting's own currency and period. No conversion. A single stated amount fills salaryMax (and salaryMin unless it says "up to").
salaryPeriodYEAR, MONTH, WEEK, DAY or HOUR.
salarySourcestructured = the ATS pay field; text = parsed from the posting, see salaryText.
salaryRangesAll ranges when the posting lists several (pay zones, tiers).
remote / workplaceTypeFrom the ATS's workplace field; otherwise remote when a location says remote/anywhere.
employmentTypeFULL_TIME, PART_TIME, CONTRACT, INTERN. Greenhouse has no standard field for it, so it is only set when the company added it as a custom field. Personio working students are PART_TIME.
postedAtGreenhouse first_published, Lever createdAt, Ashby publishedAt, Workable published_on (date only), Recruitee published_at, Personio createdAt.
locationsEvery location of the posting. Workable's feed repeats a job once per location; those copies are merged into one row with all locations.

The run summary (key-value store record SUMMARY) lists per board: jobs on the board, jobs that matched your filters, jobs written; plus boards not found, empty boards, failed requests, careers pages without a detectable board, counts per filter, and how many events were charged.

How much salary data is there?

Measured on 30 Sep 2026 across 40 well-known company boards (20 Greenhouse, 10 Lever, 10 Ashby): about 61 % of Greenhouse jobs, 62 % of Lever jobs and 69 % of Ashby jobs came with a salary range, and about a fifth of those ranges existed only in the posting text, not in the ATS pay field.

The same day, 10 company boards with open jobs per European-heavy ATS:

ATSJobsWith salaryFrom pay field / textBoards with any salary
Workable18719 (10 %)0 / 195 of 10
Recruitee23817 (7 %)17 / 04 of 10
Personio37012 (3 %)2 / 105 of 10

How much you get depends on the company and the country, not on the ATS: US postings almost always carry a range (pay transparency laws), many European ones do not. Austrian postings carry a legal minimum (one Austrian Personio board: 8 of 8 jobs), while one German board with 319 jobs had a range on only 1. Use onlyWithSalary to keep just the jobs that state pay.

Compared with other ways to get these jobs

  • Job aggregators and pre-built job databases cover far more companies and ATS platforms (including Workday and others). This Actor covers only Greenhouse, Lever, Ashby, Workable, Recruitee and Personio, and only the companies you name, but reads them live at run time, so a posting closed this morning is not in your data.
  • Single-ATS scrapers need one run and one output format per ATS. Here all six share one schema.
  • Generic scrapers often stop at the raw salary text. Here you get numbers you can sort and filter on, plus the sentence they came from.

If you need Workday, iCIMS or SmartRecruiters, or discovery of companies you do not know yet, a broader tool is a better fit. (SmartRecruiters was tested and left out on purpose: its public API answers any company name, real or invented, with "0 jobs", so a typo cannot be told apart from a quiet board, and every job needs a second request for its text.)

Pricing

Pay per event: one event per job returned and one per company that returned at least one job. Boards that are missing, empty or fail, and jobs you filtered out or already saw, cost nothing. Your "Max cost per run" is respected: the Actor stops before pushing a row it cannot charge.

Limits and honesty

  • Only boards the company publishes publicly. Nothing behind a login, no application forms, no applicant data.
  • Careers-page detection reads the page HTML. Boards that are loaded only by JavaScript are not found; use the board URL or ats:slug instead. The summary tells you when this happens.
  • Lever answers some company slugs with an empty list (HTTP 200, 0 jobs) instead of 404. Those are reported as empty, not as missing. Workable and Personio answer many existing accounts with 0 jobs (HTTP 200); also reported as empty, never as missing.
  • Personio's feed carries a posting's text only in the language it was written in. The Actor reads the English feed and, only if a posting came back without text, the German one.
  • Recruitee boards on a company's own domain (without .recruitee.com) are not detected from the careers page; pass recruitee:<slug>.
  • Some company websites refuse non-browser clients (HTTP 403/404/429). Careers-page detection then fails with that status in the summary; the board itself is unaffected, pass its URL or ats:slug.
  • Salary text parsing covers the common English and German phrasings ($120,000 - $150,000, $120-150k per year, CAD $79,600 - CAD $99,500, 70.000 € - 90.000 € brutto, $37.63/hr—$77.48/hr, € 3.200,- brutto monatlich, Jahresbruttogehalt von mindestens EUR 45.000). Unusual wordings stay null rather than guessed.