Greenhouse, Lever, Ashby & Recruitee Jobs Scraper
Pricing
from $1.50 / 1,000 job results
Greenhouse, Lever, Ashby & Recruitee Jobs Scraper
Scrape all open jobs from company career pages on Greenhouse, Lever, Ashby and Recruitee using their official public job-board APIs. One clean schema, salary ranges where published, keyword, location and remote filters, plus new-jobs-only monitoring. No login, no proxies.
Pricing
from $1.50 / 1,000 job results
Rating
0.0
(0)
Developer
Mark Demian
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 hours ago
Last modified
Categories
Share
What does this ATS jobs scraper do?
Greenhouse, Lever, Ashby & Recruitee Jobs Scraper collects every open job from company career pages hosted on the four most common applicant tracking systems (ATS). You give it a list of companies (career-page URLs or names), and you get back one clean, normalized dataset: title, department, team, location, remote/hybrid status, employment type, salary range where the company publishes one, posting date, description, and the public job and apply URLs.
It reads the ATS vendors' official public job-board APIs, the same JSON feeds that power companies' own careers pages. That makes it fast (about 4,900 jobs from 26 companies in about 20–40 seconds in our tests), reliable (no HTML parsing, so a careers-page redesign doesn't break it) and cheap to run. It needs no login, no cookies, no proxies and no browser.
Try it now: click Start. The example input pulls 20 jobs each from Figma (Greenhouse), Palantir (Lever) and Ramp (Ashby).
Main features
- 🏢 4 ATS platforms in one schema: Greenhouse, Lever, Ashby, Recruitee
- 🔎 Auto-detection: paste a careers URL,
ats:slug, or just a company slug - 💰 Salary extraction: structured pay ranges from the ATS (including Greenhouse's pay-transparency ranges), plus ranges found in the job text, and yearly min/max so hourly, monthly and annual pay are comparable
- 🎯 Filters: title keywords (include and exclude), location keywords, remote/hybrid only, posted in the last N days
- 🔔 Monitor mode: "Only new jobs since last run" turns a scheduled run into a new-job alert feed
- 🛡️ Privacy by design: recruiter emails and phone numbers are stripped from descriptions, and contact fields are never collected
- 🤝 Polite: respects
robots.txt, waits at least 1 second between requests to the same host, and backs off on errors
Because it runs on Apify, you also get scheduling, a REST API, webhooks and integrations (Google Sheets, Slack, Zapier, Make, n8n, Airbyte and more), plus exports to JSON, CSV, Excel and XML.
What can you use it for?
- Niche job boards and newsletters: build feeds like "remote Rust jobs" or "Toronto fintech jobs" from the companies you choose.
- Hiring signals and market research: see which teams, locations and roles competitors, customers or portfolio companies are hiring for.
- Recruiting and job-search automation: get daily alerts for new matching roles at your target companies.
- Salary benchmarking: collect published pay ranges (common in pay-transparency regions such as NY, CA, CO and WA).
Supported systems
| ATS | Accepted input examples | Data source (public API) |
|---|---|---|
| Greenhouse | https://boards.greenhouse.io/figma, https://job-boards.greenhouse.io/figma, greenhouse:figma | boards-api.greenhouse.io Job Board API |
| Lever | https://jobs.lever.co/palantir, lever:palantir | api.lever.co Postings API |
| Ashby | https://jobs.ashbyhq.com/ramp, ashby:ramp | api.ashbyhq.com Job Postings API |
| Recruitee | https://bunq.recruitee.com, recruitee:bunq | <company>.recruitee.com/api/offers |
A bare slug such as figma is tried on Greenhouse, then Lever, Ashby and Recruitee, in that order, and the first non-empty board is used. Use an explicit ats:slug or a URL when you know the ATS. It is faster and avoids picking the wrong board.
A company's own careers domain (for example stripe.com/jobs) is not accepted directly. Use the ATS board URL or slug instead (see the FAQ).
How to use it
- Click Try for free or Start in Apify Console.
- In Companies / career boards, add one company per line (a URL,
ats:slugor slug). - Optionally add filters: title keywords, location keywords, remote only, or posted within N days.
- Set Max jobs per company to
0to get every job. The example input uses 20 to keep your first run cheap. - Click Start, then download the results as JSON, CSV or Excel, or use the API.
- For alerts, enable Only new jobs since last run and add a Schedule (for example daily), with an integration to Slack, Sheets or a webhook.
Input examples
Quick start (the example input):
{"companies": ["greenhouse:figma", "https://jobs.lever.co/palantir", "ashby:ramp"],"maxJobsPerCompany": 20}
Remote engineering roles posted in the last 14 days, without descriptions:
{"companies": ["https://boards.greenhouse.io/stripe","https://boards.greenhouse.io/cloudflare","https://jobs.ashbyhq.com/ramp","lever:palantir"],"titleKeywords": ["engineer", "developer"],"excludeTitleKeywords": ["intern", "manager"],"remoteOnly": true,"postedWithinDays": 14,"includeDescription": false}
Daily new-job monitor for a location (schedule it, and only jobs not seen in earlier runs are output):
{"companies": ["greenhouse:figma", "greenhouse:datadog", "ashby:ramp", "recruitee:bunq"],"locationKeywords": ["New York", "Remote"],"onlyNewSinceLastRun": true}
Input fields
| Field | Type | Default | Description |
|---|---|---|---|
companies | array of strings | (required) | Career-board URLs, ats:slug, or bare slugs |
titleKeywords | array | [] | Keep jobs whose title contains any of these (case-insensitive) |
excludeTitleKeywords | array | [] | Drop jobs whose title contains any of these |
locationKeywords | array | [] | Keep jobs whose location, locations or workplace type contains any of these |
remoteOnly | boolean | false | Keep only jobs whose location or workplace type mentions remote or hybrid |
postedWithinDays | integer | 0 | Keep jobs updated or posted in the last N days (0 = no limit) |
includeDescription | boolean | true | Include the plain-text description (with emails and phones removed) |
onlyNewSinceLastRun | boolean | false | Monitor mode: output only jobs not seen in earlier runs |
maxJobsPerCompany | integer | 0 | Cap on jobs per company after filters (0 = all) |
requestDelayMs | integer | 1000 | Minimum delay between requests to the same host (minimum 1000) |
Output
Each dataset item is one job posting. Example (description shortened):
{"ats": "ashby","companySlug": "ramp","company": "ramp","jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245","title": "Security Engineer, Cloud","department": "Engineering","team": "Backend","location": "New York, NY (HQ)","locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],"workplaceType": "Hybrid","employmentType": "FullTime","salary": { "min": 211400, "max": 290600, "currency": "USD", "interval": "1 YEAR" },"salaryText": "$211.4K - $290.6K","salarySource": "ats","salaryMinYearly": 211400,"salaryMaxYearly": 290600,"salaryCurrency": "USD","payRanges": null,"postedAt": "2026-04-07T17:12:35.753Z","updatedAt": null,"url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245","applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application","descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams…","key": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245","scrapedAt": "2026-10-27T20:51:07.896Z"}
Output fields
| Field | Description |
|---|---|
ats | greenhouse, lever, ashby or recruitee |
companySlug | Board identifier on the ATS (for example figma) |
company | Company display name when the ATS provides it (Greenhouse, Recruitee); otherwise the slug |
jobId | The job's ID on the ATS |
title | Job title |
department, team | As published (can be null) |
location | Primary location text |
locations | All listed locations |
workplaceType | Remote, Hybrid or OnSite when stated. On Greenhouse it is inferred only from "remote" in the location, so it's often null |
employmentType | For example FullTime, Full-time or Contract, as the ATS words it. Greenhouse's public API doesn't expose it |
salary | {min, max, currency, interval} or null |
salaryText | Human-readable range |
salarySource | ats (structured field from the ATS), description (parsed from the job text; an interval of year? or hour? is a guess), or null |
salaryMinYearly, salaryMaxYearly | Salary converted to a yearly amount in the original currency: hour × 2,080, day × 260, week × 52, month × 12. null when the period is unknown or one-time |
salaryCurrency | Currency of the salary and the yearly fields (no currency conversion) |
payRanges | Greenhouse only, when a job lists several ranges (pay zones or countries): every range with min, max, currency, interval and its label. salary then shows the widest span in the first range's currency |
postedAt, updatedAt | ISO 8601 dates when the ATS exposes them |
url, applyUrl | Public job page and application page |
descriptionText | Plain-text description, with emails and phone numbers replaced by [email removed] / [phone removed] (omitted when includeDescription is false) |
key | Stable unique ID ats:companySlug:jobId, for deduplication |
scrapedAt | When this run collected the job |
The Output tab has two views: Jobs (all jobs) and With salary. A RUN_STATS record in the run's key-value store lists boards found and not found, and any errors.
How complete is each field? Measured on our test set of 26 company boards and 4,869 jobs on October 27, 2026 (version 0.1.3). Your companies will differ.
| ATS | Jobs in test | Salary present | Salary from the ATS's own field | Workplace type | Employment type |
|---|---|---|---|---|---|
| Greenhouse | 2,774 | 49% | 38% | 23% | 0% |
| Lever | 624 | 70% | 34% | 100% | 99% |
| Ashby | 1,451 | 64% | 57% | 78% | 100% |
| Recruitee | 20 | 0% | 0% | 100% | 100% |
Every job with a salary also got salaryMinYearly/salaryMaxYearly in this test. The rest of the salaries come from ranges parsed from the job text.
Was this useful? If this Actor saved you time, a quick star rating on the Reviews tab helps other people find it. If something didn't work, please open an issue instead, so it can be fixed.
How much does it cost to scrape Greenhouse, Lever, Ashby and Recruitee jobs?
This Actor uses pay-per-event pricing, so you pay per job result and nothing for compute:
- $0.0015 per job in the dataset ($1.50 per 1,000 jobs)
- plus Apify's standard Actor start event of $0.00005 per run (charged once per GB of memory; this Actor defaults to 1 GB)
| Example | Jobs | Approximate cost |
|---|---|---|
| Example input (3 companies × 20 jobs) | 60 | $0.09 |
| One large company (around 500 open jobs) | 500 | $0.75 |
| 25 companies, all jobs | 5,000 | $7.50 |
| Daily monitor, about 30 new jobs a day, for a month | 900 | $1.35 |
Costs are simply the number of jobs × $0.0015, plus a fraction of a cent per run. Filters are applied before results are saved, so you only pay for jobs that match. Monitor mode only charges for new jobs.
Control your spending: set Max cost per run in the run options. The Actor stops right away when the limit is reached (it cancels any board downloads still in progress), and jobs it couldn't deliver are not marked as "seen", so the next monitor run picks them up.
Free plan: Apify's free plan includes monthly platform credit (currently $5), which covers about 3,300 jobs from this Actor.
Use it from AI agents (Apify MCP)
AI agents and assistants (Claude, Cursor, VS Code and other MCP clients) can run this Actor through Apify's hosted MCP server. Add this to your MCP client's configuration. On first connection it opens your browser so you can sign in to Apify:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=fetch-actor-details,markdemian/ats-jobs-scraper"}}}
Then ask things like "List Ramp's open engineering roles in New York" or "Which of these 10 companies posted a remote data job this week?"
Tips for agents:
- Set
includeDescription: falseand a smallmaxJobsPerCompanyto keep responses short and cheap. - Use
salaryMinYearly/salaryMaxYearlyto compare pay across hourly and annual roles. - Set a max cost (
maxTotalChargeUsdin the call options) to cap what a single call can spend.
What's new
- 0.1.3 (October 27, 2026)
- Greenhouse salaries now come from Greenhouse's structured pay-transparency ranges. In our test, Greenhouse jobs with a salary went from 11% to 49%.
- New
salaryMinYearly,salaryMaxYearlyandsalaryCurrencyfields for all four ATSes, andpayRangesfor Greenhouse jobs that list several pay zones. - The With salary output view shows the yearly columns.
- 0.1.2 (October 27, 2026): when the max cost per run is reached, the Actor now stops right away instead of finishing board downloads it can no longer output.
- 0.1.1 (October 27, 2026): first public release.
FAQ
Is it legal to scrape job postings?
This Actor reads only public job postings that companies deliberately publish through their ATS's public job-board APIs, the same data shown on their careers pages without logging in. It does not collect candidate data, applicant information or anything behind a login. It removes email addresses and phone numbers from descriptions and never maps recruiter or contact fields. You are responsible for how you use the data. Respect each company's terms, and consult a lawyer if you're unsure about your use case.
Does it collect personal data?
No, by design. Job postings describe roles, not people. Contact details that sometimes appear in description text (recruiter emails and phone numbers) are automatically redacted, and fields like Recruitee's mailbox_email are never mapped. A job description can still mention a hiring manager by name in free text. If that matters for your use case, set includeDescription to false.
How do I find a company's ATS and slug?
Open the company's careers page and click a job. If the URL or the application form is on boards.greenhouse.io, job-boards.greenhouse.io, jobs.lever.co, jobs.ashbyhq.com or <name>.recruitee.com, paste that URL. If you only know the name, try the bare slug (for example figma) and the Actor will check all four systems.
Why was a company "not found"?
The company either uses a different ATS (Workday, SmartRecruiters, iCIMS, Taleo, its own system and so on), uses a different slug, or has no public board. Not-found companies are listed in the run log and in RUN_STATS. They are not charged, because no job results are produced.
How fresh is the data?
It is live: every run reads the ATS APIs directly, at the moment the run happens. For alerts, schedule it daily or hourly with Only new jobs since last run.
How does monitor mode work?
The Actor remembers the key of every job it has output in a named key-value store in your account (ats-jobs-scraper-seen). With monitor mode on, jobs already seen are skipped. To start fresh, delete that store in Storage.
Can I use it via API, Python, JavaScript, Zapier or Make?
Yes. Like every Apify Actor you can start it through the Apify API or client libraries, receive webhooks when it finishes, and connect it to Zapier, Make, n8n, Google Sheets, Slack and more. See the API tab.
Something's wrong or missing?
Open an issue on the Issues tab with the company input you used. Requests for more ATS platforms are welcome.
Limitations
- Supports Greenhouse, Lever, Ashby and Recruitee only. Workday, SmartRecruiters, iCIMS, Taleo, BambooHR, Workable and others are not supported yet.
- It returns what the ATS publishes. Fields the vendor's public API doesn't expose (for example employment type on Greenhouse) stay
null. - Salaries parsed from description text (
salarySource: "description") are a best-effort heuristic. Check thesalaryText, and treat an interval ofyear?orhour?as a guess. - Greenhouse doesn't state the pay period as a field, so it's read from the range's label (for example "Annual Base Salary Range" or "Hourly Rate"). When the label doesn't say, the period is guessed from the amount and marked
year?orhour?. - The yearly fields assume full-time hours (2,080 a year) and don't convert currencies.
companyis the slug for Lever and Ashby, because their public APIs don't include a company display name.- A bare slug is matched to the first ATS with a non-empty board. If two systems use the same slug for different companies, use an explicit
ats:slug. - Some companies use their own careers domain in front of an ATS. Use the underlying ATS board URL or slug.
- Requests to the same host are spaced at least 1 second apart, so very long lists on a single ATS take roughly 1 second per company.
- It does not apply to jobs, and it does not collect applicant or candidate data.
Was this useful? If this Actor saved you time, a quick star rating on the Reviews tab helps other people find it. If something didn't work, please open an issue instead, so it can be fixed.