Greenhouse, Lever & Ashby Jobs Scraper + AI Salary Extraction
Pricing
from $1.00 / 1,000 job-scrapeds
Greenhouse, Lever & Ashby Jobs Scraper + AI Salary Extraction
Scrape public Greenhouse, Lever, and Ashby job boards. AI extracts salary, work mode, seniority, years of experience, and tech stack — 94% salary accuracy on hand-checked postings.
Pricing
from $1.00 / 1,000 job-scrapeds
Rating
0.0
(0)
Developer
Shannon McNeil
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 days ago
Last modified
Categories
Share
Clean, structured job postings from Greenhouse, Lever, and Ashby — with salary, work mode, seniority, experience, and tech stack already extracted by AI, and accuracy you can verify.
Give it a list of companies and you get one record per open role, read straight from each company's public applicant-tracking-system (ATS) job board. Turn on AI normalization and each record also gets the details that are normally buried in the description: salary range, remote/hybrid/onsite, seniority, minimum years of experience, visa sponsorship, and tech stack.
Why use this Actor
- Straight from the source. Greenhouse, Lever, and Ashby publish public JSON job boards, so this Actor reads them directly. No browser, no login, no anti-bot workarounds, so runs are fast, cheap, and rarely break.
- AI fields you can filter on. You get
salaryMin/salaryMaxas numbers,workModeasremote/hybrid/onsite, andtechStackas an array. You can filter on them in a spreadsheet, SQL, or your app without writing parsing code. - Measured accuracy. We tested the AI fields against hand-checked labels on 50 real postings (details below). If a posting doesn't state a salary, you get
null, not a guess. - Pay only for what you get. Billing is per job delivered, plus a separate charge per job the AI actually enriched. Scraping-only runs are $1 per 1,000 jobs.
Proven accuracy
We built a 50-posting test set from live Gusto, Databricks, Ramp, Stripe, and Palantir boards, ran the AI over it, and checked every disputed answer by hand against the real posting:
| Field | Accuracy | Sample |
|---|---|---|
| Salary range (min / max / currency) | 94% | 47 / 50 |
| Work mode (remote / hybrid / onsite) | 95.7% | 45 / 47 |
| Minimum years of experience | 100% | 34 / 34 |
It never invented a salary. Of the 20 test postings that state no pay, the AI returned null for all 20. A missing salary stays missing instead of getting a plausible-looking number.
Why not just run GPT on the descriptions yourself?
You can. But then you'd be rebuilding and testing what's already proven here:
- Fetching: three different ATS APIs with different field names, pagination, rate limits, HTML-encoded descriptions, and dead boards that need auto-detection.
- Prompting: handling the edge cases. Multiple pay zones (report the overall min to max), "2–3 years" that isn't a salary, Canadian
$that isn't USD, and a city name that means onsite. - Schema enforcement: constrained JSON output so every record parses, with automatic escalation to a stronger model when the fast one isn't confident.
- Evaluation: a labeled test set and scoring harness. Without one, you don't know your accuracy. You just hope.
Most of the work is that last mile, and this Actor already ships it for $4 per 1,000 jobs with no API key, prompt engineering, or eval set to maintain.
How to use it
- Click Try for free and add companies to Companies: a board slug (
gusto) or a careers URL (https://jobs.lever.co/palantir). - Leave ATS on Auto-detect, or pick Greenhouse, Lever, or Ashby.
- Turn on AI normalize if you want the extracted fields.
- Optionally add filters and a per-company cap, then click Start.
- Download the results as JSON, CSV, Excel, or HTML, or pull them through the Apify API.
Input example
{"companies": ["gusto", "https://jobs.lever.co/palantir", "ramp"],"ats": "auto","aiNormalize": true,"filters": { "keywords": ["engineer", "data"], "remoteOnly": false, "postedWithinDays": 30 },"maxJobsPerCompany": 200}
| Field | Type | Description |
|---|---|---|
companies | string[] | Required. Company slugs or careers-page URLs on Greenhouse, Lever, or Ashby. |
ats | enum | auto (default) tries Greenhouse, then Lever, then Ashby. Or force one: greenhouse, lever, ashby. |
aiNormalize | boolean | Add the AI-extracted ai object to each job. Default false. |
filters.keywords | string[] | Keep jobs whose title or department contains any keyword (case-insensitive). |
filters.remoteOnly | boolean | Keep only roles that look remote. |
filters.postedWithinDays | integer | Keep jobs posted in the last N days. Jobs with no date are kept. |
maxJobsPerCompany | integer | Cap jobs per company (default 500). |
Filters run before AI normalization, so you're never charged AI fees for jobs you filtered out.
Output
You get one record per job. Here is a real one from our test run (description shortened):
{"company": "gusto","ats": "greenhouse","jobId": "7918214","title": "Staff Software Engineer, Tax Experiences","url": "https://job-boards.greenhouse.io/gusto/jobs/7918214","location": "San Francisco, CA - Hybrid","department": "Engineering","postedAt": "2026-07-06","descriptionText": "About Gusto\n\nAt Gusto, we're on a mission to grow the small business economy. We handle the hard stuff — payroll, health insurance, 401(k)s, and HR — so owners can focus on their craft and their customers…","ai": {"salaryMin": 163000,"salaryMax": 247000,"salaryCurrency": "USD","salaryPeriod": "year","seniority": "staff","workMode": "hybrid","visaSponsorship": "unknown","techStack": ["React", "TypeScript", "Ruby on Rails", "SQL", "AI"],"yearsExperienceMin": 8,"confidence": 0.92}}
| Field | Description |
|---|---|
company, ats, jobId | Where the job came from. ats:company:jobId is unique and stable across runs, so you can use it for deduplication and change tracking. |
title, department, location, url | As posted. |
postedAt | YYYY-MM-DD. Published or last-updated date, depending on the ATS. |
descriptionText | The full description as plain text (HTML removed). |
ai.salaryMin / ai.salaryMax | Numbers. Lowest and highest pay across all stated ranges and zones. null if no pay is stated. |
ai.salaryCurrency / ai.salaryPeriod | ISO code (USD, CAD, GBP, …) and year / month / week / day / hour. |
ai.seniority | intern, junior, mid, senior, staff, principal, lead, manager, director, executive. |
ai.workMode | remote, hybrid, or onsite. |
ai.visaSponsorship | yes / no only when the posting says so, otherwise unknown. |
ai.techStack | Technologies, languages, frameworks, and tools named in the posting. |
ai.yearsExperienceMin | Minimum years required, as an integer. |
ai.confidence | The model's own 0–1 confidence. Below 0.6, the job is automatically re-checked by a stronger model. |
The ai object appears only when AI normalize is on and extraction succeeded for that job. The dataset has two views: Jobs overview (the key fields as a table) and Full details (everything).
Pricing
This Actor uses pay-per-event pricing. You pay for results, not compute time.
| Event | Price | Charged when |
|---|---|---|
| Job scraped | $1.00 per 1,000 jobs ($0.001 each) | Once for each job delivered to your dataset |
| Job AI-normalized | $4.00 per 1,000 jobs ($0.004 each) | Once for each job the AI successfully enriched (only with AI normalize on) |
| Example run | Cost |
|---|---|
| 1,000 jobs, scraping only | $1.00 |
| 1,000 jobs with AI normalization | $5.00 |
| 10,000 jobs with AI normalization | $50.00 |
- If the AI fails on a job, you're not charged the AI fee for it.
- Filtered-out jobs are free.
- Max cost per run is respected. If you set a spending limit, the Actor works out how many jobs the remaining budget covers before it calls the AI, delivers exactly that many, and stops cleanly. You're never billed past your limit, and every job you're billed for arrives.
- Apify adds a tiny per-run start fee (fractions of a cent).
FAQ
Do I need my own OpenAI or Anthropic API key? No. AI normalization runs on Claude (Anthropic) and is included in the per-job price.
Which companies are supported?
Any company whose careers page runs on Greenhouse, Lever, or Ashby. That covers thousands of tech and growth companies. A company's slug is usually the last part of its board URL, like job-boards.greenhouse.io/gusto or jobs.lever.co/palantir. If you're unsure, use Auto-detect or paste the full careers URL.
What happens if a company isn't on any of the three? The Actor logs a warning, skips it, and moves on. You aren't charged for it.
How fresh is the data? It's live. Every run reads the current board, so a job removed from the board won't show up in your next run.
How do I track new jobs over time?
Schedule the Actor (for example daily) and compare runs on ats:company:jobId.
Is scraping job boards allowed? This Actor only reads public job-board endpoints that the ATS vendors publish for this purpose. It collects job data only, no personal data. You're responsible for how you use the results.
Can I use it from code, Zapier, Make, or n8n? Yes. Like any Apify Actor, you can start it and read its dataset through the Apify API, SDKs, webhooks, and integrations.
Limitations
- Multi-zone salary bands. Some postings list several geographic pay zones. The AI is told to report the overall lowest-to-highest range, but occasionally it reports only the primary zone and misses a lower minimum from a cheaper location (about 1 in 50 in testing).
- Occasional non-USD miss. Non-USD salaries are usually extracted correctly, but in testing the AI once missed a clearly stated GBP range (about 1 in 50).
- AI fields are only as good as the posting. If a posting doesn't mention remote work, years, or visas, the field is
nullorunknown. That's by design. - Three ATSs only. Workday, iCIMS, SmartRecruiters, and custom career sites aren't supported yet.
postedAtmeaning varies by ATS. Some report the publish date and others the last update.- Keyword filter checks the title and department only, not the full description, to avoid false matches.
Feedback
Found a posting the AI got wrong, or need another ATS? Open an issue on the Actor's Issues tab with the job URL. Misses get added to the test set, so every fix is measured.