ATS Jobs Scraper - Greenhouse, Lever & Ashby Jobs API
Pricing
from $1.00 / 1,000 actor run starteds
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.
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.
| Field | What it does | Default |
|---|---|---|
boards | Company 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_description | Include 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_contains | Keep jobs whose title contains this text, for example engineer or designer. Case-insensitive. | empty |
location | Keep jobs whose location contains this text, for example london, remote or new york. Every listed location is searched. | empty |
remote_only | Keep only postings flagged remote by the system, listing a remote location or marked as remote workplace. | false |
jobs_per_board | Maximum jobs taken from each board, before the filters (1–10,000). | 1000 |
max_boards | Maximum number of boards read in one run (1–300). Extra boards are skipped. | 50 |
concurrency | Retained for compatibility (1–15). Boards are currently read one at a time; this setting does not change collection speed. | 5 |
retries | Attempts 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,urlandapply_urlcompany,boardandats— which system published it:greenhouse,leverorashbylocation, plusall_locationswhen a posting lists several, andcountrydepartmentandteamemployment_type(full time, contract),workplace_type(onsite, hybrid, remote) andis_remotesalary— the published pay text, see belowpublished_atandupdated_at, ISO 8601 UTC across all three systemsdescriptionas plain text, plusdescription_charsposition— 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.