Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby)
Scrape open jobs from Greenhouse, Lever and Ashby boards. Get the title, location, department, posted date, description and apply link. $3.00 per 1,000.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
companies,ats,company(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.003 per job = $3 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Job returned | Charged per job posting returned. | $0.003 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-06-13, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
companies | List of job boards to scrape, each as "ats:token". The ats is greenhouse, lever or ashby; the token is the company's board slug. Examples: "greenhouse:stripe", "greenhouse:airbnb", "lever:spotify", "ashby:ramp", "ashby:openai". Find the slug in a careers-page URL (boards.greenhouse.io/{token}, jobs.lever.co/{company}, jobs.ashbyhq.com/{name}). See the README for more examples and where to find each token. | array |
ats | Alternative to the list above: pick one ATS and pair it with a single Company below. Ignored when Companies is filled. | string |
company | The single company's board slug to scrape with the ATS selected above (e.g. "stripe"). Ignored when Companies is filled. | string |
leverLocations | Optional. Only jobs posted in these places, filtered by Lever itself, so you pay only for those. Type each place exactly as the board labels it on its jobs.lever.co page, capitals and commas included, for example "New York, NY" or "London". Boards name places their own way, and a label the board does not use returns no jobs. A job posted in several places matches on any of them. Greenhouse and Ashby boards send every job, so a run with this set must list Lever boards only. To filter places on every board, use Locations below. | array |
locations | Optional. Only jobs posted in one of these places, on Greenhouse, Lever and Ashby boards alike. Whole words, any case: London finds "London" and "London, UK", New York finds "New York, NY". A job posted in several places matches on any of them, and its rows then list them all in locations. Jobs left out are not charged, so a strict list can return fewer jobs than Max jobs per company. | array |
remoteOnly | Optional. Only jobs the board itself calls remote: Lever's and Ashby's own workplace type (hybrid jobs do not count), and on Greenhouse, which has no such field, the word remote in the job's location. Jobs left out are not charged. | boolean |
maxItems | Cap the number of postings emitted per company. Leave at 0 (or empty) to return every open posting on each board. | integer |
notionConnector | Optional. Write each job as a page into your Notion when the run finishes. Authorize a Notion connector once in Settings → API & Integrations → MCP connectors, then pick it here. Leave empty to skip (default), results are always saved to the dataset regardless. | string |
notionParentId | Optional. The Notion data source ID of the database to write into (only used if a Notion connector is set). Leave empty to create the pages privately in your workspace instead. | string |
What you get
A structured dataset — each result includes fields like:
atscompanydepartmentdescriptionemploymentTypelocationpostedAtsalarytitleurlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
3 ready-to-run use cases
Greenhouse Jobs API Feed: Every Open Role on a Board
Reads a Greenhouse board, Stripe's by default, and returns title, location, department, posted date and the apply link for each open role.
Competitor Hiring Monitor: Read Rival ATS Boards
What a named set of companies has open right now, by title, team and location. It reads current postings, not headcount and not who was hired.
Job Board Scraper: Merge Several ATS Boards Into One Feed
Greenhouse, Lever and Ashby boards read in a single run and written out as one list. Salary turns up rarely, because most boards do not publish it.
Related tools in Job Market Scrapers
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
LinkedIn Jobs Scraper
Scrape public LinkedIn jobs by keyword, location, URL or ID. Filter by date, workplace type and experience. Full descriptions. $0.80 per 1,000 jobs.
BuiltIn Jobs Scraper
Scrape Built In tech jobs: salary, all locations, skills, seniority, exact posted date. No login, no API key. $0.81 per 1,000.
Dice Jobs Scraper
Scrape Dice jobs: title, company, location, type, posting age and apply URL. Descriptions optional. No login. $0.90 per 1,000 jobs.
SEEK Jobs Scraper
Scrape SEEK jobs in Australia and New Zealand: salary ranges, workplace type and full descriptions. No login. $0.81 per 1,000, flat at every volume.
Career Site Jobs Scraper
Scrape open jobs from a career page, a domain or a company name. Works with 10 ATS platforms. Get title, location, department and apply URL.
Internshala Scraper
Scrape Internshala internships and fresher jobs by keyword, city, category, stipend or work from home. Duration, apply-by date, openings. $0.34/1,000.
Where this tool sits
- Categories
- Job Market Scrapers
- Platforms
- Job Boards & ATS
Multi-ATS Jobs Scraper: every open role on a Greenhouse, Lever or Ashby board, in one schema
Give it a list of company board slugs and it returns every open posting on each one, with the full description text, the department, the apply link and the posting date. No keyword search, no login, no API key.
The three systems agree on almost no field names, so the rows are normalised into one shape. That also means some fields are simply absent on one system and present on another, and the table below says which.
| Input | Board slugs as ats:token, for example greenhouse:stripe |
| Output | One row per open posting |
| Ceiling | Every open posting on each board, or your own per-company cap |
| Account needed | None, and no API key for any of the three |
| Price | $3.00 per 1,000 jobs, flat on every plan |
🗂️ What Multi-ATS Jobs Scraper does
Greenhouse, Lever and Ashby each publish a company's whole careers board as open JSON. This reads those feeds directly, so what you get is the company's own posting data rather than a scrape of a rendered careers page.
You name the boards as ats:token. The token is the slug in the company's careers URL: job-boards.greenhouse.io/<slug> (the older boards.greenhouse.io/<slug> works too), jobs.lever.co/<slug> or jobs.ashbyhq.com/<slug>. Several boards run a few at a time, and the same posting reachable from two boards is delivered once.
Every row carries the full description as plain text, not a snippet. That is the part most job feeds make you fetch one page at a time.
📥 What you give it
{
"companies": ["greenhouse:stripe", "lever:spotify", "ashby:ramp"],
"maxItems": 0
}
| Field | Default | What it is |
|---|---|---|
companies | box starts at greenhouse:stripe, lever:spotify, ashby:ramp | The list of boards, each written ats:token. The ats part is greenhouse, lever or ashby. |
ats | empty | For a single board instead of a list. Pick one system here and pair it with company below. Ignored when companies is filled. |
company | none | One board slug, used with ats. Ignored when companies is filled. |
leverLocations | none | Lever boards only. Only jobs posted in these places, filtered by Lever itself. Type each place exactly as the board labels it on jobs.lever.co, for example New York, NY; a label the board does not use returns no jobs. A run with this set must list Lever boards only. |
locations | none | Every board. Only jobs posted in one of these places, matched as whole words in any case against every place a job lists: London finds "London, UK", New York finds "New York, NY". Up to 50. |
remoteOnly | false | Every board. Only jobs the board calls remote: Lever's and Ashby's own workplace type, where hybrid does not count, and on Greenhouse, which has no such field, the word "remote" in the job's location. |
maxItems | 0 | Cap per company, not per run. 0 means every open posting on each board. |
notionConnector | none | Optional. Write every job into your own Notion as well as the dataset. Authorise the connector once in Settings, then pick it here. |
notionParentId | none | Optional. The Notion data source ID to write into. Leave blank and the pages are created privately in your workspace. |
proxyConfiguration | off | Optional, and off by default because a normal run does not need it. |
One malformed entry stops the whole run. A spec that is not ats:token, or names a system other than the three, ends the run with a single BAD_INPUT row before any board is read. Check the list before a large run.
locations and remoteOnly work on the whole board each system sends, so they cost no extra reading, and jobs they leave out are never charged. A strict filter can return fewer jobs than maxItems, or none, in which case the board gets a free NO_RESULTS row saying so.
📤 What you get back
A real row from a recent run, with the description cut short:
{
"ok": true,
"ats": "greenhouse",
"company": "stripe",
"title": "Abuse Investigator",
"location": "Dublin",
"department": "8611 Security Analytics",
"employmentType": null,
"url": "https://stripe.com/jobs/search?gh_jid=8172487",
"postedAt": "2026-09-12T13:25:25-04:00",
"description": "Who we are\n\nAbout Stripe\n\nStripe is a financial infrastructure platform for businesses...",
"salary": null
}
| Field | What it is |
|---|---|
description | The whole posting as plain text, markup stripped. Long, and the reason rows are big. |
url | The company's own hosted job page, which is where an applicant lands. |
postedAt | An ISO timestamp. On Lever it is when the posting was created, on Ashby when it was published. On Greenhouse it is the last time the posting was edited, because that is the date the board publishes first. |
salary | Free text where the system has it. Lever gives its salary blurb, Ashby its compensation summary. Greenhouse never exposes one, so this is null on every Greenhouse row. |
employmentType | Lever's commitment field or Ashby's employment type. Always null on Greenhouse. |
department | Greenhouse joins multiple departments with a comma. Lever and Ashby give department and team joined with a slash. |
ats, company | Which system and which board slug this row came from, so a multi-board run stays sortable. |
locations | Only on rows of a leverLocations or locations run: every place the job is posted. A job can match on one that is not its main city, which is the one location shows. |
remote | Only on rows of a remoteOnly run, and always true there. |
🧾 Reading the output
Two kinds of row can land in your dataset.
| Row | How to spot it | Charged |
|---|---|---|
| A job | ok: true and a url | yes |
| A diagnostic | ok: false and an errorCode | no |
Each board reports for itself, so a run over ten boards can deliver jobs for nine and one diagnostic row for the tenth. A diagnostic row is never charged.
| Code | What it means |
|---|---|
BAD_INPUT | The list was empty, an entry was not a valid ats:token, leverLocations was set on a list with Greenhouse or Ashby boards, or a locations entry had no letters in it. Nothing was read. |
NOT_FOUND | That token is not a board slug on that system. The row carries a hint showing where to copy the slug from. |
NO_RESULTS | The board exists and currently has no open postings, or none at the places or with the remote setting you asked for. The note says which. |
RATE_LIMITED | The board asked for a slower pace. Re-run with fewer boards. |
SERVER_ERROR | The board answered with a server error. Usually passes on its own. |
BLOCKED | The board would not serve the feed this time. |
NETWORK | The board could not be reached, or answered with something that was not JSON. |
A wrong slug is by far the commonest problem, and it shows up as NOT_FOUND. The default table view does not show errorCode, so switch the dataset to All fields when a board comes back empty.
▶️ How to run it
1. Open Multi-ATS Jobs Scraper and click Try for free. 2. Open a company's careers page and copy the slug out of its URL. 3. Add one line per board to Companies (ats:token), like greenhouse:airbnb. 4. Leave Max jobs per company at 0 for the whole board, then click Start. 5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$3.00 per 1,000 jobs, which is $0.003 each. Flat on every Apify plan, no volume tiers.
You pay per posting delivered. Duplicate postings reachable from two boards are charged once, jobs your locations or remoteOnly filter leaves out are not charged, diagnostic rows are not charged, and if every board comes back empty, no rows are charged.
💡 What people use it for
- Watching a list of competitors' boards on a schedule and spotting the day a new team opens.
- Building a startup jobs feed without writing three different clients for three different systems.
- Pulling full descriptions for keyword analysis, which needs the whole text rather than a snippet.
- Checking headcount direction by department, using
departmentand the row count per company.
🚧 What it does not do
- No keyword search. You name boards, not roles. Filter the rows afterwards.
- Remote on Greenhouse is read from the location text. Greenhouse has no remote field, so a
remote job whose location never says "remote" is missed by remoteOnly.
- Only three systems. Greenhouse, Lever and Ashby. A company on anything else will not resolve.
- You have to know the slug. There is no company-name lookup; copy it from the careers URL.
- Greenhouse has no salary and no employment type, and its date is the last edit rather than the
original posting date. That is what the board publishes.
- Open postings only. Nothing closed, filled or draft, and no history of what used to be there.
- Many large boards at once is the risky run. Rows are held together before they are written,
so a long list of very large companies is the case most likely to run out of room. Split it.
- No applicant-side anything. No salary benchmarks, no company profile, no reviews.
🧭 Which jobs scraper do you need?
| If you want | Use |
|---|---|
| Whole company boards on Greenhouse, Lever or Ashby | This one |
| Career pages on other hiring systems, by company URL | Career Site Jobs Scraper |
| A keyword search across one country's listings | Indeed Jobs Scraper |
| Startup roles with equity ranges | Wellfound Jobs Scraper |
| Tech company listings by stack and perks | BuiltIn Jobs Scraper |
❓ Questions people ask
Where do I find the board token? In the careers URL. job-boards.greenhouse.io/stripe gives greenhouse:stripe, jobs.lever.co/spotify gives lever:spotify, jobs.ashbyhq.com/ramp gives ashby:ramp.
Does maxItems cap the run or each company? Each company. Five boards with maxItems at 20 is up to 100 rows.
Why is salary empty on so many rows? Greenhouse does not publish one at all. Lever and Ashby do when the company filled it in, which many do not.
How many boards can I put in one run? There is no fixed cap, but keep an eye on the size of the companies. A dozen mid-sized boards is comfortable; a dozen of the largest is not.
Can I schedule it? Yes. Daily on a fixed list works well, and url is a stable key for spotting which postings are new.
Is this legal? These are public job feeds the companies publish themselves. Postings can still carry personal data, which GDPR and similar laws cover, so have a reason for collecting it. Apify's write-up on scraping and the law is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the run ID and the exact ats:token line that went wrong. The errorCode and hint on the diagnostic row usually name the problem on their own.