Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby)
Scrape open jobs from Greenhouse, Lever, and Ashby boards by company. Get title, location, department, and apply link as JSON, CSV, or Excel. No key needed.
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 — a run that returns nothing costs nothing beyond the start fee. 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 |
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
Stripe Jobs Scraper - Greenhouse Open Roles & Apply Links
Every open Stripe role from its Greenhouse board, with job title, location, department and apply link. A clean jobs feed for recruiters and sourcers.
Fintech Hiring Tracker - Plaid, Brex & Mercury Job Data
Who Plaid, Brex and Mercury are hiring right now, pulled from their ATS boards. Headcount and team growth signals for competitor and market analysts.
Startup Jobs Feed Builder - Multi-Company ATS Aggregator
Live openings from fast-growing startups merged into one structured jobs feed for a job board or newsletter. Add or drop companies as you go.
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, and pull full descriptions.
BuiltIn Jobs Scraper
Scrape Built In tech jobs at $0.81/1,000 - salary, location, skills, posted date. No login or API key. 1,000 jobs in under 2 minutes.
Dice Jobs Scraper
Dice jobs scraper at $0.90 per 1,000 jobs plus a $0.001 run start. Companies, locations, posting dates, apply URLs and full descriptions. No login needed.
SEEK Jobs Scraper
SEEK jobs scraper at $0.81 per 1,000, flat at every volume. Australia and New Zealand, with salary ranges, workplace type and full descriptions. No login.
Career Site Jobs Scraper
Scrape open jobs from any company career page. Auto-detects the ATS across 10 platforms and returns title, location, department, type.
Internshala Scraper
Scrape Internshala internships and fresher jobs by keyword, city, category, stipend or work-from-home.
Where this tool sits
- Categories
- Job Market Scrapers
- Platforms
- Job Boards & ATS
Multi-ATS Jobs Scraper (Greenhouse · Lever · Ashby)
Scrape open job listings straight from the public JSON APIs of the three most common applicant-tracking systems — Greenhouse, Lever and Ashby. No API key, no login, no anti-bot to fight. Point it at a list of company boards and get every posting back in one normalized schema.
Thousands of companies post their jobs through exactly these three boards. Instead of writing a scraper per company, give this actor a list like ["greenhouse:stripe","lever:spotify","ashby:ramp"] and it figures out the right endpoint for each and merges the results.
Input
| Field | Notes |
|---|---|
companies | Array of "ats:token" strings. ats is greenhouse, lever, or ashby; token is the company's board slug. e.g. greenhouse:stripe, lever:spotify, ashby:openai. |
ats + company | Convenience pair for a single board (e.g. ats: "greenhouse", company: "stripe"). Ignored when companies is set. |
maxItems | Max postings per company. 0 (default) = all open postings. |
proxyConfiguration | Optional, off by default. These public APIs have no anti-bot, so no proxy is needed. Only enable one if you hit IP-based rate limits across many boards. |
Where do I find the token?
It's the slug in the public careers URL:
- Greenhouse →
boards.greenhouse.io/<token>(also<token>.greenhouse.io) - Lever →
jobs.lever.co/<company> - Ashby →
jobs.ashbyhq.com/<name>
Output
One dataset row per job posting, deduped by url:
{
"ok": true,
"ats": "greenhouse",
"company": "stripe",
"title": "Account Executive, AI Sales",
"location": "San Francisco, CA",
"department": "1650 AI GTM Strategy & Solutions",
"employmentType": "FullTime",
"url": "https://stripe.com/jobs/search?gh_jid=7964697",
"postedAt": "2026-06-05T15:44:04-04:00",
"description": "Who we are… (plain text, HTML stripped)",
"salary": "$211.4K – $290.6K • Offers Equity"
}
Field availability differs by ATS, so several fields can be null even on a successful row:
| Field | Greenhouse | Lever | Ashby |
|---|---|---|---|
employmentType | null (not exposed) | ✓ (commitment) | ✓ |
salary | null (not exposed) | best-effort (often null) | ✓ (structured, may be null) |
department | ✓ | ✓ (dept / team) | ✓ (dept / team) |
location / postedAt / url | ✓ when present, else null | ✓ when present, else null | ✓ when present, else null |
title and company are always present on a success row. Every other field above is null when the board doesn't supply it — this is honest data, not a failed scrape.
Greenhouse job descriptions come HTML-entity-encoded; the actor decodes and strips them to clean plain text.
Diagnostic rows (ok:false)
When a board has no open postings, uses a wrong/retired slug, or hits a network/blocked error, the actor pushes a single ok:false diagnostic row instead of job rows, for example:
{ "ok": false, "errorCode": "NO_RESULTS", "error": "The request succeeded but returned no results for this input.", "ats": "greenhouse", "company": "acme", "note": "No open postings for greenhouse:acme." }
An ok:false row means that one board had nothing to return — not that the run failed. These rows are never charged. Filter on ok:true to get only billable job postings. Empty input produces an ok:false row with errorCode: "BAD_INPUT" instead of crashing the run.
Billing & empty boards
$3.00 per 1,000 jobs ($0.003 each), with no run-start fee. Flat rate — no volume tiers, no plan gates — and you are charged only for jobs actually returned.
Billed per job posting returned (job), and only for genuine ok:true rows. A board with no open postings (or a wrong/retired slug) produces a single ok:false diagnostic row explaining why — and is not charged. Network/blocked errors and empty/invalid input likewise return a coded ok:false diagnostic row instead of failing the whole run, and are never charged.
Example
{
"companies": ["greenhouse:stripe", "greenhouse:airbnb", "lever:spotify", "ashby:ramp", "ashby:openai"],
"maxItems": 0
}