ATS Jobs Scraper: Greenhouse, Lever, Workday & 8 more
Pricing
Pay per event
ATS Jobs Scraper: Greenhouse, Lever, Workday & 8 more
Scrape job listings from company career pages on 11 ATS (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable…) in one schema: salary per year, skills, remote, new and closed jobs. Export to JSON, CSV or Excel.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Nice Dev
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
💼 What is ATS Jobs Scraper?
ATS Jobs Scraper extracts job postings from company career pages hosted on 11 ATS — Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling and Teamtailor — into one schema: title, company, locations, salary converted to a yearly amount, remote / hybrid / on-site, seniority, years of experience, skills, full description and more. It works as a Greenhouse, Lever, Ashby and Workday jobs API alternative: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.
Type company names (stripe, ramp, spotify) and the Actor finds which ATS hosts each one — or paste career page links, or tick Search all companies in our directory to search 17,463 companies at once. Click Start and download the jobs in JSON, CSV or Excel. No login, nothing to set up.
📋 What data can you extract from career pages?
One item per job, 79 fields, the same whatever the ATS:
| Category | What you get |
|---|---|
| 🏷️ Job | title, job link, apply link, an ID unique across every ATS and company, status (open, updated, taken down) — Software Engineer, AI Connections (Developer Platform) |
| 🏢 Company | name, career page, ATS, number of open jobs on the whole board, hiring entity, website, description — Notion, 137 open jobs |
| 📍 Location | main location and every other one, city, region, postal code, country and country code, map coordinates when published — San Francisco, California |
| 🏠 Remote and contract | remote / hybrid / on-site, fully remote or not, contract type (full-time, part-time, contract, internship…) normalized and as published — hybrid, full-time |
| 🎓 Profile asked | seniority (intern to executive), years of experience, highest degree, skills, visa sponsorship, security clearance — 10 years, master, TypeScript |
| 💰 Salary | minimum and maximum, currency, period, the same converted to a year, where it was read, every pay range by location or tier, equity — $272,000 – $304,000 per year |
| 🗂️ Team | department, team, job function, industry, requisition ID, recruiter name, the company's own custom fields |
| 🕒 Dates | published, updated, "Posted 3 Days Ago" as shown, days since posted, application deadline — what the date filters read |
| 📝 Text | full description as plain text and HTML, requirements, benefits, titled sections, posting language |
| 📋 Application form | the questions of the application form: label, type, required or not, choices (option) |
| ✉️ Company contacts | public e-mails, phone numbers and social links found on the company's website (option) |
| 🔔 Monitoring | first seen, last seen, taken down on, the keywords a job matched, what you typed that led to it |
Every field, with an example, is listed in the Output section below.
Seniority, workplace type, contract type and language come from the ATS when it gives them; otherwise they are detected from the job text, like the years of experience, highest degree, skills, visa sponsorship and security clearance (empty when the text says nothing).
The description comes with the job list on Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor. On Workday, SmartRecruiters, Workable, BambooHR and Rippling, tick Extract job details (paid option, off by default) to open each job page for the description and, depending on the ATS, the exact posting date, requirements, benefits or extra locations.
✅ Why use ATS Jobs Scraper?
- 🧩 11 ATS, one schema: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling and Teamtailor jobs land in the same columns — one dataset, one import.
- 🔎 Type a name, not a URL:
stripeis enough — the Actor tries the ATS you allow and finds the career page. A domain (stripe.com), a forced ATS (greenhouse:airbnb) or any career page or job link work too. A Workday company is found by name only when it is in the directory; otherwise paste its career page link. A name found nowhere is listed, and the run goes on. - 📚 Jobs at companies you don't know yet: a built-in directory of 17,463 company career pages (over 1 million open jobs when they were checked), searched with your keywords and filters.
- 💵 Salaries you can compare: hourly, daily, weekly and monthly pay converted to a year, every pay range kept, and where the amount was read.
- 🏭 Big Workday boards in full: Workday shows at most 2,000 jobs per search; past that, the Actor splits the board by country, then by job family, and saves each job once.
- 🎯 The same filters on every ATS: whole-word keywords and excluded words, places and countries, remote, contract, seniority, language, years of experience, skills, visa sponsorship, yearly salary, dates, company size.
- 🔔 Monitoring built in: tick Only new jobs and schedule the Actor: each run returns only the jobs never delivered before — and, if you want, the jobs updated and taken down since.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON / CSV / Excel export via the Apify platform.
🚀 How to scrape jobs from Greenhouse, Lever, Workday and other ATS
- Create a free Apify account.
- Open ATS Jobs Scraper and type company names in Companies (e.g.
stripe), paste career page links into Career page URLs, or tick Search all companies in our directory. - Add a Job keyword (e.g.
engineer) and the filters you need: location, remote, seniority, salary, dates… - Set how many job listings to save — Max jobs (100 by default, 0 = no limit) — then click Start.
- Download the dataset in JSON, CSV, Excel or via API.
💰 How much does it cost to scrape job postings?
This Actor uses pay per event pricing: you pay for what it delivers, and the price of each event is in the Pricing tab. What is charged:
- each job saved in the dataset — a job saved again because it changed (Also report updated jobs) counts as a job;
- each job page opened with Extract job details, on top of the job — only on Workday, SmartRecruiters, Workable, BambooHR and Rippling, and only when the page was really read;
- each job delivered with its application questions (Application form questions), on top of the job — a job without questions pays nothing more;
- each company summary written (Hiring summary per company);
- each company with at least one e-mail found (Company contact e-mails), once per company — phone numbers and social links alone are free;
- each job taken down reported (Report jobs taken down), instead of the price of a job;
- a small fee per run start, and a small fee for each job that one of your filters checks and drops (
filter-check, ordetail-filter-checkwhen the filter needed the job page).
A job already delivered, with Only new jobs, is neither saved nor charged. Platform usage is included in the price.
⚙️ Input
{"companies": ["stripe", "ramp", "spotify"],"query": "engineer","workplaceTypes": ["remote", "hybrid"],"maxItems": 200}
Search the whole directory: data engineers in the US, paid at least $150,000 a year, posted in the last 7 days:
{"searchAllCompanies": true,"maxCompanies": 2000,"atsPlatforms": ["greenhouse", "ashby", "lever"],"searchQueries": ["data engineer", "analytics engineer"],"countries": ["US"],"minSalary": 150000,"salaryCurrency": "USD","postedAfter": "7 days","maxItems": 500}
Or with career page links, as a daily monitor of new, updated and taken-down jobs:
{"startUrls": [{ "url": "https://job-boards.greenhouse.io/airbnb" },{ "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" }],"maxItems": 0,"onlyNew": true,"includeUpdatedJobs": true,"includeClosedJobs": true,"stateKey": "airbnb-nvidia"}
| Field | Notes |
|---|---|
companies | Company names (stripe, ramp), website domains (stripe.com) or a forced ATS with its prefix (greenhouse:airbnb, ashby:notion, workday:nvidia.wd5/NVIDIAExternalCareerSite). A career page link works here too, with or without https:// (jobs.lever.co/spotify); a name with a colon that is no ATS prefix (Re:Work) is read as a name. Each name is looked for on the ATS ticked in ATS platforms; a Workday company is found by name only when it is in the built-in directory, otherwise give its career page link (here or in Career page URLs). A name found nowhere is listed in the FAILED_REQUESTS record of the run and the run goes on. Max 5,000. |
startUrls | Career pages or job pages of the 11 ATS: https://job-boards.greenhouse.io/airbnb, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/ramp, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://apply.workable.com/huggingface. A job link reads the whole board of its company. Workday needs the full link (company and site): it is the way to read a Workday company that is not in the directory. Max 5,000. |
searchAllCompanies, maxCompanies | Also read the companies of the built-in directory (17,463 career pages checked on 21-22 October 2026), the largest boards first, restricted by atsPlatforms, includeCompanies and excludeCompanies. maxCompanies = how many (500 by default, 0 = the whole directory). |
atsPlatforms | greenhouse, lever, ashby, workday, smartrecruiters, recruitee, workable, personio, bamboohr, rippling, teamtailor: the ATS a company name is looked for on, and the ATS of the directory companies. Empty = all eleven. |
query, searchQueries, searchInDescription | Keep the jobs whose title, department or team contains the word or phrase (engineer, data scientist; whole words, case and accents ignored). searchQueries adds more keywords: a job matching any of them is kept, once (up to 100 in searchQueries, plus query). searchInDescription reads the description too; on Workday, SmartRecruiters, Workable, BambooHR and Rippling it turns extractDetails on. Empty = all jobs. |
excludeKeywords | Drop the jobs whose title contains one of these whole words (intern, sales); the description too with searchInDescription. |
location, locations | Keep the jobs with a location containing this text (London, Germany, Remote; case and accents ignored); locations adds more places (up to 100, plus location), a job matching any of them is kept. |
countries | ISO codes (US, GB, DE) or English names (Germany): a job with several locations is kept when one of them matches; a job whose country cannot be read is dropped. |
excludeLocations | Drop the jobs whose every location contains one of these words (India). On Workday, SmartRecruiters, Workable, BambooHR and Rippling, a job whose list entry shows no location is checked on its job page (one more request, charged as a filter check only if the job is dropped). |
workplaceTypes, remoteOnly | remote, hybrid, onsite: from the ATS when it says it, otherwise from the location and title. remoteOnly adds remote to workplaceTypes: alone, it keeps the remote jobs only; with hybrid ticked too, it keeps both. |
employmentTypes | full-time, part-time, contract, temporary, internship, apprenticeship, volunteer: from the ATS when it gives it, otherwise from the title. A job whose type is found neither on its ATS nor in its title is dropped once this list is set. |
seniority | intern, junior, mid, senior, lead, manager, director, executive: from the ATS level when there is one, otherwise from the title. A job with no level is dropped once this list is set. |
departments | Keep the jobs whose department, team or job function contains one of these words (Engineering, Sales). Workday gives no department: its jobs are dropped once this list is set. |
skills | Keep the jobs that name at least one of these skills in the title or description (Python, Salesforce, Kubernetes; whole words). |
languages | Language of the posting, ISO codes (en, de, fr): from the ATS when it gives it, otherwise detected from the description. |
maxYearsExperience | 3 keeps the jobs that ask 3 years of experience or less; a job that writes no number is kept. On Workday, SmartRecruiters, Workable, BambooHR and Rippling, whose job list has no description, the job page of each job is read for it (one more request, charged as a filter check only if the job is dropped). 0 = no limit. |
visaSponsorshipOnly | Keep only the jobs that say they sponsor visas. |
salaryCurrency, minSalary, maxSalary, keepJobsWithoutSalary, onlyWithSalary | Yearly salary bounds in this currency (USD by default, EUR, GBP…), hourly to monthly pay converted to a year first: minSalary reads the top of the range, maxSalary the bottom. A job in another currency or without a salary is dropped; keepJobsWithoutSalary keeps the jobs without a salary. onlyWithSalary keeps only the jobs that show a salary. |
minOpenJobs | 50 keeps the companies with at least 50 open jobs on their board, counted before your filters. 0 = all companies. |
includeCompanies, excludeCompanies | Keep, or drop, the jobs of the companies whose name or slug contains one of these words (Stripe) — dropping staffing agencies is a common use. |
postedAfter, postedBefore | Publication date range: 2026-09-01 (the whole day is included) or a period before now (7 days, 24 hours, 2 weeks). Reads publishedAt; a job without a date is dropped. |
updatedAfter | Jobs updated on their ATS since this date or period (3 days), read on updatedAt, else on publishedAt. |
extractDetails | Paid option, off by default. Opens each job page on Workday, SmartRecruiters, Workable, BambooHR and Rippling, whose job list has no description: description, exact posting date, requirements, benefits or extra locations, depending on the ATS. Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor always give the full description. |
includeApplicationQuestions | Paid option, off by default. Greenhouse, Ashby, Recruitee, Rippling and BambooHR: the questions of the application form (label, type, required, choices), plus the pay ranges Greenhouse publishes. Charged per job that has questions. |
descriptionFormat, descriptionMaxLength | both (default), text, html or none: which description columns to save (description, descriptionHtml). descriptionMaxLength cuts the plain text to that many characters (0 = the full text, up to 32,000 characters); descriptionHtml is kept up to 200,000 characters. |
includeCompanySummary | Paid option, off by default. One summary per company with jobs in the results, counted on the jobs this run delivered (after your filters, maxItems and onlyNew); only its count of open jobs is the whole board, before your filters. Jobs by department, country, workplace type, seniority and contract type, share of remote jobs, jobs posted in the last 7 and 30 days, new and taken down since the last run, salary range. Saved in the COMPANY_SUMMARIES record of the key-value store (linked in the Output tab). If the jobs reach the maximum cost set for the run, some summaries can be left out: the log says how many. |
enrichEmails | Paid option, off by default. For each company whose website is known (the domain typed in Companies, Ashby's company profile, or the careers page linked by Greenhouse or Recruitee), reads its contact and about pages: public e-mails, phone numbers, social links. Charged once per company with at least one e-mail found; phone numbers and social links alone are free. |
maxItems, maxItemsPerQuery | Jobs saved for the whole run (0 = no limit), and the cap of each company board, so that one big employer cannot use up the whole budget (0 = none). |
onlyNew, stateKey, resetState | Monitoring: only the jobs never delivered under this memory key (fintech-engineers); resetState forgets the memory. |
includeUpdatedJobs, includeClosedJobs | With onlyNew: also save again a job already delivered whose content changed (status updated, charged as a job), and report once each job taken down from its board (status closed, paid option, charged per job taken down). Up to 32 records of 4,000 followed jobs each: see Known limitations. |
| Advanced | proxyConfiguration (none by default: add one if your runs are rate-limited), maxConcurrency, maxRequestsPerMinute, minRequestIntervalMs, maxRequestRetries, debugLog. |
📦 Output
One real job (Notion, on Ashby), shortened: some columns are left out (most of them empty for this job) and the description is cut.
{"id": "1fc309c8-da20-4ff2-84c7-8b863ece2b0a","globalId": "ashby:notion:1fc309c8-da20-4ff2-84c7-8b863ece2b0a","url": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a","applyUrl": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a/application","status": "open","ats": "ashby","companySlug": "notion","companyName": "Notion","companyOpenJobs": 137,"boardUrl": "https://jobs.ashbyhq.com/notion","title": "Software Engineer, AI Connections (Developer Platform)","department": "Engineering","departments": ["Engineering"],"team": "Engineering","location": "San Francisco, California","locations": ["San Francisco, California", "New York, New York"],"city": "San Francisco","region": "California","country": "United States","countryCode": "US","countryCodes": ["US"],"workplaceType": "hybrid","isRemote": false,"employmentType": "full-time","employmentTypeRaw": "FullTime","minYearsExperience": 10,"maxYearsExperience": 10,"educationLevel": "master","skills": ["TypeScript", "LLM"],"salaryMin": 272000,"salaryMax": 304000,"salaryCurrency": "USD","salaryPeriod": "year","salaryMinYearly": 272000,"salaryMaxYearly": 304000,"salaryText": "$272,000 – $304,000 per year","salarySource": "description","salaryRanges": [{ "title": null, "min": 272000, "max": 304000, "currency": "USD", "period": "year" }],"publishedAt": "2026-08-24T14:44:49.699Z","postedDaysAgo": 58,"language": "en","description": "WHO WE ARE\n\nNotion is the collaborative AI workspace where teams and agents think together https://www.youtube.com/watch?v=vkpYpWfEK5s. We're building one place where your knowledge, projects, meetings, and AI tools live side by side, so work is faster, clearer, and less fragmented. …","descriptionHtml": "<h1>Who We Are</h1><p style=\"min-height:1.5em\">Notion is the collaborative AI workspace where teams and agents …","sections": [],"customFields": {},"applicationQuestions": [],"companyEmails": [],"companyPhones": [],"companySocialLinks": [],"matchedKeywords": [],"sourceInput": "ashby:notion","scrapedAt": "2026-10-21T22:58:00.128Z"}
You can download the dataset in various formats such as JSON, HTML, CSV or Excel. The Output tab also has a salaries view.
All 79 fields
| Fields | What you get |
|---|---|
id, globalId | the job's ID on its ATS, and ats:companySlug:id — unique across every ATS and company, the key to merge runs: ashby:notion:1fc309c8-… |
url, applyUrl | the job page and the application form |
status | open, updated (delivered before and changed since) or closed (taken down from its board) |
ats, companySlug, boardUrl, sourceApiUrl | ashby, notion, https://jobs.ashbyhq.com/notion, and the address the job was read from |
companyName, hiringOrganization, companyOpenJobs | Company: Notion, the hiring entity when named apart (Personio; Workday with Extract job details), 137 open jobs on the whole board, before your filters |
companyWebsite, companyDomain, companyLogoUrl, companyDescription | website and domain (the domain you typed, Ashby's company profile with Company contact e-mails, or the careers page linked by Greenhouse or Recruitee), logo (not filled yet: always empty), about-the-company text (SmartRecruiters and Rippling, with Extract job details) |
title | Software Engineer, AI Connections (Developer Platform) |
department, departments, team, jobFunction, industry | Team: Engineering, every department (parent first), team, job function or category, industry (SmartRecruiters) |
location, locations, city, region, postalCode | Location: San Francisco, California, every location of the job, San Francisco, California, postal code |
country, countryCode, countryCodes, latitude, longitude | United States, US, the codes of every location, coordinates (SmartRecruiters) |
workplaceType, isRemote | remote, hybrid or onsite; true when the job can be done fully remote |
employmentType, employmentTypeRaw | full-time, part-time, contract, temporary, internship, apprenticeship or volunteer; as published: FullTime |
seniority, experienceLevelRaw | intern, junior, mid, senior, lead, manager, director or executive; the level as published |
minYearsExperience, maxYearsExperience, educationLevel | Profile asked: 10, 10 (3-5 years gives 3 and 5), master (high-school, bachelor, master or phd) |
skills | ["TypeScript", "LLM"], from a fixed list of common skills |
visaSponsorship, securityClearance | true, false, or null when the job says nothing |
recruiterName | the recruiter who published the job (SmartRecruiters) |
salaryMin, salaryMax, salaryCurrency, salaryPeriod | Salary: 272000, 304000, USD, year (or month, week, day, hour) |
salaryMinYearly, salaryMaxYearly | converted to a year (hour × 2,080, day × 260, week × 52, month × 12): $33.65 - $38.70 per hour gives 69992 and 80496 |
salaryText, salarySource, salaryRanges, offersEquity | $272,000 – $304,000 per year; ats, pay-transparency or description; every pay range (by location or tier); equity (Ashby) |
publishedAt, updatedAt, postedOnText, postedDaysAgo | Dates: 2026-08-24T14:44:49.699Z (the day alone, 2026-09-21, when the ATS gives no time: Workable, BambooHR, Workday), last update (Greenhouse and Recruitee), Posted 30+ Days Ago (Workday), 58 |
applicationDeadline, requisitionId, internalJobId | last day to apply, as written by the job (2026-11-30; Greenhouse and Recruitee), the company's reference of the opening, its internal ID |
language | en |
description, descriptionHtml | Text: the full description, plain text and HTML (HTML up to 200,000 characters) |
requirements, benefits, sections | requirements and benefits when the ATS publishes them apart, the titled sections of the description |
customFields | the fields the company added on its ATS, name → value |
applicationQuestions | with Application form questions: label, type, required, choices |
companyEmails, companyPhones, companySocialLinks | with Company contact e-mails: public e-mails, phone numbers, LinkedIn, X, Facebook… pages |
matchedKeywords, sourceInput | the keywords the job matched; the company or link you typed (directory for the directory) |
firstSeenAt, lastSeenAt, closedAt | with Only new jobs: first delivered, last run that found it, taken down at |
scrapedAt | ISO timestamp of the extraction |
💡 Tips
Search the whole directory
Tick Search all companies in our directory to read the career pages of 17,463 companies checked on 21-22 October 2026 (about 1,009,000 open jobs between them when they were checked), the largest boards first, up to Max companies from the directory (500 by default, 0 = all). Narrow them down with ATS platforms, Only these companies and Exclude companies, then keep the jobs you want with keywords and filters.
| ATS | Companies | Open jobs when checked |
|---|---|---|
| Workable | 3,684 | 65,934 |
| Greenhouse | 3,548 | 145,226 |
| BambooHR | 2,556 | 18,496 |
| Workday | 1,962 | 498,730 |
| Ashby | 1,783 | 42,813 |
| Personio | 1,619 | 15,302 |
| Teamtailor | 634 | 7,784 |
| SmartRecruiters | 611 | 185,711 |
| Rippling | 400 | 5,239 |
| Recruitee | 372 | 8,006 |
| Lever | 294 | 15,690 |
How to get more results
Set maxItems to 0, leave maxItemsPerQuery at 0, and use broad keywords. Big Workday boards are read past 2,000 jobs, nothing to set. With searchInDescription, a keyword written only in the description is found too.
How to reduce costs
The price is per job, so the levers are maxItems, maxItemsPerQuery, the filters (a job a filter drops costs only the small filter fee) and onlyNew for recurring runs (you never pay twice for the same job, unless it changed and you ticked includeUpdatedJobs). Leave the paid options off unless you need them: Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor already give the full description.
Several keywords and places in one run
Fill searchQueries and / or locations, up to 100 each (plus the single query and location): a job is kept when it matches any keyword and any place, and is saved — and charged — once, with the keywords it matched in matchedKeywords. The single query and location fields still work and are added to the lists. Set maxItemsPerQuery to give every company board its own cap: without it, the first big boards can use up the whole maxItems budget.
Monitoring: new, updated and taken-down jobs
Tick Only new jobs (onlyNew) and schedule the Actor. The first run returns everything; each later run skips the jobs already delivered: they are not saved and not charged. The memory lives in a named key-value store of your account (ats-jobs-scraper-seen, up to 150,000 listings per key) and is only updated with jobs that really reached the dataset, so a failed run never hides anything. Give each schedule its own stateKey (two schedules sharing a key would hide each other's jobs), and tick resetState once to start over.
Add Also report updated jobs to get a job again when its title, locations, salary, description or dates changed (status = updated), and Report jobs taken down to get, once, each delivered job that is no longer on its company board (status = closed, with closedAt). Tick them from the first run of the schedule: jobs are followed from a run that has one of them ticked. A board is judged only when the run read it in full: a board that failed, was cut by a cap, was searched for a keyword on the ATS itself, or is a Workday board of 2,000 jobs or more reports no job taken down. Up to 4,000 jobs are followed in each of 32 records (a company board always in the same one): past that, the next jobs of a full record are not reported as updated or taken down.
Salary filters
minSalary and maxSalary compare the yearly amount (hour × 2,080, day × 260, week × 52, month × 12) in salaryCurrency (USD by default). There is no currency conversion: a job paid in another currency is dropped, and so is a job without a salary unless you tick keepJobsWithoutSalary. The salary comes from the ATS's pay fields, from the pay ranges Greenhouse publishes (with includeApplicationQuestions), or from an amount written in the description — salarySource tells which.
Filter by publication date
postedAfter and postedBefore take a date (2026-09-01, the whole day is included) or a period before now (7 days, 2 weeks, 24 hours). They read publishedAt; on Workday without Extract job details, that is the day computed from "Posted 3 Days Ago" ("30+ Days Ago" counts as 30 days) — unless one of your date bounds is more than 30 days ago: then the page of each "30+ Days Ago" job is opened to read its exact date (one more request per such job, not charged as Extract job details). A job without a date is dropped as soon as a date bound is set. updatedAfter reads updatedAt, or publishedAt when the ATS gives no update date. Filtered-out jobs are not saved and do not count in maxItems.
🔌 Integrations and API
Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.
🤖 Use with AI agents (MCP)
AI agents and assistants (any MCP client) can find and run this Actor through the Apify MCP server, billed to their Apify account like any run. It returns one item per job posting. Actor id: nice_dev/ats-jobs-scraper; MCP server with this Actor only: https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/ats-jobs-scraper.
Smallest input, for a cheap first call:
{"companies": ["stripe"],"maxItems": 10}
Key output fields: title, companyName, url, location, workplaceType, salaryMinYearly, publishedAt, description.
Cost: pay per event — see the pricing section above and the Pricing tab. Cap each call with maxItems and, through the API, with the run option maxTotalChargeUsd.
❓ FAQ
Is it legal to scrape job postings from career pages?
The Actor only reads the job postings that companies publish on their public career pages for anyone to see. It logs in to nothing and solves no captcha. Results can contain personal data — the name of a recruiter (SmartRecruiters) and, with Company contact e-mails, the public e-mails and phone numbers of a company — which is protected by GDPR: do not store it without a legitimate reason. You are responsible for using the data in compliance with the Terms of Use of each career site and ATS and with applicable law. This Actor is not affiliated with Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee, Workable, Personio, BambooHR, Rippling, Teamtailor or the companies whose jobs it reads.
Does it need a login or a proxy?
No login, and no proxy by default. A request a site turns away is retried after a pause of 5 seconds, doubled at each retry up to 150 seconds. If your runs are rate-limited (many companies, frequent schedules), add a proxy in Proxy configuration: a refused request is then retried at once on a new proxy session, up to 10 times on top of the retries.
Is the data safe to open in Excel or to show on a web page?
Titles and descriptions are the companies' own words, copied as they are. A text can begin with -, +, = or @: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. descriptionHtml is the HTML the ATS publishes, left as it is by the Actor (only cut past 200,000 characters): sanitize it before showing it on a web page, and escape every other field like any text written by a stranger.
Known limitations
- Workday shows at most 2,000 jobs per search: past that, the Actor splits the board by country, then by job family. If the pieces cannot cover the whole board, the log says that some jobs may be missing. On such a board, a run capped at 20 jobs or fewer without filters gets the first jobs of the career page; with a higher cap or filters, the jobs come from the pieces in no fixed order.
- Workable limits each IP to a few hundred requests a day. If a Workable board is still refused, the run goes on with the other boards and its log tells you to add a proxy or to run again the next day.
- With a single keyword, Workday, SmartRecruiters and Workable boards are searched for it on the ATS itself, and
companyOpenJobsis then empty for them. SetminOpenJobsand the whole board is read so that it can be counted. - Workday companies are found by name only when they are in the built-in directory: for another one, give its career page link.
- Updated and taken-down jobs are followed in 32 records of up to 4,000 jobs each, a company board always in the same record. Once a record is full, the next jobs put in it are not followed: they are never reported as updated or taken down, and the log warns once.
descriptionMaxLength= 0 gives the full text up to 32,000 characters: a longer description is cut there.- Fields detected from the job text are empty when the text does not say it: a job that names no degree has no
educationLevel. onlyNewremembers job IDs: a job that changed comes back only withincludeUpdatedJobs.- Two runs sharing the same
stateKeyat the same time may both return the same new job.
A run that reaches its timeout stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with Only new jobs, remembered, and the run ends Succeeded with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).
A run the platform stops without warning (out of memory)
- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the jobs already saved are skipped: none is delivered or charged twice, and
maxItemsstill counts them. - With
onlyNew, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the jobs it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the jobs of its last 2 seconds once more.
Something doesn't work?
The last line of the log counts the jobs saved and the requests that failed after every retry. Those requests, and the company names found on no ATS, are listed with the reason in the FAILED_REQUESTS record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause.
If an ATS changes its job pages, you are told instead of paying for blank rows. If the first 20 listings read all lack their title, or their publication date on the nine ATS whose job list shows it (all but BambooHR and Rippling), the run saves nothing more, stops and fails, and its last message names the missing field: at most those first jobs are charged. A job that postedAfter / postedBefore drops because it has no date at all counts among those 20. A run of fewer jobs (a scheduled Only new jobs run that finds a few new ones, a small Max jobs) is checked at its end, from 5 listings: its jobs are already saved, and the run fails with the missing field instead of ending green.
🛟 Support
Open an issue in the Issues tab with a link to your run: the run log and the FAILED_REQUESTS record of the key-value store show exactly which companies or URLs failed and why.