ATS Jobs Feed & Hiring Signals: Greenhouse, Lever, Ashby
Pricing
from $1.50 / 1,000 job delivereds
ATS Jobs Feed & Hiring Signals: Greenhouse, Lever, Ashby
Live job postings from company career pages on Greenhouse, Lever and Ashby via their official public APIs. One unified schema, salary when published, and an only-new-jobs mode for daily feeds.
Pricing
from $1.50 / 1,000 job delivereds
Rating
0.0
(0)
Developer
Sirak Alem
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 hours ago
Last modified
Categories
Share
ATS Jobs Feed: Greenhouse, Lever & Ashby jobs (only new jobs mode)
👋 Hi! Give this Actor a list of companies and it brings you their open jobs, fresh from their own career pages: same format for every company, salary when they publish it, and an "only new jobs" mode so tomorrow you only see what was posted since today. Or switch to company hiring signals and get one row per company: open roles by function (sales, SDRs, engineering...), new roles this week, remote share and an explained hiring score.
It works with any company whose careers page runs on Greenhouse, Lever or Ashby, which is a lot of tech companies and startups (GitLab, Ramp, Zoox and thousands more).
Why I built it
I'm an independent developer from Italy who builds small automation tools. When I looked at the existing job scrapers for these platforms, many runs failed or returned duplicates and stale data. So I kept this one simple and boring on purpose: it reads the official public APIs, it does one job, and it tells you clearly when something goes wrong. If it doesn't work for you, tell me (see the bottom of this page) and I'll fix it.
In short
- Data comes from the official public job board APIs of each ATS (the same APIs companies use to build their own career pages). No login, no proxies, no browser, no scraping of HTML.
- Live, not a stale database: every run reads the boards at that moment.
- No duplicates: every job has a stable
id(platform:company:jobId). - One wrong slug never breaks your run: it is reported in
RUN_SUMMARYand the other companies are processed normally. - You pay only for jobs delivered. Errors, empty boards and filtered-out jobs cost nothing.
What you can use it for
- Daily alerts of new openings at a list of target companies (recruiters, job seekers, sales teams selling to companies that are hiring).
- Hiring signals for sales and lead generation: which companies are hiring SDRs, AEs or a VP of Sales right now, which teams are growing, which roles just closed (see Hiring signals).
- Salary benchmarks from Ashby and Lever postings that publish pay ranges.
- Feeding a job board, a Slack channel, a Google Sheet or a CRM through Apify integrations.
Input
You only need the companies. The slug is the part of the career page URL after the domain:
| Platform | Career page URL | Slug |
|---|---|---|
| Greenhouse | https://boards.greenhouse.io/gitlab or https://job-boards.greenhouse.io/gitlab | gitlab |
| Lever | https://jobs.lever.co/palantir (EU: https://jobs.eu.lever.co/...) | palantir |
| Ashby | https://jobs.ashbyhq.com/linear | linear |
Not sure about the slug? Paste the career page URL into Career page URLs and the platform is detected for you.
Run it with an empty input and you get a small demo: 3 jobs each from GitLab, Palantir and Linear (9 jobs, about $0.01).
| Field | Type | Description |
|---|---|---|
greenhouse | list of strings | Greenhouse board slugs (URLs accepted) |
lever | list of strings | Lever site names (EU boards detected automatically) |
ashby | list of strings | Ashby job board names |
careerPageUrls | list of strings | Any mix of career page URLs, platform auto-detected |
outputMode | jobs / companySignals | One row per job (default) or one row per company with hiring signals |
onlyNew | boolean | Output only jobs not returned in previous runs (default false) |
stateId | string | Name of the feed, to keep several independent feeds (default default) |
includeUnchangedCompanies | boolean | Company signals + only new: also output companies with no change (default false) |
titleKeywords | list of strings | Keep jobs whose title contains any of these words (case-insensitive) |
locationKeywords | list of strings | Keep jobs whose location or country contains any of these words |
remoteOnly | boolean | Keep only remote jobs |
maxJobsPerCompany | integer | Cap per company, most recent first (0 = no cap). Jobs mode only |
descriptionFormat | text / html / none | Job description as plain text (default), original HTML, or omitted |
Example input
{"careerPageUrls": ["https://job-boards.greenhouse.io/gitlab","https://jobs.lever.co/zoox","https://jobs.ashbyhq.com/ramp"],"titleKeywords": ["engineer"],"maxJobsPerCompany": 2,"descriptionFormat": "text"}
Output
One item per job. All platforms share the same fields; a field is null when the ATS does not publish it.
Real output of the example above (run on 2026-10-23, description shortened):
{"id": "ashby:ramp:29a5da77-37f0-402a-92bc-072778e77ed8","platform": "ashby","companySlug": "ramp","jobId": "29a5da77-37f0-402a-92bc-072778e77ed8","title": "Software Engineer, Forward Deployed","companyName": "ramp","department": "Engineering","team": "Engineering","location": "New York, NY (HQ)","locations": ["New York, NY (HQ)", "San Francisco, CA"],"country": "USA","remote": false,"workplaceType": "hybrid","employmentType": "full-time","salaryMin": 168000,"salaryMax": 285000,"salaryCurrency": "USD","salaryInterval": "year","salaryText": "$168K - $285K","url": "https://jobs.ashbyhq.com/ramp/29a5da77-37f0-402a-92bc-072778e77ed8","applyUrl": "https://jobs.ashbyhq.com/ramp/29a5da77-37f0-402a-92bc-072778e77ed8/application","postedAt": "2026-10-22T19:20:16Z","updatedAt": null,"description": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams...","isNew": null,"scrapedAt": "2026-10-23T19:00:47Z"}
{"id": "lever:zoox:09924dfa-16b4-415a-828e-4ae7d903ecc2","platform": "lever","title": "Senior Radar Engineer","department": "Advanced Hardware Engineering","team": "Sensor Engineering","location": "Foster City, CA","country": "US","workplaceType": "onsite","employmentType": "full-time","salaryMin": 199999,"salaryMax": 271000,"salaryCurrency": "USD","salaryInterval": "year","salaryText": "USD 199,999 - 271,000 per year","url": "https://jobs.lever.co/zoox/09924dfa-16b4-415a-828e-4ae7d903ecc2","postedAt": "2026-10-22T20:15:21Z"}
{"id": "greenhouse:gitlab:8899972002","platform": "greenhouse","companyName": "GitLab","title": "Engineering Manager, Tenant Scale: Gitaly","department": "Tenant Scale Engineering","location": "Remote, United Kingdom","locations": ["Remote, United Kingdom", "United Kingdom"],"remote": true,"workplaceType": "remote","url": "https://job-boards.greenhouse.io/gitlab/jobs/8899972002","postedAt": "2026-10-23T16:05:57Z","updatedAt": "2026-10-23T16:05:57Z"}
Which fields each ATS fills
Measured on 3,615 real jobs from 12 companies (4 per platform) on 2026-10-23:
| Field | Ashby (1,144 jobs) | Lever (635) | Greenhouse (1,836) |
|---|---|---|---|
postedAt | 100% | 100% | 100% |
department | 100% | 51% | 100% |
employmentType | 100% | 99% | not published |
workplaceType | 74% | 100% | inferred from location ("remote") |
country | 100% | 100% | not published |
| salary min/max | 70% | 35% | not published as a field |
Run summary
Each run also stores RUN_SUMMARY in the key-value store: status per company (ok / error / skipped),
number of open jobs, jobs that matched your filters, jobs delivered, and in only-new mode the number of
new and closed jobs since the previous run. Wrong slugs get a clear message, for example:
Board "acme" not found on ashby (check the slug in the career page URL; the company may have changed ATS)
Only new jobs (feed mode)
- Turn on Only new jobs since the last run.
- The first run returns all open jobs: that is your baseline.
- Schedule the Actor (for example daily). Each next run returns only jobs that were not there before.
The list of already-seen jobs is kept in a named key-value store called ats-jobs-feed-state in your Apify
account (the Actor needs only the standard, limited permissions). Use a different Feed name (stateId) to run
independent feeds, for example one per client. If a run stops because you reached your maximum cost per run, the
jobs that were not delivered are not marked as seen: you get them on the next run.
Hiring signals: one row per company
Sometimes you don't want 700 job postings, you want to know what a company is doing: is it building a sales
team, hiring its first marketing lead, slowing down? Set Output to Company hiring signals
("outputMode": "companySignals") and you get one row per company instead of one row per job.
I added this because, for sales teams and recruiters, the job list is only the raw material: the real question is "who is hiring SDRs right now?" or "which of my accounts just opened a VP of Sales role?". Each row tells you:
- Open roles by function: sales, customerSuccess, marketing, engineering, data, product, design, people, finance, legal, operations, other.
- Role types worth a call: SDR/BDR, account executives, sales leadership, engineering leadership, any leadership (VP, Head of, Director, C-level), internships.
- Fresh roles: published in the last 7 and 30 days (from the publication date the ATS gives), and which functions they are in.
- Where: share of remote roles, hybrid roles, top locations, countries and departments.
- The 10 most recently published roles, with links.
- A hiring score from 0 to 100, with the math next to it (see below).
Your filters still apply: with titleKeywords: ["SDR", "BDR", "sales development"] the row counts only those roles,
so the score answers "how hard is this company hiring SDRs?".
The hiring score, explained
No black box. The score is the sum of 4 parts, and every row contains scoreBreakdown with the points and the reason:
| Part | Max | How it is computed |
|---|---|---|
| volume | 30 | open roles: 1-4 = 5, 5-19 = 10, 20-49 = 18, 50-149 = 24, 150+ = 30 |
| freshness | 30 | share of open roles published in the last 30 days; 50% or more = 30, linear below |
| velocity | 25 | roles published in the last 7 days: 1-2 = 5, 3-5 = 10, 6-14 = 15, 15-29 = 20, 30+ = 25 |
| leadership and go-to-market | 15 | 3 points per leadership role + 1 per sales role, up to 15 |
Level: 0-24 low, 25-49 moderate, 50-74 high, 75-100 very high. Big companies naturally score higher on
volume; sort by newLast7Days or by a single part of scoreBreakdown if you care about momentum only.
Functions come from simple keyword rules on the job title (then the department, then the team). They are right most of the time, not always: "Solutions Engineer" counts as sales (pre-sales), "Support Engineer" as customerSuccess, "Data Engineer" as engineering. If you see a role in the wrong bucket, open an issue with the title and I'll fix the rule.
What changed since the last run
Turn on Only new jobs since the last run together with company signals, schedule it daily or weekly, and each row also tells you:
newSinceLastRunandnewRolesSinceLastRun: roles that appeared (title, function, location, link);closedSinceLastRunandclosedRolesSinceLastRun: roles that disappeared (filled, paused or pulled);firstRun: trueon the first run, which is the baseline.
A company with no change since the last run is not output and costs nothing (you still see it in RUN_SUMMARY).
Want a row for every company on every run anyway? Turn on Company signals: also output companies with no change.
The memory for company signals is separate from the one for jobs, so you can run both modes with the same feed name.
If you change the filters, use a new Feed name, otherwise the next run will see the change as opened/closed roles.
Example
{"greenhouse": ["gitlab", "anthropic", "stripe"],"lever": ["palantir", "zoox"],"ashby": ["ramp", "linear", "notion"],"outputMode": "companySignals","onlyNew": true,"stateId": "weekly-accounts"}
Real output for Ramp from a run on 2026-10-24 (lists shortened):
{"recordType": "companySignal","id": "ashby:ramp","platform": "ashby","companySlug": "ramp","careersUrl": "https://jobs.ashbyhq.com/ramp","openJobsTotal": 167,"jobsAnalyzed": 167,"hiringScore": 77,"hiringLevel": "very high","scoreBreakdown": [{"part": "volume", "points": 30, "max": 30, "why": "167 open roles (1-4 = 5, 5-19 = 10, 20-49 = 18, 50-149 = 24, 150+ = 30)"},{"part": "freshness", "points": 17, "max": 30, "why": "28% of open roles published in the last 30 days (50%+ = full points)"},{"part": "velocity", "points": 15, "max": 25, "why": "11 roles published in the last 7 days (1-2 = 5, 3-5 = 10, 6-14 = 15, 15-29 = 20, 30+ = 25)"},{"part": "leadershipAndGtm", "points": 15, "max": 15, "why": "8 leadership roles x 3 + 55 sales roles x 1"}],"byFunction": {"sales": 55, "engineering": 36, "customerSuccess": 17, "finance": 13, "people": 10, "product": 10, "marketing": 9, "data": 7, "legal": 4, "design": 3, "operations": 3},"roleTypes": {"sdrBdr": 11, "accountExecutive": 10, "salesLeadership": 1, "engineeringLeadership": 0, "leadership": 8, "internship": 5},"newLast7Days": 11,"newLast30Days": 46,"newLast30DaysByFunction": {"sales": 13, "engineering": 6, "customerSuccess": 5, "finance": 4, "legal": 4, "product": 4, "marketing": 3, "people": 3, "data": 2, "design": 2},"remoteJobs": 13,"hybridJobs": 137,"remoteShare": 0.08,"topLocations": [{"name": "New York, NY (HQ)", "jobs": 130}, {"name": "London, UK", "jobs": 12}, {"name": "San Francisco, CA", "jobs": 10}],"topDepartments": [{"name": "Sales", "jobs": 69}, {"name": "Engineering", "jobs": 37}, {"name": "People & Talent", "jobs": 14}],"newestPostedAt": "2026-10-23T19:41:17Z","latestRoles": [{"title": "GTM Senior Business Systems Analyst, Marketing & Pre-Sales", "function": "sales", "location": "New York, NY (HQ)", "postedAt": "2026-10-23T17:17:16Z", "url": "https://jobs.ashbyhq.com/ramp/aa433e44-f095-484b-a46a-a330583d84b0"}],"newSinceLastRun": null,"closedSinceLastRun": null,"firstRun": true,"scrapedAt": "2026-10-24T12:48:25Z"}
Same run, all 9 companies in 17-70 seconds: GitLab 100, Stripe 89, Anthropic 87, Ramp 77, Zoox 75, Notion 71,
Palantir 60, Linear 57. Mistral's Lever board exists but had 0 jobs (the company may have moved to another ATS): it is reported in the row and in RUN_SUMMARY, not counted as an error.
Pricing
Pay per event:
- $1.50 per 1,000 jobs delivered to the dataset.
- Company hiring signals: $0.01 per company ($0.0015 result + $0.0085 company signal). Companies with no change in only-new mode are free.
- A tiny Actor start fee set by Apify (default $0.00005 per run).
Empty boards, wrong slugs and filtered-out jobs are free. In only-new mode you pay only for the new jobs, and for company signals only for the companies that changed. Use Max jobs per company or the maximum cost per run in Apify to cap your spend.
Speed and limits
- About 1 second per company page (Lever returns 100 jobs per page). 12 companies and 3,615 jobs took 20 seconds in our test.
- Requests are throttled to at most 1 per second per ATS host, with automatic retries and backoff on errors and rate limits.
- Up to 500 companies per run.
- Greenhouse boards hosted in the EU (
job-boards.eu.greenhouse.io) are not supported: Greenhouse has no public EU Job Board API host. - Only jobs that companies publish publicly are returned. Internal postings and unlisted Ashby jobs are excluded.
Is it legal to use this data?
The Actor reads only the public, documented job board endpoints:
- Greenhouse Job Board API: "Job Board data is publicly available, so authentication is not required for any GET endpoints."
- Lever Postings API: "all job postings in the published state are publicly viewable. These jobs may be scraped by third parties."
- Ashby Public Job Posting API, documented at developers.ashbyhq.com.
It does not collect personal data such as recruiter names or e-mails. You are responsible for how you use the data; respect the terms of the companies whose postings you republish.
FAQ
Where do I find the slug? Open the company's careers page, click a job, and look at the URL: boards.greenhouse.io/<slug>, jobs.lever.co/<slug>, jobs.ashbyhq.com/<slug>. Or just paste the URL into Career page URLs.
A company returns 0 jobs. The board exists but has nothing published. The company may have moved to another ATS: check its career page URL.
Why is a role in the wrong function? Functions come from keyword rules on the title. Open an issue with the title and I'll adjust the rule.
Workday, SmartRecruiters, Workable? Not yet. Open an issue with the companies you need.
Found a problem or need a feature? Open an issue on the Issues tab with your input (no personal data). I read every issue myself and usually reply within 48 hours. Requests for new platforms are very welcome: they decide what I build next.
Thanks for trying it! If it saves you time, a short review on the Store helps a lot. 🙏