Greenhouse Jobs Scraper: Lever & Ashby Job Feed
Pricing
from $1.00 / 1,000 results
Greenhouse Jobs Scraper: Lever & Ashby Job Feed
Greenhouse jobs scraper for Lever and Ashby too: get jobs by company name, domain or careers URL with title, location, remote flag, salary and apply link as JSON, CSV or Excel. Watch mode returns new, changed and closed jobs. From $1/1,000 results.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Alexandre Manguis
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 days ago
Last modified
Categories
Share
Greenhouse Jobs Scraper: Lever & Ashby Job Feed with New/Closed Alerts
What does ATS Jobs Watch Feed do?
This Greenhouse jobs scraper also reads Lever and Ashby career boards. Give it company names, domains, career-page URLs or board tokens. It finds each company's job board and returns every open posting in one normalized format: title, department, locations, remote flag, salary (when published), description and direct apply URL.
In watch mode it remembers the previous run and returns only the new, changed and closed postings, so a daily schedule stays small and cheap.
It reads the public job-board APIs that Greenhouse, Lever and Ashby publish for third parties. No login, no browser and no proxy is involved.
Use cases
- Sales and RevOps teams: use hiring as a buying signal. Which target accounts are hiring a "data engineer" right now?
- Recruiting agencies: track competitors' and clients' open roles.
- Job-board and newsletter builders: aggregate postings with apply links and normalized salary and remote fields.
- Competitive intelligence: spot roles that were closed (filled or frozen).
- Automations and AI agents: structured job data per company, ready for Slack, Google Sheets, Make, Zapier or a CRM.
Features
- Three ATSs in one schema: Greenhouse, Lever, Ashby.
- Input by company name, domain, careers URL, board URL or board token. The ATS and token are detected automatically (best effort, see Limitations).
- Watch mode: NEW / CHANGED / CLOSED rows since the last run, one snapshot per watch list name. Only the rows returned are billed.
- Filters: title keywords, location keywords, remote only, cap per company, overall result limit.
- Normalized salary (min, max, currency, period) when the ATS publishes it, remote flag, workplace type, country and seniority inferred from the title.
- Optional plain-text and HTML descriptions (turn off for lighter rows).
- Export to JSON, CSV, Excel, XML or HTML from the Apify dataset, or call it through the API.
Input and configuration
Input fields
| Field | Type | Default | Description |
|---|---|---|---|
companies (required) | array of strings | – | Board URLs (jobs.lever.co/palantir), board tokens (stripe), domains (stripe.com), careers page URLs or company names. |
ats | auto / greenhouse / lever / ashby | auto | Force one ATS for bare tokens and names. |
mode | all / watch | all | all returns every open posting. watch returns only NEW, CHANGED and CLOSED postings since the previous run with the same watch list name. The first watch run returns everything as NEW. |
watchStateName | string | default | Name of the watch list (a-z, 0-9, -). Each name keeps its own snapshot, so several schedules run independently. |
titleKeywords | array of strings | [] | Keep jobs whose title contains any of these words (case-insensitive). |
locationKeywords | array of strings | [] | Keep jobs whose location text contains any of these words. |
remoteOnly | boolean | false | Keep only jobs flagged as remote. |
includeDescription | boolean | true | Include descriptionText and descriptionHtml. |
maxJobsPerCompany | integer | 0 | Cap per company (0 = no cap). |
maxResults | integer | 100 | Maximum rows for the whole run (also caps your spending). |
Example input
{"companies": ["stripe", "jobs.lever.co/palantir", "jobs.ashbyhq.com/linear"],"mode": "all","titleKeywords": ["engineer"],"maxResults": 100}
Output
Example output
One dataset row per job. Short example (description shortened, values illustrative):
{"jobId": "greenhouse:stripe:8172508","ats": "greenhouse","boardToken": "stripe","companyInput": "stripe.com","companyName": "Stripe","title": "Abuse Investigator","department": "8611 Security Analytics","locations": ["Dublin"],"country": null,"isRemote": false,"workplaceType": null,"employmentType": null,"seniority": null,"salaryMin": null,"salaryMax": null,"salaryCurrency": null,"salaryPeriod": null,"salaryText": null,"descriptionText": "About the team and the role …","descriptionHtml": "<h2>About the team</h2> …","jobUrl": "https://stripe.com/jobs/search?gh_jid=8172508","applyUrl": "https://stripe.com/jobs/search?gh_jid=8172508#app","publishedAt": "2026-09-03T17:32:53.000Z","updatedAt": "2026-09-25T20:45:00.000Z","changeType": null,"changedFields": null,"firstSeenAt": null,"closedAt": null,"scrapedAt": "2026-10-04T10:21:10.285Z"}
Watch mode rows
In watch mode changeType is NEW, CHANGED or CLOSED, firstSeenAt is set, and CHANGED rows list the changed fields in changedFields.
Output fields and fill rates
Fill rates measured on a 60-row test run across several boards (all three ATSs, mode: all). They depend on what each company publishes, so your own results will vary.
| Field | Fill rate | Notes |
|---|---|---|
jobId, ats, boardToken, companyInput, title, jobUrl, applyUrl, scrapedAt | 100% | Always present. |
department, locations, isRemote, publishedAt | 100% | |
descriptionText, descriptionHtml | 100% | null when includeDescription is off. |
workplaceType | 62% | When the ATS publishes it. |
country | 68% | Only when it can be inferred reliably. |
employmentType | 60% | |
companyName | 40% | Only when the board publishes it. |
updatedAt | 40% | Not exposed by every ATS. |
salaryMin, salaryMax, salaryCurrency, salaryPeriod, salaryText | 47% | Only when the posting publishes pay. In a Greenhouse-only discovery run (15 rows) none did. No guessing. |
seniority | 15% | Inferred from the title; null when unclear. |
changeType, firstSeenAt | watch mode only | 100% in a watch test run, null in all mode. |
changedFields, closedAt | watch mode only | Only on CHANGED / CLOSED rows. |
How to use via the API
Replace YOUR_APIFY_TOKEN with your own token.
curl
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~ats-jobs-watch-feed/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"companies": ["stripe", "jobs.lever.co/palantir"], "maxResults": 50}'
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('YOUR_USERNAME/ats-jobs-watch-feed').call({companies: ['stripe', 'jobs.lever.co/palantir'],mode: 'watch',watchStateName: 'sales-targets',});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.length, 'new, changed or closed jobs');
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("YOUR_USERNAME/ats-jobs-watch-feed").call(run_input={"companies": ["stripe", "jobs.lever.co/palantir"],"mode": "watch","watchStateName": "sales-targets","remoteOnly": False,})items = client.dataset(run["defaultDatasetId"]).list_items().itemsprint(len(items), "new, changed or closed jobs")
Scheduling a "new jobs" feed in watch mode
- Create a Task with
mode: watchand a fixedwatchStateName. - Add an Apify Schedule (for example daily).
- Add a webhook or an integration (Slack, Google Sheets, Make, Zapier) on run success. Each run's dataset holds only what changed since the last run.
Use a different watchStateName for each list of companies you want to track separately.
Pricing
Pay per result: you are billed one job event per dataset row returned. Unresolved companies and runs that return nothing cost no result events. Apify platform usage (a few hundredths of a cent per test run) is shown separately in your run.
| Apify plan | Price per 1,000 results |
|---|---|
| Free | $1.50 |
| Bronze | $1.30 |
| Silver | $1.15 |
| Gold, Platinum, Diamond | $1.00 |
In watch mode only NEW, CHANGED and CLOSED rows are returned and billed, so unchanged jobs cost nothing. Use maxResults to cap spending.
Limitations and troubleshooting
- Only Greenhouse, Lever and Ashby are supported. Other systems (Workday, SmartRecruiters, …) are not.
- A company is not found. Name and domain discovery is best effort: it needs a recognisable board token or a careers page that links to the ATS board. Try the board URL or token directly. Unresolved entries are listed with a reason in the
RUN_SUMMARYkey-value record, and the run still succeeds without billing them. In a test with an unknown board andexample.com, the run succeeded with 0 results. - Missing salary or
nullfields. Fields are filled only when the posting publishes them. The Actor does not guess. - "Field input.companies is required". Provide at least one company.
- Watch mode returned everything. The first run of a watch list returns all jobs as NEW. If the snapshot is missing or corrupted, the run is treated as a first run.
- Rate limits. Requests are paced and retried with backoff.
FAQ
Does it need a board token? No. You can pass a name, domain or careers URL, though a board URL or token is the most reliable.
Is the data public? Yes. It comes from the public job-board APIs these ATS vendors offer, with no login. Descriptions are kept as the employer published them. Check your own legal basis if you process recruiter contact details found in a description.
Can it apply to jobs or read candidate data? No. It only reads public postings.
Does watch mode work across different Tasks? Snapshots are stored per watchStateName, in your account. Reuse the same name to continue a list.
Keywords
greenhouse jobs scraper, lever jobs api, ashby jobs scraper, ats job feed, career page scraper, greenhouse job board api, lever jobs scraper, new job alerts, hiring signals, company job postings, job change monitor, career site jobs api
Hashtags
#greenhouse #lever #ashby #jobs #jobscraper #ats #careerpages #hiringsignals #recruiting #leadgeneration #jobalerts