ATS Jobs Scraper — Greenhouse, Lever & Ashby
Pricing
from $2.00 / 1,000 results
ATS Jobs Scraper — Greenhouse, Lever & Ashby
Pull open job postings straight from companies' public ATS boards (Greenhouse, Lever, Ashby). Full descriptions, skills, normalized salary, cross-run dedupe and webhook delivery. No browser, no proxy.
Pricing
from $2.00 / 1,000 results
Rating
0.0
(0)
Developer
Mukesh Kumar
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
3
Monthly active users
18 days ago
Last modified
Categories
Share
ATS Jobs Scraper — Greenhouse, Lever & Ashby Job Postings API
Scrape job postings directly from company career pages powered by Greenhouse, Lever, and Ashby. Get every open role with the full job description, department, location, salary, and apply URL in clean JSON — no browser, no proxy, no CAPTCHA, no anti-bot blocking. One HTTP request per board returns every job a company is hiring for.
Reads only public, company-published Applicant Tracking System (ATS) job-board APIs. Not affiliated with Greenhouse, Lever, or Ashby.
What this actor does
Pulls open positions from companies that publish their careers page on:
- Greenhouse (
boards.greenhouse.io/{company}) — used by GitLab, Stripe, Airbnb, Figma, Anthropic, Databricks, Cloudflare, Reddit, Discord, MongoDB, Datadog, Pinterest, Lyft, Robinhood, Instacart, and 1000s more. - Lever (
jobs.lever.co/{company}) — used by Spotify, Netflix, GoPuff, Ro, SwordHealth. - Ashby (
jobs.ashbyhq.com/{company}) — used by Ramp, Notion, Linear, Perplexity, Cursor, Vanta, Watershed, Replit, Cohere, Sierra.
Each scraped job is normalized into a unified schema so you can mix providers in one dataset.
Why scrape ATS boards instead of Indeed / LinkedIn / Glassdoor
Job aggregators (Indeed, LinkedIn, Glassdoor, ZipRecruiter) sit behind Cloudflare, CAPTCHAs, and aggressive rate limits, making them slow and expensive to scrape. Company ATS boards expose clean public JSON APIs that return richer data with zero blocking:
| This actor (ATS boards) | Aggregator scrapers | |
|---|---|---|
| Source | Company's own job board | Re-listed by 3rd party |
| Data freshness | Real-time (company-published) | Lagging, sometimes stale |
| Full job description | Yes, full HTML + text | Often truncated |
| Department / team / comp | Yes, when published | Rarely |
| Anti-bot | None | Cloudflare, CAPTCHA, IP bans |
| Proxies needed | No | Yes, residential |
| Cost per 10k jobs | Pennies | Dollars |
| Reliability | Stable public APIs | Frequently broken |
Use cases
- Recruiting & talent sourcing — monitor hiring at target companies and surface new roles the moment they post.
- Sales / lead generation — companies posting Sales, Marketing, or DevOps roles signal buying intent for your tool.
- Investor & market intelligence — track headcount growth across a portfolio or competitive set.
- Job aggregator websites — build a niche board (remote-only, AI startups, fintech, design, etc.) with reliable, full-fidelity data.
- HR analytics & compensation benchmarking — collect salary ranges (where published) across hundreds of companies.
- Slack / email alerts — get new postings pushed to a webhook the second they appear.
Features
- 3 ATS providers, one schema — Greenhouse, Lever, Ashby normalized to the same fields.
- Full descriptions — plain text plus optional raw HTML.
- Filters built in — by job title, location, department, keywords, remote-only, posted-within-days.
- Skill & seniority extraction —
skills[],detectedSeniority,minYearsExperienceparsed from descriptions. - Salary normalization — annualized
min/maxin your target currency (USD, EUR, GBP, INR, +12 more) using built-in or custom FX rates. - Cross-run deduplication — emit only NEW postings since the previous run for scheduled monitoring.
- Webhook delivery — POST results to Slack, Make, Zapier, or any custom endpoint on finish.
- No proxy required — public APIs, no IP rotation needed.
- Fast & cheap — single HTTP call per board returns every job with full content.
Input
Provide at least one board (tokens per provider, or full board URLs — provider auto-detected). Every other field is optional.
Minimal input
{"greenhouseBoards": ["gitlab", "stripe"],"leverBoards": ["spotify"],"ashbyBoards": ["Ramp"]}
Full input with all options
{"greenhouseBoards": ["gitlab", "stripe", "figma"],"leverBoards": ["spotify"],"ashbyBoards": ["Ramp", "Notion"],"boardUrls": ["https://boards.greenhouse.io/anthropic","https://jobs.lever.co/leverdemo","https://jobs.ashbyhq.com/Linear"],"jobTitle": "software engineer","location": "remote","searchKeywords": ["python", "kubernetes"],"departmentFilter": "Engineering","remoteOnly": true,"postedWithinDays": 14,"maxJobsPerBoard": 0,"maxJobs": 0,"extractSkills": true,"normalizeSalary": true,"targetCurrency": "USD","fxRatesOverride": {},"includeDescriptionHtml": false,"deduplicate": true,"onlyNewSinceLastRun": false,"dedupeStoreName": "ats-seen-jobs","notifyWebhookUrl": "","maxConcurrency": 10,"proxyConfiguration": { "useApifyProxy": false }}
Input fields
Boards (at least one required)
| Field | Type | Default | Description |
|---|---|---|---|
greenhouseBoards | string[] | ["gitlab", "stripe", "figma"] | Greenhouse board tokens (slug from boards.greenhouse.io/{slug}). |
leverBoards | string[] | ["spotify"] | Lever company slugs (from jobs.lever.co/{slug}). |
ashbyBoards | string[] | ["Ramp", "Notion"] | Ashby org slugs, case-sensitive (from jobs.ashbyhq.com/{Slug}). |
boardUrls | string[] | [] | Any board URL; provider is auto-detected from the host. |
Filters
| Field | Type | Default | Description |
|---|---|---|---|
jobTitle | string | "" | Keep only jobs whose title contains this text (case-insensitive). |
location | string | "" | Keep only jobs whose location contains this text. |
searchKeywords | string[] | [] | Keep jobs whose title OR description contains ANY keyword. |
departmentFilter | string | "" | Keep only jobs whose department contains this text. |
remoteOnly | boolean | false | Keep only roles detected as remote. |
postedWithinDays | integer | 0 | Recency filter; 0 = no limit. |
maxJobsPerBoard | integer | 0 | Cap per board; 0 = no limit. |
maxJobs | integer | 0 | Total cap across all boards; 0 = no limit. |
Enrichment & output
| Field | Type | Default | Description |
|---|---|---|---|
extractSkills | boolean | true | Parse description into skills[], detectedSeniority, minYearsExperience. |
normalizeSalary | boolean | true | Add normalizedSalary{} with annualized min/max in target currency. |
targetCurrency | string | "USD" | Output currency: USD, EUR, GBP, CAD, AUD, INR, SGD, ZAR, BRL, MXN, AED, JPY, CHF, SEK, PLN. |
fxRatesOverride | object | {} | Override built-in FX rates, e.g. {"EUR": 0.92} (units per 1 USD). |
includeDescriptionHtml | boolean | false | Include raw HTML description alongside plain text. |
Deduplication & monitoring
| Field | Type | Default | Description |
|---|---|---|---|
deduplicate | boolean | true | Drop duplicates within the current run. |
onlyNewSinceLastRun | boolean | false | Cross-run dedupe — emit only postings not seen in previous runs. |
dedupeStoreName | string | "ats-seen-jobs" | Named key-value store for cross-run seen-job IDs. |
notifyWebhookUrl | string (secret) | "" | POST a JSON summary of this run's jobs to Slack / Make / Zapier / custom endpoint. |
Performance
| Field | Type | Default | Description |
|---|---|---|---|
maxConcurrency | integer | 10 | Parallel board requests (1–50). |
proxyConfiguration | object | { "useApifyProxy": false } | Optional proxy. Not required — these are public APIs. |
Output
One record per job, normalized across providers, written to the default dataset.
Full output example
{"source": "greenhouse","boardToken": "gitlab","company": "GitLab","jobId": "8503792002","title": "Senior Backend Engineer, Platform","department": "Engineering","team": "Platform Infrastructure","location": "Remote, Americas","isRemote": true,"employmentType": "Full-time","descriptionText": "GitLab is hiring a Senior Backend Engineer to work on our platform infrastructure team. You will design and build scalable Ruby on Rails services...","descriptionHtml": "<p>GitLab is hiring a <strong>Senior Backend Engineer</strong>...</p>","salary": {"min": 134400,"max": 287700,"currency": "USD","period": "year","raw": "$134,400 - $287,700 USD"},"normalizedSalary": {"min": 134400,"max": 287700,"currency": "USD","period": "year"},"skills": ["Ruby on Rails", "PostgreSQL", "Kubernetes", "Go", "GraphQL"],"detectedSeniority": "senior","minYearsExperience": 5,"applyUrl": "https://job-boards.greenhouse.io/gitlab/jobs/8503792002","jobUrl": "https://job-boards.greenhouse.io/gitlab/jobs/8503792002","postedAt": "2026-04-30T22:34:50.000Z","updatedAt": "2026-05-15T10:12:00.000Z","scrapedAt": "2026-05-21T10:00:00.000Z"}
Output fields
| Field | Type | Description |
|---|---|---|
source | "greenhouse" | "lever" | "ashby" | Which ATS provider the job was scraped from. |
boardToken | string | Provider slug used to fetch the board. |
company | string | Human-readable company name. |
jobId | string | Provider's stable job identifier. |
title | string | Job title. |
department | string | null | Department name (e.g. Engineering, Sales). |
team | string | null | Sub-team within department. |
location | string | Location string as published. |
isRemote | boolean | Heuristic remote detection from location & description. |
employmentType | string | null | E.g. Full-time, Part-time, Contract, Internship. |
descriptionText | string | Full job description as plain text. |
descriptionHtml | string | null | Raw HTML description (only when includeDescriptionHtml: true). |
salary | object | null | Salary as published: min, max, currency, period, raw. |
normalizedSalary | object | null | Annualized salary converted to targetCurrency. |
skills | string[] | Extracted skills (only when extractSkills: true). |
detectedSeniority | "intern" | "junior" | "mid" | "senior" | "staff" | "principal" | "lead" | null | Detected from title + description. |
minYearsExperience | integer | null | Minimum years extracted from description. |
applyUrl | string | Direct URL to apply. |
jobUrl | string | Canonical job posting URL. |
postedAt | string (ISO 8601) | null | First-published timestamp. |
updatedAt | string (ISO 8601) | null | Last-updated timestamp (when provided). |
scrapedAt | string (ISO 8601) | When this actor fetched the job. |
Export formats
The Apify dataset is available as JSON, CSV, Excel, XML, JSONL, RSS, or HTML via the dataset API, or piped directly into Google Sheets, S3, BigQuery, Airtable, or any webhook.
Popular verified company boards
All slugs below were verified live to return jobs. Drop them into the matching input field.
Greenhouse (greenhouseBoards)
gitlab · stripe · airbnb · dropbox · databricks · robinhood · instacart · reddit · figma · asana · discord · gusto · samsara · cloudflare · twitch · lyft · pinterest · datadog · mongodb · elastic · peloton · sofi · affirm · chime · betterment · flexport · amplitude · airtable · calendly · faire · scaleai · anthropic
Ashby (ashbyBoards, case-sensitive)
Ramp · Vanta · Linear · Watershed · Replit · Modal · Baseten · Browserbase · Notion · Perplexity · Cohere · Zip · Sierra · Decagon · Cursor
Lever (leverBoards)
spotify · gopuff · ro · swordhealth
Companies migrate between ATS providers over time. If a slug returns nothing, check the company's current careers page URL (
boards.greenhouse.io/…,jobs.lever.co/…,jobs.ashbyhq.com/…) and use the new slug.
How it works
Each provider exposes a public, unauthenticated JSON endpoint returning all open postings with full content in a single request — no pagination, no detail-page fetch, no JavaScript rendering:
- Greenhouse:
https://boards-api.greenhouse.io/v1/boards/{token}/jobs?content=true - Lever:
https://api.lever.co/v0/postings/{company}?mode=json - Ashby:
https://api.ashbyhq.com/posting-api/job-board/{org}?includeCompensation=true
Built on Crawlee's HttpCrawler (no browser, no Playwright). Skill extraction, salary normalization, deduplication, and webhook delivery are shared modules applied uniformly to every provider's output.
Scheduled monitoring — only NEW jobs
- Set
onlyNewSinceLastRun: true - Set
dedupeStoreName: "my-target-companies"(any unique name) - Optionally set
notifyWebhookUrlto a Slack / Make / Zapier webhook - Schedule the actor (every 30 min, hourly, daily — your call)
Each run persists seen jobIds to the named key-value store and emits only postings unseen in prior runs. Combined with the webhook, this gives you real-time new-role alerts for any list of companies.
Pricing
- Pay-per-result: see the Apify Store page for current price per 1,000 jobs.
- Compute: extremely low — one HTTP call per board, no browser, no proxy. Hundreds of boards scrape in under a minute.
Local development
git clone <repo>cd ats-jobs-scrapernpm install# edit storage/key_value_stores/default/INPUT.jsonnpm start
Requires Node.js 20+.
FAQ
Is scraping Greenhouse, Lever, and Ashby job boards legal? This actor only fetches publicly accessible, company-published job-board APIs — the same endpoints the companies' own careers pages call from the browser. No login, no rate-limit evasion, no anti-bot bypass. You should still consult your own legal counsel for your specific use case and jurisdiction.
Do I need a proxy to scrape these ATS boards? No. These are public, unauthenticated APIs designed to be hit from the browser. Apify Proxy is available as an option for very large board lists, but it's off by default.
How fast is it? One HTTP request per board returns every job with the full description. A list of 100 boards typically completes in under a minute on the default concurrency of 10.
How do I find a company's board slug?
Open their careers page. If the URL is boards.greenhouse.io/acme → Greenhouse slug is acme. If jobs.lever.co/acme → Lever slug is acme. If jobs.ashbyhq.com/Acme → Ashby slug is Acme (case-sensitive). You can also just paste the full URL into boardUrls and the provider is auto-detected.
Can I scrape Workday, Greenhouse-embedded iframes, or Indeed? This actor covers Greenhouse, Lever, and Ashby — the three providers with the cleanest public JSON APIs. Workday, SmartRecruiters, BambooHR, and aggregators like Indeed require different scraping strategies and are outside this actor's scope.
Does it return salary?
Yes, when the company publishes it in the posting (now mandatory in jurisdictions like NYC, California, Colorado, Washington, and many EU countries). Both raw salary and annualized normalizedSalary in your target currency are returned.
Can I get only new jobs since last run?
Yes — set onlyNewSinceLastRun: true plus a dedupeStoreName. Ideal for scheduled monitoring with Slack / Zapier / webhook delivery.
Does it support full-text search across all companies?
There is no cross-company search API on Greenhouse / Lever / Ashby — each board is fetched independently. Use jobTitle, location, searchKeywords, and departmentFilter to filter results from the boards you select.
Which fields work with which providers?
All listed output fields are populated when the provider publishes them. Coverage of department, team, salary, employmentType, and updatedAt varies by provider and by company configuration; the normalized schema always has the field (with null when absent) so downstream code is consistent.
What happens if a board returns nothing? The most common cause is that the company migrated to a different ATS. Check their live careers page URL and update the slug. Failed boards never abort the run — other boards continue.
Related actors
- Greenhouse Jobs Scraper
- Lever Jobs Scraper
- Ashby Jobs Scraper
- LinkedIn Jobs Scraper
- Indeed Jobs Scraper
- Glassdoor Jobs Scraper
Keywords
job postings scraper, ATS scraper, Greenhouse API scraper, Lever API scraper, Ashby API scraper, careers page scraper, hiring data, recruiting data, applicant tracking system, remote jobs scraper, tech jobs scraper, salary data scraper, job board API, jobs JSON API, company hiring monitor, new job alerts, jobs webhook, Slack jobs notifier