Request a tool
All toolsAutomationsGuidesMCP serverRequest a toolPlatformsCategories
Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby) icon

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.

5 from 1 review on Apify 267 runs on Apify $0.003 per job ($3 / 1,000)
Run this in the cloudRun on Apify →

Job Market Scrapers

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust companies, ats, company (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export 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 forWhenPrice
Job returnedCharged 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

FieldWhat it doesType
companiesList 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
atsAlternative to the list above: pick one ATS and pair it with a single Company below. Ignored when Companies is filled.string
companyThe single company's board slug to scrape with the ATS selected above (e.g. "stripe"). Ignored when Companies is filled.string
leverLocationsOptional. 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
locationsOptional. 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
remoteOnlyOptional. 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
maxItemsCap the number of postings emitted per company. Leave at 0 (or empty) to return every open posting on each board.integer
notionConnectorOptional. 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
notionParentIdOptional. 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:

atscompanydepartmentdescriptionemploymentTypelocationpostedAtsalarytitleurl

Export 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 iconJob Market Scrapers

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.

Ready to run — no setup

BuiltIn Jobs Scraper iconJob Market Scrapers

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.

Ready to run — no setup

Dice Jobs Scraper iconJob Market Scrapers

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.

Ready to run — no setup

SEEK Jobs Scraper iconJob Market Scrapers

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.

Ready to run — no setup

Career Site Jobs Scraper iconJob Market Scrapers

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.

Ready to run — no setup

Internshala Scraper iconJob Market Scrapers

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.

Ready to run — no setup

See all Job Market Scrapers →

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.

InputBoard slugs as ats:token, for example greenhouse:stripe
OutputOne row per open posting
CeilingEvery open posting on each board, or your own per-company cap
Account neededNone, 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
}
FieldDefaultWhat it is
companiesbox starts at greenhouse:stripe, lever:spotify, ashby:rampThe list of boards, each written ats:token. The ats part is greenhouse, lever or ashby.
atsemptyFor a single board instead of a list. Pick one system here and pair it with company below. Ignored when companies is filled.
companynoneOne board slug, used with ats. Ignored when companies is filled.
leverLocationsnoneLever 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.
locationsnoneEvery 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.
remoteOnlyfalseEvery 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.
maxItems0Cap per company, not per run. 0 means every open posting on each board.
notionConnectornoneOptional. Write every job into your own Notion as well as the dataset. Authorise the connector once in Settings, then pick it here.
notionParentIdnoneOptional. The Notion data source ID to write into. Leave blank and the pages are created privately in your workspace.
proxyConfigurationoffOptional, 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
}
FieldWhat it is
descriptionThe whole posting as plain text, markup stripped. Long, and the reason rows are big.
urlThe company's own hosted job page, which is where an applicant lands.
postedAtAn 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.
salaryFree 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.
employmentTypeLever's commitment field or Ashby's employment type. Always null on Greenhouse.
departmentGreenhouse joins multiple departments with a comma. Lever and Ashby give department and team joined with a slash.
ats, companyWhich system and which board slug this row came from, so a multi-board run stays sortable.
locationsOnly 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.
remoteOnly on rows of a remoteOnly run, and always true there.

🧾 Reading the output

Two kinds of row can land in your dataset.

RowHow to spot itCharged
A jobok: true and a urlyes
A diagnosticok: false and an errorCodeno

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.

CodeWhat it means
BAD_INPUTThe 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_FOUNDThat token is not a board slug on that system. The row carries a hint showing where to copy the slug from.
NO_RESULTSThe 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_LIMITEDThe board asked for a slower pace. Re-run with fewer boards.
SERVER_ERRORThe board answered with a server error. Usually passes on its own.
BLOCKEDThe board would not serve the feed this time.
NETWORKThe 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 department and 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 wantUse
Whole company boards on Greenhouse, Lever or AshbyThis one
Career pages on other hiring systems, by company URLCareer Site Jobs Scraper
A keyword search across one country's listingsIndeed Jobs Scraper
Startup roles with equity rangesWellfound Jobs Scraper
Tech company listings by stack and perksBuiltIn 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.