ATS Jobs Scraper - Greenhouse, Lever & Ashby Jobs API avatar

ATS Jobs Scraper - Greenhouse, Lever & Ashby Jobs API

Pricing

from $1.00 / 1,000 actor run starteds

Go to Apify Store
ATS Jobs Scraper - Greenhouse, Lever & Ashby Jobs API

ATS Jobs Scraper - Greenhouse, Lever & Ashby Jobs API

Export every open job from a company's Greenhouse, Lever or Ashby job board: title, location, department, remote flag, full description and published salary range. Type a company name or paste a board URL. For recruiters, sales teams and labour-market research.

Pricing

from $1.00 / 1,000 actor run starteds

Rating

0.0

(0)

Developer

SR

SR

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

a month ago

Last modified

Categories

Features

Limited permissions

Share

ATS Jobs Scraper: Greenhouse, Lever and Ashby job boards

The ATS Jobs Scraper exports every open position a company publishes through its applicant-tracking system. Use it to track who is hiring, benchmark published pay or feed a job board. Greenhouse, Lever and Ashby all publish their job boards openly, so this reads structured data rather than parsing a careers page.

Give it a company name or a pasted board URL. No API key, no login.

Why an ATS jobs scraper beats scraping a careers page

The three systems each expose a documented public job-board endpoint. That has two consequences worth knowing before you compare this with a page scraper:

It does not break when a site is redesigned. There is no markup to parse, so a careers-page facelift changes nothing here.

It returns a whole board at once. Stripe's Greenhouse board came back with 716 open positions in a single read on 4 October 2026. A page scraper would walk that in dozens of paginated fetches.

You do not need to know which system a company uses

Type stripe and all three are tried, in the order Greenhouse, Lever, Ashby, until one answers with jobs. If you already know, pin it with greenhouse:stripe, lever:matchgroup or ashby:Ramp, or just paste the board URL you were looking at (https://jobs.ashbyhq.com/Ramp, https://boards.greenhouse.io/stripe, https://jobs.lever.co/matchgroup).

A company that is on none of the three is reported as exactly that in the run's errors record, rather than as an empty result you would have to interpret. The run itself still succeeds.

ATS Jobs Scraper input

All fields are optional. Every field keeps the name and default it has always had.

FieldWhat it doesDefault
boardsCompany names, system:board pairs or board URLs, one per line. A comma-separated string also works. Duplicates are removed.prefilled with stripe and https://jobs.ashbyhq.com/Ramp
include_descriptionInclude full descriptions. Lever and Ashby always include the text; for Greenhouse it means a larger response, so turn it off when you only need titles and locations.true
title_containsKeep jobs whose title contains this text, for example engineer or designer. Case-insensitive.empty
locationKeep jobs whose location contains this text, for example london, remote or new york. Every listed location is searched.empty
remote_onlyKeep only postings flagged remote by the system, listing a remote location or marked as remote workplace.false
jobs_per_boardMaximum jobs taken from each board, before the filters (1–10,000).1000
max_boardsMaximum number of boards read in one run (1–300). Extra boards are skipped.50
concurrencyRetained for compatibility (1–15). Boards are currently read one at a time; this setting does not change collection speed.5
retriesAttempts per board on a failed request (1–8).3

Board names are case-sensitive on Ashby (Ramp, not ramp) and lower-case on Greenhouse and Lever. Pasting the URL avoids the question entirely.

ATS Jobs Scraper output

One dataset row per open position, in the order of the boards you gave. Every row has:

  • job_id, title, url and apply_url
  • company, board and ats — which system published it: greenhouse, lever or ashby
  • location, plus all_locations when a posting lists several, and country
  • department and team
  • employment_type (full time, contract), workplace_type (onsite, hybrid, remote) and is_remote
  • salary — the published pay text, see below
  • published_at and updated_at, ISO 8601 UTC across all three systems
  • description as plain text, plus description_chars
  • position — the row's place in this run

Additional fields on every row: source, platform, fetched_at, posted_at, employment_type_code, country_code, city, salary_min, salary_max, salary_currency and salary_period. The original employment and country text stays under employment_type and country; the normalised fields use standard employment codes and country codes where the source gives an unambiguous value.

description_chars is more useful than it looks: a posting with 200 characters is a stub, and one with 4,000 is a real spec. Sorting by it separates the two without reading any of them.

Example row

A real row from Ramp's Ashby board, fetched on 4 October 2026. The description field holds the full 4,343-character text and is left out here for length.

{
"job_id": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
"title": "Security Engineer, Cloud",
"url": "https://jobs.ashbyhq.com/Ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
"apply_url": "https://jobs.ashbyhq.com/Ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
"company": "Ramp",
"board": "Ramp",
"ats": "ashby",
"location": "New York, NY (HQ)",
"all_locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
"country": "USA",
"department": "Engineering",
"team": "Backend",
"employment_type": "FullTime",
"workplace_type": "Hybrid",
"is_remote": true,
"salary": "$211.4K – $290.6K • Offers Equity",
"published_at": "2026-04-07T17:12:35Z",
"updated_at": null,
"description_chars": 4343,
"position": 5,
"source": "ats-jobs-scraper",
"platform": "ashby",
"fetched_at": "2026-10-04T14:12:10Z",
"posted_at": "2026-04-07T17:12:35Z",
"city": "New York City",
"country_code": "US",
"employment_type_code": "FULL_TIME",
"salary_min": 211400,
"salary_max": 290600,
"salary_currency": "USD",
"salary_period": "YEAR"
}

Run summary

The summary record in the key-value store gives boards requested and read, a count per system, jobs returned, how many carried pay and a description, how many are remote, and the number of distinct companies and departments. Boards that could not be read are listed in the errors record with a code and a short message.

The per-system breakdown is the useful health check: if a run of twenty companies reports jobs from only one system, the other names were probably wrong rather than empty.

About salary

Ashby publishes the original salary text, including the range and any equity note. Greenhouse does not publish a salary range through its public board. Lever's original salary field stays empty for compatibility, but its published structured pay is available in salary_min, salary_max, salary_currency and salary_period.

The numeric fields also read Ashby's salary component. Bonus, commission and equity are excluded. An unavailable amount stays null. withSalary and salaryNote in the summary describe the original text field, so numeric ranges can be present on a Lever row whose salary is null.

Three payload details this gets right

Greenhouse escapes its own HTML. Its description arrives as <h2><strong> rather than as markup. A parser that strips tags without unescaping first leaves every entity code in place. Here it is unescaped once, then stripped.

Lever timestamps are milliseconds. Read as seconds, a 2026 posting dates from the year 58,000. That still sorts and still renders, which is what makes it dangerous. It is converted correctly here.

The three publish three different date formats. Sorting a mixed run by raw date strings quietly gets the order wrong. Everything is converted to one UTC form.

Use cases for an ATS jobs scraper

Recruiting intelligence. Which teams a competitor is growing, and how fast, shows up in the department breakdown across repeated runs. published_at turns that into a hiring-velocity series.

Pay benchmarking. The Ashby and Lever rows with published ranges are a genuine sample of pay by role and location, which very few sources give you in structured form.

Job aggregation. One read per company, everything normalised into one shape, so a job board of a hundred companies is a hundred reads and one table.

Lead scoring and hiring signals. A company that just opened fifteen engineering roles is hiring, and hiring is a buying signal if you sell to engineering teams.

Time-to-fill tracking. Only currently open positions appear. A role that is filled or withdrawn stops being published, so running on a schedule and keeping the rows shows how long postings stay open, a fair proxy for how hard a role is to fill.

How this compares with other options

  • Careers-page scrapers parse HTML that changes with every redesign and paginate through large boards. This reads the board the company's own careers page is built from.
  • Single-system scrapers cover only Greenhouse, only Lever or only Ashby, so you first have to find out which one a company uses. Here a plain company name is enough.
  • Job aggregators and search engines show a subset of postings, often late and without the department, team or published pay the source system carries.
  • The public board APIs themselves are free, but each has its own shape, date format and quirks. This scraper gives you one row format across all three, with filters and a summary.

Pricing

The price is $0.001 per run plus $0.001 per delivered job, so 1,000 jobs cost about one dollar. The run fee is charged once, including a run with no jobs or an empty input. Empty results generate no job charges. Jobs are delivered to the dataset before their job charge is applied.

Users without a paid Apify plan receive up to ten results per run. This limit is applied after the filters, so the actor can still inspect all requested boards to find those ten jobs. The summary reports the full filtered count; the run output reports how many results were delivered. Paying users keep their requested limits.

FAQ

Which applicant-tracking systems does the ATS Jobs Scraper support? Greenhouse, Lever and Ashby. A company on another system, or on none, is reported in the errors record and the run still succeeds.

Do I need an API key or a login? No. All three systems publish their job boards openly, and the actor reads those public boards.

How do I find a company's board name? Open the company's careers page and click a job. The address shows the board: boards.greenhouse.io/<board>, jobs.lever.co/<board> or jobs.ashbyhq.com/<board>. Paste that URL into boards, or just try the company name.

Why is salary empty on a Greenhouse job? Greenhouse does not publish pay through its public board. An empty salary means the system carries none, not that the job is unpaid.

Can I run it on a schedule? Yes. Use an Apify schedule to run it daily or weekly and compare the datasets to see which roles opened and closed.

How many jobs can one run return? Up to 10,000 per board and 300 boards per run. Each board is read in one go, however many openings it holds.

Large lists take longer because boards are read one at a time. For a large batch, start a run asynchronously and retrieve its dataset when it finishes. Synchronous API calls can reach their 300-second wait limit while the actor is still collecting boards.