Greenhouse, Lever & Ashby Jobs Tracker: New & Closed Roles
Pricing
from $0.70 / 1,000 job postings
Greenhouse, Lever & Ashby Jobs Tracker: New & Closed Roles
Track public job postings on Greenhouse, Lever, Ashby, and Workable boards. Get normalized jobs with published pay, and see which roles were opened, changed, or closed since your last run. Closed roles and diagnostics are free.
Pricing
from $0.70 / 1,000 job postings
Rating
0.0
(0)
Developer
SuicidalSquirrel
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Monitor company job boards for new, changed, and closed roles
Track public job postings on Greenhouse, Lever, Ashby, and Workable boards, and see exactly which roles were opened, changed, or closed since your last run.
The Actor reads each company's public job board API with direct HTTP requests (never a browser). It returns one clean, normalized item per open posting, flags changes against a previous run, and reports every posting that disappeared from a board. A board that is missing, empty, blocked, or unsupported gets an explicit, free diagnostic item instead of a silent empty result.
What you get
- One item per open posting: title, job and apply URLs, department, team, all locations, country, workplace type (onsite, remote, hybrid), employment type, published date, and a clean plain-text description.
- Published pay, when the board shows it: salary range, currency, and interval from Ashby and Lever boards that publish it. Never estimated.
- Change monitoring: compare with an earlier run and every posting is labeled
new,updated(with the exact changed fields), orunchanged. - Closed roles: each posting that disappeared from a board since your last run comes back as a
removeditem with its last known details. It's reported only when the board was read completely, so a failed or partial fetch can never look like closed roles. - Explicit diagnostics:
BOARD_NOT_FOUND,NO_OPEN_JOBS,UNSUPPORTED_INPUT,RATE_LIMITED, and more. Every input you give produces at least one item. - Privacy-aware text: email addresses and phone numbers in employer-written descriptions are redacted. Names that employers write into a description (for example a recruiter's name) are not removed.
- Run telemetry: requests, bytes, retries, durations, per-board completeness, and concurrency.
This is an independent community Actor. It is not affiliated with or endorsed by Greenhouse, Lever, Ashby, or Workable.
How to monitor job boards
- Paste one or more company board URLs, or short
ats:companynames, into Job board URLs or shorthand. - Run the Actor and open the Overview tab.
- Next time, select the first run's dataset in Previous dataset for comparison to see what changed.
{"boards": ["https://job-boards.greenhouse.io/stripe","https://jobs.lever.co/spotify","ashby:ramp","workable:workmotion"]}
Which boards are supported
| ATS | Paste a URL like | or shorthand |
|---|---|---|
| Greenhouse | https://job-boards.greenhouse.io/stripe, boards.greenhouse.io/... | greenhouse:stripe |
| Lever | https://jobs.lever.co/spotify | lever:spotify |
| Lever (EU accounts) | https://jobs.eu.lever.co/peppy | lever-eu:peppy |
| Ashby | https://jobs.ashbyhq.com/ramp | ashby:ramp |
| Workable (beta) | https://apply.workable.com/workmotion/, workmotion.workable.com | workable:workmotion |
A link to a single job posting also works; the Actor monitors that posting's whole board. Greenhouse embed links (...embed/job_board?for=stripe) are understood too. A lever: name that only exists on Lever's EU instance is found automatically.
Company careers pages on their own domains (for example stripe.com/jobs) are not supported yet. They return a free UNSUPPORTED_INPUT item. To find the board, open a job on the careers page: the URL usually shows the ATS host and company name.
Input reference
| Field | Purpose | Default |
|---|---|---|
boards | Board URLs, job posting URLs, or ats:company shorthand (up to 500) | Required |
maxJobsPerBoard | Most postings saved from one board (1 to 10,000) | 1000 |
maxJobs | Hard cap on postings saved in the whole run (1 to 100,000) | 5000 |
includeDescription | Include the plain-text description | true |
includeCompensation | Include pay ranges the board publishes | true |
previousDatasetId | Dataset of an earlier run to compare with | Not set |
outputMode | all: every posting is a result. changes: unchanged postings cost much less | all |
emitRemoved | Report postings that disappeared from completely read boards | true |
maxConcurrency | Boards fetched at the same time (1 to 20); lowers itself after rate limiting | 5 |
proxyConfiguration | Optional Apify Proxy or your own proxies | Direct connection |
A board that hits maxJobsPerBoard or maxJobs is marked incomplete and never reports removed postings, because the Actor cannot know what it didn't read.
Job posting output
Trimmed examples from a real run on 15 October 2026 (descriptions shortened). The Full data view shows every field.
An open posting with published pay, compared with the previous run:
{"status": "ok","ats": "ashby","boardSlug": "ramp","jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245","title": "Security Engineer, Cloud","jobUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245","department": "Engineering","team": "Backend","locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],"workplaceType": "hybrid","employmentType": "full-time","compensation": {"summary": "$211.4K – $290.6K • Offers Equity","currency": "USD","min": 211400,"max": 290600,"interval": "year"},"description": "About Ramp\nRamp is building the smart infrastructure for finance teams…","publishedAt": "2026-04-07T17:12:35.753Z","change": { "type": "unchanged", "changedFields": [], "previousFetchedAt": "2026-10-15T08:22:25.193Z" },"source": { "input": "ashby:ramp" },"fetchedAt": "2026-10-15T08:53:21.926Z"}
A role that was closed since the previous run:
{"status": "ok","ats": "greenhouse","boardSlug": "stripe","companyName": "Stripe","jobId": "8048266","title": "Sales Development Representative","jobUrl": "https://stripe.com/jobs/search?gh_jid=8048266","locations": ["Dublin"],"change": { "type": "removed", "changedFields": [], "previousFetchedAt": "2026-10-15T08:22:16.890Z" },"source": { "input": "https://job-boards.greenhouse.io/stripe" },"fetchedAt": "2026-10-15T08:53:17.759Z"}
A diagnostic for a board that doesn't exist:
{"status": "unavailable","errorCode": "BOARD_NOT_FOUND","errorMessage": "No public job board was found for this name (404). Check the spelling, or whether the company uses another ATS.","ats": "greenhouse","boardSlug": "thisdoesnotexist12345","source": { "input": "greenhouse:thisdoesnotexist12345" }}
Dataset views: Overview (status, company, title, locations, workplace, department, change, URL), Changes (change type and changed fields), and Full data (every field).
Which fields each ATS publishes
The Actor never guesses a value. When a board's public API doesn't publish a field, it is null:
| Field | Greenhouse | Lever | Ashby | Workable (beta) |
|---|---|---|---|---|
| Company name | Yes | No | No | Yes |
| Department / team | Department | Both, when set | Both | Top-level department only |
| Workplace type | Only when the location says Remote/Hybrid | Yes | Yes | Remote only (onsite and hybrid are null) |
| Employment type | Only from a custom field | Yes | Yes | Yes, when set |
| Country | No | Yes | Yes | Yes |
| Pay range | No | When published | When published | No |
| Published date | First published | Created date | Published | Published (day) |
Detect opened, changed, and closed roles
- Run the Actor once. This is your baseline.
- On the next run, choose that run's dataset in Previous dataset for comparison.
- Read
change.typeon each item:new,updated,unchanged, orremoved.
changedFields lists what changed, from this fixed list: title, jobUrl, applyUrl, department, team, locations, country, workplaceType, employmentType, compensation, and descriptionHash (the description text). Reordered locations are not a change.
outputMode: "changes" is made for daily monitoring. New and updated postings are charged at the normal price, while unchanged postings are charged at a tenth of it. Unchanged postings are still saved, so every run's dataset is a complete baseline for the next one.
Run it every day
An Apify schedule repeats the same input, so it cannot pass the newest dataset ID by itself. Chain runs with a small script (or the equivalent steps in Make, Zapier, or n8n): read the last successful run's dataset ID, then start a new run with it.
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const actor = client.actor('SynZROvsBdv9kmaub');const last = await actor.lastRun({ status: 'SUCCEEDED' }).get();const run = await actor.call({boards: ['https://job-boards.greenhouse.io/stripe', 'lever:spotify', 'ashby:ramp'],outputMode: 'changes',...(last ? { previousDatasetId: last.defaultDatasetId } : {}),});const { items } = await client.dataset(run.defaultDatasetId).listItems();const changes = items.filter((item) => item.change && item.change.type !== 'unchanged');console.log(changes);
The Actor does not keep its own memory between runs, and it does not send alerts. Route the changes list to email, Slack, or a spreadsheet with your own workflow.
Use cases
- Sales prospecting on hiring signals: see which target accounts just opened roles in your buyer's team.
- Recruiting market maps: track which competitors are hiring, where, and for which teams.
- Investor and market research: follow hiring momentum and freezes across a portfolio or a sector.
- Job alerts: get only new roles at the companies you care about.
- Data pipelines: load normalized postings into a warehouse, spreadsheet, or BI tool.
- AI agents: give an agent a predictable, typed tool for "what changed at these companies' job boards?"
Integrations and API
The examples use the Actor's ID. Keep your API token in an environment variable or secret manager, never in code or URLs.
REST API
For a small run that returns items directly:
curl --request POST \--url 'https://api.apify.com/v2/acts/SynZROvsBdv9kmaub/run-sync-get-dataset-items?clean=true' \--header "Authorization: Bearer $APIFY_TOKEN" \--header 'Content-Type: application/json' \--data '{ "boards": ["ashby:linear"] }'
For many boards, start the run asynchronously and read its defaultDatasetId when it finishes.
JavaScript or TypeScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('SynZROvsBdv9kmaub').call({ boards: ['lever:spotify', 'ashby:ramp'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('SynZROvsBdv9kmaub').call(run_input={'boards': ['lever:spotify', 'ashby:ramp']})items = client.dataset(run['defaultDatasetId']).list_items().itemsprint(items)
MCP and AI agents
Connect an MCP-compatible agent to https://mcp.apify.com, add this Actor as a tool, and ask the agent to run it with the JSON input above. The input and output schemas describe every field and diagnostic, so the agent gets structured results.
Make
- Add Run an Actor from the Apify app and select this Actor.
- Map the
boardslist (andpreviousDatasetIdfor monitoring) from your scenario. - Add Get Dataset Items with the run's default dataset ID.
For many boards, use Watch Actor Runs and then Get Dataset Items instead of waiting synchronously.
Zapier
Use Apify's Run Actor action for a few boards. Zapier's synchronous action has a 30-second limit, so for larger runs start the Actor asynchronously and continue with Finished Actor Run and Fetch Dataset Items.
Pricing
Pay per saved job posting. Platform usage is included in the price.
| Apify plan | Posting (job-snapshot) | Unchanged posting in changes mode (unchanged-snapshot) |
|---|---|---|
| Free | $1.00 per 1,000 | $0.10 per 1,000 |
| Bronze | $0.90 per 1,000 | $0.09 per 1,000 |
| Silver | $0.80 per 1,000 | $0.08 per 1,000 |
| Gold, Platinum, and Diamond | $0.70 per 1,000 | $0.07 per 1,000 |
Always free: removed postings (closed roles), diagnostic items, board discovery, pagination, and change classification.
Worked examples (Free plan, with Gold in brackets):
- One snapshot of a few boards with 1,000 open jobs in total: $1.00 ($0.70).
- Daily monitoring of about 7,000 jobs across 40 boards in
changesmode, with about 5 new or edited postings a day and the rest unchanged: about $0.70 a day ($0.49), or about $21 a month ($14.70). The same daily run inallmode would cost about $7.00 a day.
Set maxJobs, or a maximum total charge when you start a run, to cap what a run can cost. When a run reaches its charge limit, it stops starting new boards, finishes the ones in progress, and gives every remaining board a free EVENT_CHARGE_LIMIT_REACHED item.
Performance
Measured on the Apify platform on 15 October 2026 (512 MB memory, direct connection), on a benchmark of 51 inputs: 40 company boards across all four ATS, plus empty, misspelled, and unsupported inputs.
- Coverage: checked against open-job counts taken minutes earlier, all 40 boards matched exactly (6,952 postings). The counts came from each board's API: Greenhouse's reported total, Lever's full unpaginated list, Workable's careers-page API, and Ashby's listed jobs. Every one of the 51 inputs got its expected result.
- Speed: the full benchmark took 49 to 66 seconds with 5 boards in parallel (including the comparison with a previous run), and 29 seconds with 20 boards in parallel. A single 726-job board took a median of 3.0 seconds per run (2.5 to 6.1 seconds over 3 runs). Peak memory stayed under 400 MB.
- Change detection: in four comparison runs that day, every reported new or removed posting matched the live boards when checked right afterwards (new postings listed, removed postings gone). The first comparison found 1 new and 2 removed postings with 0 false updates across 6,952 unchanged postings; the last found 1 new, 2 removed, and 2 description edits.
- Field accuracy: in a hand-checked sample of 16 postings (4 per ATS), title, job URL, and locations matched the public job page in all 16, and every published department matched except one Workable job, where only the top-level department is available.
These results describe the benchmark boards on that date, not every company or ATS account.
Limits and responsible use
- Only public job boards on the listed ATS hosts are supported. Company careers domains, Workday, SmartRecruiters, and other ATS are not supported yet.
- Workable support is beta: it uses Workable's public jobs widget, which Workable does not document and could change.
- Postings an employer marked as unlisted (direct link only) on Ashby are not returned.
- Descriptions are employer-written text. Emails and phone numbers are redacted, including company recruiting addresses; names written into the text are kept.
- Lever asks for at most one request per second, and its API returns 100 postings per page, so large Lever boards take at least 1 second per 100 postings (612 postings took 26 seconds).
- No logins, application forms, candidate data, or ATS admin APIs are used, and access controls or geographic restrictions are not bypassed.
Use the Actor only where you have a lawful basis to do so. You are responsible for complying with applicable laws, the boards' terms, and reasonable request rates.
FAQ
How do I find a company's board?
Open any job on the company's careers page. If the URL or the application page contains greenhouse.io, lever.co, ashbyhq.com, or workable.com, paste that link. The Actor finds the board from it.
Why did I get a diagnostic instead of jobs?
Check errorCode and errorMessage in the Overview tab. BOARD_NOT_FOUND usually means a misspelled name or a company that uses another ATS. NO_OPEN_JOBS means the board exists but has no public openings right now. UNSUPPORTED_INPUT means the URL isn't a supported board.
Why is the company name empty?
Lever and Ashby don't publish it in their public API. Use boardSlug or boardUrl to identify the company.
Why wasn't a closed role reported as removed?
Removals are reported only for boards that were read completely in this run. If a board failed, hit maxJobsPerBoard or maxJobs, or changed while it was being read, the Actor skips its removals rather than guessing.
Can it run automatically every day?
Yes, with a small workflow that passes the previous run's dataset ID (see Run it every day). The Actor itself doesn't store state between runs or send notifications.
Can I use a proxy?
Yes, but you usually don't need one. Direct requests are the default, and a proxy is used only if you configure Apify Proxy or your own proxy URLs. No paid residential proxy is ever selected automatically.
Can I export the results?
Yes. Download the dataset as JSON, CSV, Excel, XML, or RSS, or read it with the API.
Changelog
October 2026
- First version: public Greenhouse, Lever (including EU accounts), Ashby, and Workable (beta) boards.
- Change monitoring against a previous run, with
removedpostings for completely read boards and a changes-only mode. - Explicit, free diagnostics for missing, empty, unsupported, blocked, and failed boards.
- Parallel board fetching that slows down automatically after rate limiting, and optional user-configured proxies.
- Employment types are matched as whole words, so Lever commitments such as "International EOR" are no longer read as internships.