Greenhouse, Lever & Ashby Jobs Tracker: New & Closed Roles avatar

Greenhouse, Lever & Ashby Jobs Tracker: New & Closed Roles

Pricing

from $0.70 / 1,000 job postings

Go to Apify Store
Greenhouse, Lever & Ashby Jobs Tracker: New & Closed Roles

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

SuicidalSquirrel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

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), or unchanged.
  • Closed roles: each posting that disappeared from a board since your last run comes back as a removed item 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

  1. Paste one or more company board URLs, or short ats:company names, into Job board URLs or shorthand.
  2. Run the Actor and open the Overview tab.
  3. 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

ATSPaste a URL likeor shorthand
Greenhousehttps://job-boards.greenhouse.io/stripe, boards.greenhouse.io/...greenhouse:stripe
Leverhttps://jobs.lever.co/spotifylever:spotify
Lever (EU accounts)https://jobs.eu.lever.co/peppylever-eu:peppy
Ashbyhttps://jobs.ashbyhq.com/rampashby:ramp
Workable (beta)https://apply.workable.com/workmotion/, workmotion.workable.comworkable: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

FieldPurposeDefault
boardsBoard URLs, job posting URLs, or ats:company shorthand (up to 500)Required
maxJobsPerBoardMost postings saved from one board (1 to 10,000)1000
maxJobsHard cap on postings saved in the whole run (1 to 100,000)5000
includeDescriptionInclude the plain-text descriptiontrue
includeCompensationInclude pay ranges the board publishestrue
previousDatasetIdDataset of an earlier run to compare withNot set
outputModeall: every posting is a result. changes: unchanged postings cost much lessall
emitRemovedReport postings that disappeared from completely read boardstrue
maxConcurrencyBoards fetched at the same time (1 to 20); lowers itself after rate limiting5
proxyConfigurationOptional Apify Proxy or your own proxiesDirect 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:

FieldGreenhouseLeverAshbyWorkable (beta)
Company nameYesNoNoYes
Department / teamDepartmentBoth, when setBothTop-level department only
Workplace typeOnly when the location says Remote/HybridYesYesRemote only (onsite and hybrid are null)
Employment typeOnly from a custom fieldYesYesYes, when set
CountryNoYesYesYes
Pay rangeNoWhen publishedWhen publishedNo
Published dateFirst publishedCreated datePublishedPublished (day)

Detect opened, changed, and closed roles

  1. Run the Actor once. This is your baseline.
  2. On the next run, choose that run's dataset in Previous dataset for comparison.
  3. Read change.type on each item: new, updated, unchanged, or removed.

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 os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('SynZROvsBdv9kmaub').call(run_input={'boards': ['lever:spotify', 'ashby:ramp']})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(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

  1. Add Run an Actor from the Apify app and select this Actor.
  2. Map the boards list (and previousDatasetId for monitoring) from your scenario.
  3. 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 planPosting (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 changes mode, 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 in all mode 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 removed postings 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.