ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workable
Pricing
Pay per event
ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workable
Live ATS jobs scraper for Greenhouse, Lever, Ashby and Workable. Paste company slugs or careers URLs, get every open role — title, location, remote, department, salary, apply URL, posting age — read live with no 5,000-job cap, plus ghost-job risk, seniority and a hiring-momentum summary.
Pricing
Pay per event
Rating
0.0
(0)
Developer
daehwan kim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
ATS Jobs Scraper — Greenhouse, Lever, Ashby & Workable
Paste a list of companies. Get back every open role on their job board, read live at the moment you run it, with a judged one-line verdict on each posting.
No database of yesterday's jobs. No 5,000-job ceiling. No API key.
in → ["https://boards.greenhouse.io/dropbox", "https://jobs.lever.co/binance"]out → one row per open role + one hiring-momentum summary per company
Why this one
Most ATS scrapers on the store hand you a cached copy of someone else's crawl, capped at a few thousand rows per run, and then point you at a paid API when you need more. This Actor calls the company's own job board at run time, so:
| This Actor | |
|---|---|
| Freshness | Read live, per run. A role posted an hour ago is in your first run. |
| Per-run job limit | None. A 824-posting board comes back whole. |
| Coverage | Greenhouse, Lever, Ashby and Workable, auto-detected from a slug or URL. |
| Judgement | Every row is scored, not just copied — see below. |
The judgement layer
Other scrapers give you fields. This one gives you a verdict:
headline— the row in one line:Senior Backend Engineer — Remote (United States), posted 3d ago, $180k–220kfreshness—fresh(≤30d),aging(≤90d),stale(older)postedAgeDays— how long this role has actually been openghostJobRisk—none/low/medium/high, with the reasons inghostJobFlags: open over 90 or 180 days, never updated, or a duplicate title sitting on the same boardseniority—intern/junior/senior/principal/manager/director/executive, read from the titlesalary—min,max,currencyparsed out of whatever the board publishedremoteandworkplaceType— normalised across four boards that each say it differentlykeywordHits— which of your keywords this role matched
And once per company, a company-summary row: department and seniority mix, remote share, average posting age, top locations, and a hiring-momentum verdict — hiring hard, steady, slowing or stalled, based on how many roles opened in the last 30 days.
Input
| Field | Type | Description |
|---|---|---|
companies | array | Company slugs or careers-page URLs. Greenhouse, Lever, Ashby and Workable are detected automatically. |
company | string | Alternative to the list — a single company. |
keywords | array | Keep only roles whose title contains one of these words. Empty = every role. |
locations | array | Keep only roles whose location mentions one of these (Remote works). Empty = everywhere. |
postedWithinDays | integer | Keep only roles first published within N days. 0 = no date filter. |
maxJobsPerCompany | integer | Ceiling per company. 0 = unlimited, which is the default. |
includeDescription | boolean | Add the full job description as plain text. Off by default — descriptions are large. |
monitorMode | boolean | Return only what changed since your previous run (default false). See Monitor mode below. |
monitorKey | string | Optional name for the watch, e.g. competitor-hiring-weekly. Empty = derived from your input. |
includeUnchanged | boolean | Monitor mode only — also return roles that are still open and unchanged (default false). |
disclaimerAck | boolean | Acknowledges how this Actor sources data (see Data sources & responsibility). |
Accepted address formats:
dropbox (bare slug — probed across all four boards)https://boards.greenhouse.io/dropboxhttps://job-boards.greenhouse.io/stripe/jobs/12345https://jobs.lever.co/binancehttps://jobs.ashbyhq.com/linearhttps://apply.workable.com/blueground
A URL is always faster and unambiguous. A bare slug costs up to four probe requests.
Example
{"companies": ["https://boards.greenhouse.io/databricks","https://jobs.ashbyhq.com/linear"],"keywords": ["engineer", "designer"],"locations": ["Remote", "United States"],"postedWithinDays": 30,"maxJobsPerCompany": 0,"includeDescription": false,"disclaimerAck": true}
Output
One row per open role (rowType: "job"):
| Field | Description |
|---|---|
headline | The one-line verdict |
company, companySlug, inputTarget | Who this role belongs to, and what you typed |
ats, atsLabel | greenhouse / lever / ashby / workable |
jobTitle | Role title |
location, locations | Primary location and every listed location |
remote, workplaceType | true/false/null, and remote / hybrid / onsite |
department, departments | Team and department names |
employmentType | Full-time, contract, intern, … where the board publishes it |
postedAt, updatedAt | ISO dates from the board |
postedAgeDays, updatedAgeDays | Age in days |
freshness | fresh / aging / stale / unknown |
ghostJobRisk, ghostJobFlags | Risk band and the reasons behind it |
seniority | Inferred from the title |
salary | { min, max, currency, raw } when the posting publishes pay |
keywordHits | Your keywords that matched |
applyUrl | Direct application link |
jobId, requisitionId | Board identifiers |
jobDescription | Plain text, when includeDescription is on |
sourceUrl, scrapedAt | Exactly which endpoint was read, and when |
changeType, changeDetail | Monitor mode only — new / changed / removed / unchanged, and what moved |
One row per company (rowType: "company-summary"): hiringMomentum, hiringMomentumReason, totalJobsOnBoard, jobsMatchingFilters, jobsDelivered, remoteJobs, remoteSharePercent, newLast30DaysPercent, averagePostingAgeDays, jobsWithPublishedSalary, departmentDistribution, seniorityDistribution, topLocations.
Rows with rowType: "notice" are status messages — an address with no board behind it, a company with no open roles, a limit reached. Notice rows are never charged.
Invalid input ends the run as SUCCEEDED with a notice row.
Monitor mode (weekly change alerts)
Hiring is a moving target. Turn on Monitor mode and the Actor compares this run with your previous run and returns only what moved on those boards:
changeType | Meaning |
|---|---|
new | A role that was not on the board the last time you ran this — the one recruiters and job-seekers actually want |
changed | The title or location moved; changeDetail shows what it said before |
removed | No longer listed: filled, withdrawn or expired |
unchanged | Still open, still identical — withheld by default, set includeUnchanged to receive it |
Every run also returns one free change-report row, e.g. 12 new job postings, 3 gone, 1 changed since 2026-08-19, with newCount, removedCount, changedCount and unchangedCount. A quiet week returns just that row and no job rows.
The company summary row still describes the whole board (hiring momentum, department mix, remote share) so the change rows always have context.
Put it on a weekly schedule (3 steps)
- Run the Actor once with Monitor mode on — the first run saves a baseline and returns every open role.
- On the run's page click Actions ▸ Schedule Actor, and pick
Every week. - Add an integration on the schedule (Slack, email, webhook) so new roles at the companies you watch reach you without opening Apify.
Runs are matched by monitor key. Leave monitorKey empty and it is derived from your input, so one schedule keeps one history automatically; set it (e.g. competitor-hiring-weekly) to keep several independent watches. State is kept in a named key-value store holding only job identifiers and a short title/location label — never descriptions.
A board that could not be read this run is left untouched: its roles are never reported as "removed" because of a network error.
Pricing
Pay per event:
| Event | Price | When |
|---|---|---|
run-started | $0.005 | Once per run, when your company list is accepted and the boards are read. |
job-listed | $0.003 | Once per job posting written to the dataset, with its full judged row. |
company-summary | $0.01 | Once per company, for the summary row. Only written when at least one job row was delivered for that company. |
A 40-role company therefore costs 0.005 + 40 × 0.003 + 0.01 = $0.135.
Notice rows — unreadable board, no open roles, no matching filters, limit reached, and the monitor change report — are not charged.
In Monitor mode the same job-listed price applies to each delivered change row, removed rows included: a role that has just been filled is exactly the answer you scheduled the run for. A week with no movement delivers no job rows and therefore costs only the run-start fee.
Free Apify plans receive up to 25 billable rows per run and finish normally with a notice explaining the cap. Paid plans have no per-run job limit.
Data sources & responsibility
This Actor reads the public, unauthenticated job-board endpoints that each applicant tracking system serves to a company's own careers page:
Greenhouse https://boards-api.greenhouse.io/v1/boards/<slug>/jobs?content=trueLever https://api.lever.co/v0/postings/<slug>?mode=jsonAshby https://api.ashbyhq.com/posting-api/job-board/<slug>?includeCompensation=trueWorkable https://apply.workable.com/api/v1/widget/accounts/<slug>?details=true
- Exactly one request per company, two companies at a time, with an honest bot User-Agent (
ntriq-ats-jobs/1.0). - No login, no captcha, no anti-bot measure is bypassed. Nothing behind an authentication wall is read.
- Only job-posting data is returned. No recruiter names, no applicant data, no personal contact details.
This Actor is unofficial and is not affiliated with, endorsed by, or sponsored by Greenhouse, Lever, Ashby, Workable, or any employer whose board you read. You are responsible for complying with the terms of service of each applicant tracking system and each employer, and for using the results lawfully. You are the data controller for everything you collect with it, including any obligations under GDPR or comparable law.
ghostJobRisk is a heuristic built from posting age, update dates and duplicate titles. It is a signal to investigate, not a statement about any employer's hiring intentions.
Notes
- Boards that publish no posting date are still returned; their
freshnessisunknownandpostedWithinDaysnever filters them out. - Ashby and Lever publish pay ranges more often than Greenhouse and Workable, so
salaryis populated unevenly. It is parsed from what the board actually published — nothing is estimated. - A company whose board exists but has no open roles returns a free
no-jobsnotice, not an error.
Works well with
- whois-domain-lookup — Qualify the hiring company by its domain: registrar, age and registrant details.
- lighthouse-website-audit — Score the company site for performance and SEO before you pitch or apply.
- theharvester-osint — Collect public emails and hosts for the same company domain.
Every run of this Actor also returns these suggestions in the nextSteps field of its summary row.