Career Site Job Scraper: Greenhouse, Lever, Ashby, Workday
Pricing
from $1.50 / 1,000 job results
Career Site Job Scraper: Greenhouse, Lever, Ashby, Workday
Get every open job from company career sites on Greenhouse, Lever, Ashby, Workday and SmartRecruiters via their public job-board feeds. Normalized fields, salary ranges, clean descriptions, filters, and new/closed job tracking between runs. $1.50 per 1,000 jobs.
Pricing
from $1.50 / 1,000 job results
Rating
0.0
(0)
Developer
Naveen Raja
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Career Site Job Scraper & API: Greenhouse, Lever, Ashby, Workday + new/closed job tracking
Get every open job from company career sites that run on Greenhouse, Lever, Ashby, Workday and SmartRecruiters, in one clean JSON format. The Actor reads the public job-board feeds that the companies' own careers pages use, so the data is complete, current and fast to fetch. No browser, no login, no proxy.
Switch on change tracking and every later run tells you which jobs are new and which were closed (taken down) since the previous run. Schedule it daily and you have a hiring monitor.
Price: $1.50 per 1,000 jobs ($0.0015 per job) plus $0.0005 per run. You pay only for job rows returned; Apify platform costs are included.
| What you run | Cost |
|---|---|
| 100 jobs | $0.1505 |
| Every open job at a 700-role company (e.g. Stripe) | about $1.10 |
| Daily "only new and closed" monitor of 20 companies (~50 changes a day) | about $0.08 a day |
What you get
- One normalized item per job, same fields for every ATS: company, title, department, team, locations, remote status, workplace type, employment type, posted date, job URL, apply URL, salary range (when the company publishes one) and an optional clean-text job description.
- New / existing / closed status for each job when tracking is on, with the time we first saw the job.
- Filters: keywords, excluded words, locations, departments, remote only, posted in the last N days.
- Paste careers-page URLs and the ATS is detected for you, or use short
ats:slugentries. - Built for automation and AI agents: predictable schema, pay-per-event pricing with no usage fees, works with limited permissions, a run summary record, and a clean stop when your spending limit is reached.
Supported job boards
| ATS | Example input | What the ATS publishes |
|---|---|---|
| Greenhouse | https://job-boards.greenhouse.io/stripe or greenhouse:stripe | Title, department, location, first published / updated dates, pay ranges (pay transparency), description |
| Lever | https://jobs.lever.co/palantir or lever:palantir (EU boards on jobs.eu.lever.co too) | Title, team, department, all locations, workplace type, commitment, created date, salary range, description |
| Ashby | https://jobs.ashbyhq.com/openai or ashby:openai | Title, department, team, primary + secondary locations, remote flag, workplace type, employment type, published date, compensation, description |
| Workday | https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite or workday:nvidia.wd5/NVIDIAExternalCareerSite | Title, all locations, time type, start/posted date, remote type (some sites), description |
| SmartRecruiters | https://jobs.smartrecruiters.com/ServiceNow or smartrecruiters:ServiceNow | Title, department, function, location with remote/hybrid flags, employment type, release date, description |
You can also paste a company's own careers page (for example https://www.figma.com/careers/). The Actor opens that page once and looks for an embedded Greenhouse, Lever, Ashby, Workday or SmartRecruiters board. This works for many sites but not all (some pages are built entirely in JavaScript or block automated visits); if it fails, the run summary tells you to pass the ATS URL instead.
Use cases
- Job boards and aggregators: pull complete, fresh listings straight from employers' career sites.
- Hiring signals for sales and investing: see which companies are hiring for which teams and where, and get alerted when new roles open or close.
- Recruiting and talent intelligence: track competitors' open roles, locations and published salary ranges.
- Job alerts: schedule a daily run with keywords and "Return only new and closed jobs" to get just the changes.
- AI agents and LLM apps: give an agent a reliable tool to answer "Is Stripe hiring data engineers in Dublin?" with structured data.
How to use
- Add companies in Companies (one per line). Careers-page URLs or
ats:slugentries both work. - Optional: add filters (keywords, locations, departments, remote only, posted within N days).
- Choose whether to include the job description (on by default).
- Optional: turn on Track new and closed jobs. Use the same Tracking ID on every run of the same monitor.
- Run the Actor and download the results as JSON, CSV, Excel or via API. A per-company summary is saved as the
SUMMARYrecord in the run's key-value store.
The same board entered twice (for example greenhouse:stripe and https://job-boards.greenhouse.io/stripe, or a careers page that leads to a board you also listed) is read and charged once. An entry that returns no jobs because of a problem (a wrong slug, no board found on a careers page, an error at the job board) gives one free error row in the dataset with status: "error", the input, an errorKind and the reason in error.
Input example
{"companies": ["greenhouse:stripe","https://jobs.lever.co/palantir","ashby:openai","https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite","smartrecruiters:ServiceNow"],"keywords": ["engineer", "data"],"locations": ["San Francisco", "Remote"],"includeDescription": true,"maxJobsPerCompany": 0,"trackChanges": true,"onlyNewAndClosed": false,"trackingId": "my-hiring-monitor"}
Output example
A real item from a test run in October 2026 (Ramp on Ashby, with Remote jobs only; description shortened):
{"company": "ramp","companySlug": "ramp","ats": "ashby","jobId": "d1183b00-6590-4fe4-a585-28d84e578fe3","uid": "ashby:ramp:d1183b00-6590-4fe4-a585-28d84e578fe3","title": "Software Engineer, Security, Stablecoin","department": "Engineering","team": "Backend","locations": ["New York, NY (HQ)","San Francisco, CA","Remote (US)"],"remote": true,"workplaceType": "remote","employmentType": "Full-time","postedAt": "2026-05-13T20:28:09Z","updatedAt": null,"url": "https://jobs.ashbyhq.com/ramp/d1183b00-6590-4fe4-a585-28d84e578fe3","applyUrl": "https://jobs.ashbyhq.com/ramp/d1183b00-6590-4fe4-a585-28d84e578fe3/application","compensation": {"min": 189000,"max": 330000,"currency": "USD","interval": "year","summary": "$189K – $330K • Offers Equity"},"status": "new","firstSeenAt": "2026-10-19T22:37:26Z","scrapedAt": "2026-10-19T22:37:26Z","input": "ashby:ramp","error": null,"errorKind": null,"descriptionText": "About Ramp\n\nRamp is building the smart infrastructure for finance teams, embedded in the transaction flow of every dollar a business spends. We automa ..."}
A closed job (tracking on) has the same shape with "status": "closed". It keeps the title, locations, department, team, URLs, remote status, workplace type and firstSeenAt saved when the job was first returned; the other fields are null because the posting no longer exists. (For jobs saved by builds before 1.1.2, remote is recomputed from the saved locations, often null, and workplaceType is null; their closures are always reported, also with Remote jobs only or the location "Remote", because the monitor returned those jobs before.)
An error row (free) has "status": "error", the input it belongs to, errorKind (not_found, invalid_input, no_board_found, careers_page_unreadable, source_error or internal_error) and error (what went wrong and what to do); the job fields are null.
Output fields
| Field | Description |
|---|---|
company, companySlug, ats | Company name as published by Greenhouse and SmartRecruiters. Lever, Ashby and Workday don't publish a company name, so for them it is the board name (the slug, e.g. openai, or the Workday tenant, e.g. nvidia). Then the board identifier and the ATS |
jobId, uid | Job ID on the ATS, and a globally unique ats:companySlug:jobId key |
title, department, team | As published by the company |
locations | List of location strings |
remote | true: remote (see "Remote jobs" below). false: the ATS says hybrid or on-site. null: the ATS doesn't say |
workplaceType | remote / hybrid / onsite as published by the ATS, otherwise null |
employmentType | Full-time, Part-time, Contract, Internship, ... |
postedAt, updatedAt | ISO 8601 (UTC). Workday gives a date only. Lever and Ashby have no update date |
url, applyUrl | Job page and application page |
compensation | {min, max, currency, interval, summary} or null |
descriptionText | Clean plain-text description (when Include job description is on) |
status | open (tracking off), new / existing / closed (tracking on), or error (free error row) |
firstSeenAt, scrapedAt | When this tracker first returned the job, and when this run read it |
input | The company entry from your input that produced the row |
error, errorKind | Error rows only (null on job rows): why the entry returned no jobs |
The dataset has ready-made views: Jobs, New & closed, Compensation, Errors and All fields. Apify views can't hide rows, so error rows also appear in the job views as nearly empty rows with status error. To keep only jobs, skip rows whose status is error (in a spreadsheet, filter the Status column; in code, [r for r in items if r["status"] != "error"]). Failed entries are also listed in the SUMMARY record.
Remote jobs
The remote field and the Remote jobs only filter follow the same rules for every ATS:
- A workplace type published by the ATS wins. Hybrid and on-site jobs are
remote: false, even when the ATS also flags them as remote-eligible (Ashby setsisRemote: trueon hybrid postings) or one of their locations says "Remote". - Without a workplace type, an explicit remote flag from the ATS decides (Ashby
isRemote). - Otherwise a location that clearly says remote ("Remote", "US-Remote", "Remote - Canada", "Remote-Friendly, United States") gives
remote: true(withworkplaceType: null, because a location such as "US-SF, US-NYC, US-Remote" means remote is possible, not that the job is fully remote). - Otherwise the remote status is unknown:
remote: null. We don't guess from the description text.
What each ATS publishes: Lever, SmartRecruiters and most Ashby boards give a workplace type for every job. Greenhouse gives one only when the company adds it as a custom field (many don't), and Workday only on sites that publish a "remote type". On those boards, jobs without a "Remote" location are null. Remote jobs only keeps remote: true jobs; tick Remote only: also keep jobs with unknown remote status to also get the null ones and check them yourself. The location filter value "Remote" works like Remote jobs only, including that option.
How change tracking works
With Track new and closed jobs on, the Actor saves the jobs it has returned for each company in a named key-value store in your Apify account (career-site-jobs-tracking, one record per company and Tracking ID). On the next run:
- new: on the board now and not returned before by this tracker
- existing: returned in an earlier run and still on the board
- closed: returned in an earlier run and no longer on the board (it is output once, then forgotten)
Good to know:
- The first run marks every job as
new. - Return only new and closed jobs skips
existingjobs, so a daily monitor costs you only for the changes. Ticking it turns change tracking on by itself. - Jobs that don't match your filters are not stored, so if you widen the filters later, newly matching jobs show up as
new. - Closed jobs are reported only when the whole board could be read in that run (for example not when a very large Workday site could not be read completely). If a run stops early because of your spending limit, unreported changes are kept and reported next time.
- Use different Tracking IDs for independent monitors (for example one per team or per filter set).
Pricing
Pay per event, no subscription and no extra usage fees:
| Event | Price |
|---|---|
job: one job row in the dataset (open, new, existing or closed) | $0.0015 ($1.50 per 1,000) |
| Actor start (standard Apify event, per run; one event per GB of memory, so 1 at the default 512 MB) | $0.0005 |
Examples: all 731 open jobs at Stripe cost about $1.10. A daily "only new and closed" monitor of 20 companies that sees 50 changes a day costs about $0.08 per day.
- Apify platform costs (compute, storage, data transfer) are included in the price.
- Free: error rows, the run summary (
SUMMARYrecord), duplicate board entries (read once), and jobs whose detail page could not be loaded (skipped, not charged). - Set Maximum cost per run in the run options (or
maxTotalChargeUsdvia API) to cap spending. The Actor stops cleanly when the cap is reached: it stops listing boards and loading job details as soon as it can't charge for more rows, and everything returned up to that point is in the dataset. - If Apify moves a run to another server mid-run, it continues where it stopped and never returns or charges a job twice.
Changes in version 1.1 (20 Oct 2026)
What existing users may notice:
- Error rows in the dataset. An entry that returns no jobs because of a problem now gives one free row with
status: "error",input,erroranderrorKind; all job fields arenull. To keep only jobs, skip rows whosestatusiserror. Every row now has the keysinput,erroranderrorKind(so CSV/Excel exports have three more columns;erroranderrorKindarenullon job rows). - Remote status.
remoteisnull(unknown) instead offalsewhen the job board doesn't say, and hybrid or on-site jobs are alwaysfalse(Ashby hybrids used to betrue). Remote jobs only and the location value "Remote" now return only remote jobs; tick Remote only: also keep jobs with unknown remote status to include the unknown ones. workplaceTypeis only what the job board publishes: Greenhouse jobs that are remote only according to their location text now haveworkplaceType: null(wasremote).- Board ids. Greenhouse and Ashby slugs are lower-case in
companySluganduid(greenhouse:Figmagivesgreenhouse:figma:…), and SmartRecruiters uses its own spelling of the company id (ServiceNow). The same board entered twice is read and charged once. Change tracking keeps working: records saved by version 1.0 under the old spelling are taken over on the first 1.1 run, so jobs stayexisting. - Tracking. Return only new and closed jobs now turns change tracking on by itself (it creates the
career-site-jobs-trackingstore). - Run status. A run where every entry fails because of the input (for example a wrong slug) now ends as succeeded, with the error rows explaining why.
Use it from the API, an app or an AI agent
Run synchronously and get the items in one call (keep your own API token in the APIFY_TOKEN environment variable):
curl -X POST "https://api.apify.com/v2/acts/fairfetch~career-site-jobs-api/run-sync-get-dataset-items?maxTotalChargeUsd=0.50" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"companies": ["greenhouse:stripe"], "keywords": ["data"], "includeDescription": false}'
The Actor runs with limited permissions and pay-per-event pricing without usage fees, so AI agents can call it through the Apify MCP server and pay per run. Each run also writes a machine-readable SUMMARY record with per-company counts and errors.
Performance and limits
- Greenhouse, Lever, Ashby and SmartRecruiters boards are read with one request per board or per 100 jobs. In our tests a 700 to 800-job board took 10 to 50 seconds, and 5,288 jobs from five companies took 2.5 minutes (without descriptions).
- Max jobs per company returns the newest jobs on every ATS. Greenhouse and Ashby send the whole board in one response, and Lever boards are always read in full because Lever doesn't list jobs by date. Workday and SmartRecruiters list newest first, so without filters or tracking only the first pages are read.
- Workday and SmartRecruiters need one extra request per job for the description, so large boards with descriptions take longer (roughly 1 to 2 jobs per second per company). Turn off Include job description for speed.
- Workday search returns at most 2,000 jobs per query. For bigger sites the Actor automatically splits the query by job category, so you still get the full board (tested: 2,735 NVIDIA jobs). If a split can't cover the whole site, the run says so in
SUMMARYand skips closed-job detection for it, so no job is wrongly reported as closed. - Requests are polite: at most 3 at a time per host, automatic retries with exponential backoff for errors and rate limits, and timeouts.
- Fields depend on what each company publishes. For example, many Greenhouse boards don't publish employment type, and Workday sites don't publish departments (the department filter is skipped for Workday).
FAQ
Do I need an account with Greenhouse, Lever or the other ATSs? No. The Actor uses the public job-board feeds that the career sites themselves use.
Do I need proxies? No. The job-board APIs are public and the Actor keeps request rates low. A proxy option exists for edge cases.
How do I find a company's ATS slug?
Open the company's careers page and click a job. The URL usually shows it: job-boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>, <tenant>.wd5.myworkdayjobs.com/<site> or jobs.smartrecruiters.com/<slug>. You can paste that URL directly.
Why is a company missing jobs I can see on its website? Some companies show jobs from several boards or use an ATS that isn't supported yet. Check which board the job links point to and add that board.
Can I get only jobs posted recently? Yes, set Posted within the last N days. For an alerting workflow, change tracking with Return only new and closed jobs is more reliable because it does not depend on posting dates.
What happens if one company fails?
The other companies still run. The failed entry gets a free error row in the dataset, and the reason is also in the SUMMARY record and the run status message. A wrong slug returns "Job board not found (HTTP 404)". SmartRecruiters answers "0 jobs" for company IDs that don't exist, so an ID without jobs also gets an error row asking you to check it. If every entry fails because of the input, the run still ends as succeeded, with the error rows explaining why.
Why is remote null for some jobs?
The ATS doesn't say whether those jobs are remote (common on Greenhouse boards without a workplace field and on Workday sites without a "remote type"). See "Remote jobs" above.
Is there a limit on companies per run? No hard limit. Companies are processed a few at a time; very large lists simply take longer.
Legal
Not affiliated with or endorsed by Greenhouse, Lever, Ashby, Workday, SmartRecruiters or any employer whose jobs it reads; these names are used only to describe compatibility.
This Actor only reads job postings that companies publish openly on their public career sites, through the same public endpoints those sites use. It does not log in, bypass access controls or collect personal data about candidates. Job postings may include the name of a hiring contact in rare cases; handle any personal data you receive in line with the laws that apply to you (such as GDPR). You are responsible for how you use the data and for complying with the terms of the websites you read.