Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed avatar

Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed

Pricing

from $1.50 / 1,000 job posting rows

Go to Apify Store
Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed

Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed

Greenhouse jobs plus Lever, Ashby, Workable and Personio postings from public job boards in one flat schema with salary, location and remote fields. Change mode returns only new, changed or closed postings since your last run. No recruiter fields; emails and phone numbers removed from descriptions.

Pricing

from $1.50 / 1,000 job posting rows

Rating

0.0

(0)

Developer

Jack Valmadre

Jack Valmadre

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

17 days ago

Last modified

Categories

Share

Greenhouse, Lever, Ashby & Workable Jobs Feed: New & Closed

Get the open jobs of any company that publishes its job board on Greenhouse, Lever, Ashby, Workable or Personio, in one flat table, and, on a schedule, only the postings that are new, changed or closed since your last run.

It reads the public job-board APIs and feeds these applicant-tracking systems provide for employers' careers pages (plain JSON, or Personio's XML feed; no login, no browser, usually one request per board; see Politeness), so runs are quick and cheap.

SystemWhat to enterSalary fields
Greenhousegreenhouse:stripe or https://boards.greenhouse.io/stripewhen the employer publishes a pay range
Leverlever:spotify or https://jobs.lever.co/spotify (EU: https://jobs.eu.lever.co/...)when the employer publishes a pay range
Ashbyashby:linear or https://jobs.ashbyhq.com/linearwhen the employer publishes a pay range
Workableworkable:skroutz or https://apply.workable.com/skroutznever (Workable's public job list has no salary field)
Personiopersonio:thermondo or https://thermondo.jobs.personio.dewhen the employer publishes a pay range

What you can use it for

  • Keep a job board, newsletter or niche jobs site up to date with new postings and remove closed ones.
  • Watch hiring at a list of companies (new teams, new locations, roles closing).
  • Salary and remote-work research across employers that publish pay ranges.
  • Spot stale or long-open postings (use maxDaysOpen to filter them out, or use days_open to sort/flag them yourself).
  • Flag postings that have been advertised before: reopened = true when the same title and location reappears after closing.

Input

FieldWhat it does
boardsOne board per line: greenhouse:stripe, lever:spotify, ashby:linear, workable:skroutz, personio:thermondo, or a board URL (https://boards.greenhouse.io/figma, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/linear, https://apply.workable.com/skroutz, https://thermondo.jobs.personio.de). EU-hosted Lever boards (https://jobs.eu.lever.co/...) work too; EU-hosted Greenhouse boards (boards.eu.greenhouse.io), single Workable job links (https://apply.workable.com/j/...) and Workable careers sites on a company's own domain are not supported and are reported as invalid. Up to 500 per run. Also accepted as startUrls, urls or companies.
modefull (default): every open posting on every run, marked new / changed / unchanged, plus closed ones. changes: only new, changed and closed postings since the previous run with the same boards; the first run returns every open posting as new. Use changes for scheduled runs.
maxRowsStop after this many rows (each row is one charged job-row event). The input form starts at 10 so a first try costs about US$0.015; clear it (or set 0) to get every posting. When calling the API, leave it out for no limit. Also accepted as maxItems.
includeDescriptionAdds the plain-text job description (off by default; about 5–7 times larger output in our tests). Email addresses and phone numbers are removed.
stateStoreNameNamed key-value store that remembers previous runs. Set your existing store name explicitly to keep its history under limited permissions; see below for the blank-field fallback.
resetStateForget the history for these boards and start over.
titleIncludes / titleExcludesKeep postings whose title contains any of these words or phrases / leave out those that contain any of them.
locationsKeep postings whose location, other locations or country contains any of these (e.g. Berlin, Germany, US).
remoteOnlyKeep only postings marked remote.
workplaceTypesKeep postings with one of these workplace types: remote, hybrid, onsite.
hasSalaryKeep only postings with a published pay range.
minSalary + salaryCurrencyKeep postings whose pay range reaches at least this much per year, in this currency (e.g. 100000 and USD).
salaryPeriodUnknownAsYearWith minSalary: treat pay ranges with no stated period (all Greenhouse ranges) as yearly.
postedWithinDaysKeep postings the employer published at most this many days ago.
maxDaysOpenLeave out open postings that have been open more than this many days (by published_at; postings without a date are left out). Closed postings are still reported.

Filters

All filters are optional; with none set you get every posting. Postings a filter leaves out are not written and not charged. Several values in one filter are alternatives (any may match); different filters must all match.

  • Text (titleIncludes, titleExcludes, locations) is case-insensitive and matches at the start of a word: engineer matches "Senior Engineering Manager", ML matches "MLOps" but not "HTML", US matches "USA" but not "Austin". Country is a code on Lever and Workable (US, GB), usually a name on Ashby, and absent on Greenhouse and Personio, where only the location text is searched.
  • Remote and workplace type use the fields each system provides. Lever and Ashby state the workplace type; Workable marks remote jobs only; Greenhouse and Personio have no such field, so there a posting counts as remote only when its location says "Remote".
  • Salary floor (minSalary) compares the top of the employer's own pay range with your floor, only in the currency you give (no exchange rates), after converting the stated period to a year (hour x 2,080, day x 260, week x 52, month x 12). Postings without a range, in another currency, or without a stated period are left out; nothing is guessed from description text. Greenhouse never states the period: set salaryPeriodUnknownAsYear to include Greenhouse ranges as yearly.
  • Posted within N days uses published_at; postings without a date are left out. Closed postings are still reported when they match your other filters, however long ago they were posted.
  • Maximum days open (maxDaysOpen) keeps only open postings where days_open is at most N. Postings without a published_at (so no days_open) are left out. Closed postings are still reported.
  • Filters and the change feed: the history covers the whole board, whatever the filters. Changing a filter never makes postings look new or closed. It also means that widening a filter in changes mode does not replay postings that were already open: run once in full mode (or with resetState) to get them.
  • The run summary (OUTPUT) lists the filters used and how many postings each one left out.

The board name is the part of the careers-page URL after the domain (for https://jobs.lever.co/spotify it is spotify; for https://apply.workable.com/skroutz it is skroutz); for Personio it is the part before .jobs.personio.de (thermondo for https://thermondo.jobs.personio.de).

How the change feed works

The actor keeps the postings it saw in a named key-value store in your own Apify account, one record per distinct board list (the record key is a hash of the sorted boards, so the order and URL form don't matter). Schedule the actor with the same boards and mode set to changes (for example daily) and each run returns only what changed. Changing mode or includeDescription keeps the history. Editing the board list starts a new history for the new list. The record is small (about 24 KB for 272 postings in our test) and named stores are kept until you delete them.

Keeping your existing history: set stateStoreName explicitly to the store your scheduled runs already use (usually ats-job-feed-state). Apify can then request read/write permission for that store. Keep the same store name and boards on subsequent runs.

If you leave stateStoreName blank, the actor first tries ats-job-feed-state. If Apify denies opening that store with HTTP 403, the actor uses ats-job-feed-state-limited instead. This is a separate history: existing records are not copied, and the first run for your boards in that store returns every open posting as new, including postings seen in the old store. Subsequent runs using this store retain their history. To keep using that history explicitly, set stateStoreName to ats-job-feed-state-limited. An access error for a store you named explicitly fails the run instead of switching stores.

  • A posting is changed when its title, team, location, workplace type, employment type, salary, links or description change. Greenhouse's updated_at alone does not count (Greenhouse updates it without visible edits).
  • A closed posting appears once, on the first run after it disappeared, then never again.
  • A board that fails to load (network error, 404) keeps its history and never produces closed rows; the run summary lists it.
  • A run stopped early by your maximum cost per run or by maxRows saves history only for the postings it wrote: the rest come back on the next run, and boards it didn't reach never produce closed rows.
  • Rows are written before the history is saved, so an interrupted run can repeat rows on the next run but never lose a change.

Output

One dataset row per posting, same fields for all five systems (missing values are null):

source, board, company, job_id, posting_key (source:board:job_id, stable across runs), title, department, team, location, all_locations, country, workplace_type (remote / hybrid / onsite), remote, employment_type, salary_min, salary_max, salary_currency, salary_interval, salary_text, url, apply_url, published_at, updated_at, description, change_type (new / changed / unchanged / closed), first_seen_at, days_open, reopened, closed_at, scraped_at.

days_open: integer days from published_at to the run time (open postings) or to the run time at close (closed postings). null when published_at is missing.

reopened: true on a new posting when the same board has a previous closed posting with the same title (case-insensitive, stripped) and location. false on the first run for a board (no history to compare against). Useful for flagging roles that keep being re-advertised.

Example row (real output for Figma's Greenhouse board, 2026-09-25, description shortened):

{
"source": "greenhouse", "board": "figma", "company": "Figma", "job_id": "5426468004",
"posting_key": "greenhouse:figma:5426468004", "title": "Account Executive, Enterprise",
"department": "Sales", "location": "San Francisco, CA • New York, NY • United States",
"salary_min": 165000.0, "salary_max": 190000.0, "salary_currency": "USD",
"url": "https://boards.greenhouse.io/figma/jobs/5426468004?gh_jid=5426468004",
"published_at": "2025-01-28T18:57:29-05:00", "change_type": "new",
"first_seen_at": "2026-09-25T09:41:36Z", "days_open": 604, "reopened": false, "closed_at": null
}

The run summary (key-value store record OUTPUT) lists each board's status (ok, not_found, error, invalid, duplicate), counts of new / changed / unchanged / closed postings, and a warning when a board is empty (companies that move to another applicant-tracking system often leave an empty board behind).

What the data covers (measured)

Field coverage depends on what each employer fills in. On 21 real boards on 2026-09-25 (4,651 postings), a salary was present on 33% of Greenhouse, 35% of Lever and 66% of Ashby postings, and a remote flag on 17%, 100% and 78%. On Greenhouse, salary_text is the employer's label for the pay range (e.g. "Annual Base Salary Range:") and salary_interval is usually empty.

Workable (3 real boards on 2026-09-27, 54 postings): the salary fields are always empty; country, remote and all_locations were filled on every posting, department on 51 and employment_type on 41; workplace_type is set only for remote jobs. Workable lists a job once per location; the actor returns it as one row with every location in all_locations, so the row count matches the job total on the company's Workable careers page (33, 19 and 2 jobs on these boards).

Personio (9 real boards in two samples on 2026-09-27 UTC, 578 postings): department and location were filled on all but 2 of 578 postings, employment_type on all but 1, and published_at on every posting. A salary was on 7% of postings in one sample (4 boards) and on 1 of 68 in the other (5 boards), and remote was set on 16% and 43%: it depends on the employer. remote is true when any of the posting's offices has "Remote" in its name (e.g. "Remote - Germany"), otherwise empty, never false; offices named "Hybrid …" are not flagged. country and workplace_type are always empty (the feed has no such fields), and team is Personio's recruiting category. company is the employer's legal entity as the feed writes it, when the feed gives one (e.g. "Thermondo GmbH", "deskbird AG"; some feeds add a number, as in "ottonova Holding AG - 9680"); otherwise it is the board name. Postings are in the language the employer wrote them in, often German. With descriptions on, the actor reads the feed in English and, if some postings have no English text, once more in German for those postings; with descriptions off it reads the English feed only.

Limitations

  • Only Greenhouse, Lever, Ashby, Workable and Personio job boards. Companies using other systems (Workday, iCIMS, SmartRecruiters, Recruitee and others) are not covered; a company that moved away shows as not_found or empty.
  • You supply the boards; the actor doesn't discover companies or search all jobs.
  • Only postings the employer publishes on the public board (Ashby unlisted postings are skipped).
  • A board whose address redirects to another site is reported as an error and keeps its history (no false closed rows). Personio boards are never followed through a redirect (Personio sends unknown company names to its own website): they are reported as not_found and keep their history.
  • Personio: only boards on <company>.jobs.personio.de (or .com) are read; careers pages on a company's own domain are not recognised. When descriptions are on, a change to a German-only description is not reported as changed.
  • Personal data: recruiter and hiring-manager fields, Greenhouse custom fields and internal ids are never copied, and email addresses and phone numbers are removed from descriptions. Names of people that appear inside the free text of a description are not removed; switch descriptions off if you don't need them.
  • Postings are the employers' own job ads. You are responsible for how you use and republish them.

Politeness

Usually one request per board per run (a second one for a Personio board when descriptions are on and some postings have no English text; up to 2 retries on errors), at least 1 second between requests to the same host (Lever's robots.txt asks for this), and a clear user agent. Only the public read-only endpoints are used; no applications are submitted.

Use with AI agents and other actors

Input is plain JSON, e.g. {"boards": ["greenhouse:stripe", "ashby:linear", "workable:skroutz"], "mode": "changes"}; startUrls in the usual [{"url": "..."}] form also works. Each row has a stable posting_key for de-duplication.

Pricing

Pay per event: US$0.0015 per dataset row (job-row), plus a start fee of US$0.00005 per GB of run memory, charged once per run (at most US$0.00005 at the default 256 MB). Every row counts: in full mode (the default) that is every open posting plus closed ones, in changes mode only new, changed and closed postings. There is no extra charge for Apify platform usage. Apify shows the price before you run, and you can set a maximum cost per run. When that budget (or maxRows) runs out, the run writes as many rows as it covers (part of a board if need be), then stops, succeeds, and says so in its status message; the OUTPUT record marks the cut board partial and the boards after it not_read. Nothing is lost in the change feed: postings whose row wasn't written keep their saved history, so the next run with these boards still reports them as new, changed or closed, and boards that weren't read never produce closed rows.

Support

Please use the Issues tab of this actor. We aim to respond within 14 days. This actor is built and supported with AI assistance; a human owner can be reached on request through the Issues tab.

Publisher: Madrasco. Not affiliated with Greenhouse, Lever, Ashby, Workable or Personio.