Greenhouse Jobs Scraper: Lever, Ashby, Workable avatar

Greenhouse Jobs Scraper: Lever, Ashby, Workable

Pricing

from $0.65 / 1,000 job postings

Go to Apify Store
Greenhouse Jobs Scraper: Lever, Ashby, Workable

Greenhouse Jobs Scraper: Lever, Ashby, Workable

Scrape job postings from Greenhouse, Lever, Ashby, Workable and Recruitee boards for a list of companies. One row per job: title, location, department, apply URL, full description and pay when published. Filter by title, location or remote; get only new jobs.

Pricing

from $0.65 / 1,000 job postings

Rating

0.0

(0)

Developer

Pradio Actors

Pradio Actors

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 hours ago

Last modified

Share

What does Greenhouse Jobs Scraper do?

Greenhouse Jobs Scraper reads the public job-board feeds of Greenhouse, Lever, Ashby, Workable and Recruitee for a list of companies in one run. Each posting is one row: title, company name, seniority, city, region and country, department, apply URL, the full description, and pay when the posting publishes it. You do not need to know a company's slug: give its name or its careers-page URL and the Actor finds the board. Or start from a preset list of AI or fintech companies. Filter by title, keywords, department, location, remote or posting age before anything is read; ask for only the postings you have not seen since your last run. No login, no browser, no applicant or Harvest APIs. The default company is ramp (Ramp's Ashby board).

Who uses Greenhouse Jobs Scraper

WhoWhat they run it for
Talent intelligence and aggregatorsPull every open role across a list of companies, whichever of the five vendors each one uses, into one table with one shape.
Recruiters and sourcersRefresh a target list's live postings, keep apply URLs and published pay, and see only what is new since last week.
Sales and hiring-signal workWatch which roles a company opens, in which department and where, and whether pay is posted.
Agents and pipelinesPass a list of company names and get rectangular rows instead of five vendor dialects.

Features

  • Finds the board from a company name or careers-page URL. Give Hugging Face or https://careers.bunq.com and the Actor tries the likely slugs on all five vendors until one answers.
  • Five vendors, one row shape. Greenhouse, Lever, Ashby, Workable and Recruitee postings come back with the same columns, in the same types.
  • Preset company lists. ai-startups (21 companies) and fintech (12 companies), each board checked on its vendor's public feed.
  • Filters before anything is read. Title, keywords, department, location, remote and posting age; a posting a filter removes costs nothing.
  • Only the new jobs. Turn on onlyNew and each run returns only the postings you have not had before, ready for a daily schedule.
  • Pay read where it is published. Structured pay fields from Ashby, Lever and Recruitee, and a range the posting text states next to a pay word on Greenhouse and Workable.
  • Seniority and location split out. Seniority read from the title, and the location split into city, region and a two-letter country code.

What you can count on

  • every row is charged only after it is written to your dataset; a row you cannot see is never billed
  • a run that finds nothing returns one NO_MATCHING_LISTINGS row that says so, never an empty dataset
  • a spending limit stops the run cleanly with a STOPPED_EARLY row saying how many rows were returned and how many were not
  • every run writes a RUN_SUMMARY entry with rowsFetched, rowsPushed, rowsCharged and duplicatesDropped, so a short run and a broken one are told apart
  • if a board changes its response, the run fails with the error in the log; it never returns rows full of nulls and calls it success

Why this one

The most-used alternative was run on 2026-09-25 on the same board as this Actor's sample, Ramp's Ashby board. Both filled the title, the pay range, the employment type and the remote status on every posting they returned, so on a board that publishes those fields the two agree. The differences are the price, the memory and the reach: it charges $0.0015 a posting and this Actor charges $0.0012; it runs at 1024 MB and this Actor at 256 MB; and this Actor also reads Recruitee boards, answers a misspelt company with a row that names it, and keeps a removal list that every run checks before it reads anything.

What data does Greenhouse Jobs Scraper return?

One real posting from the default Ramp board (description shortened):

{
"platform": "ashby",
"official_url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
"title": "Security Engineer, Cloud",
"posted_date": "2026-04-07T17:12:35.753+00:00",
"location": "New York, NY (HQ)",
"is_remote": false,
"workplace_type": "Hybrid",
"description": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams, embedded in the transaction flow of every dollar a business spends.",
"job_type": "FullTime",
"department": "Engineering",
"job_id": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
"salary_minimum": 211400,
"salary_maximum": 290600,
"salary_currency": "USD",
"compensation": {
"compensationTierSummary": "$211.4K – $290.6K • Offers Equity",
"scrapeableCompensationSalarySummary": "$211.4K - $290.6K",
"compensationTiers": [
{
"id": "5f7a903e-36e4-492c-ac09-f2745d717daa",
"tierSummary": "$211.4K – $290.6K • Offers Equity",
"title": null,
"additionalInformation": null,
"components": [
{
"id": "feaef96f-559f-4df8-a38c-3eee072a8d74",
"summary": "Offers Equity",
"compensationType": "EquityPercentage",
"interval": "NONE",
"currencyCode": null,
"minValue": null,
"maxValue": null
},
{
"id": "3481c194-45fd-4b89-8592-e8f4d4b51f20",
"summary": "$211.4K – $290.6K",
"compensationType": "Salary",
"interval": "1 YEAR",
"currencyCode": "USD",
"minValue": 211400,
"maxValue": 290600
}
]
}
],
"summaryComponents": [
{
"compensationType": "EquityPercentage",
"interval": "NONE",
"currencyCode": null,
"minValue": null,
"maxValue": null
},
{
"compensationType": "Salary",
"interval": "1 YEAR",
"currencyCode": "USD",
"minValue": 211400,
"maxValue": 290600
}
]
},
"company_slug": "ramp",
"address": {
"postalAddress": {
"addressRegion": "NY",
"addressCountry": "USA",
"addressLocality": "New York City"
}
},
"apply_url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
"company_name": "Ramp",
"seniority": null,
"salary_text": "$211.4K - $290.6K",
"pay_interval": "year",
"has_equity": true,
"city": "New York City",
"region": "NY",
"country": "US",
"row_type": "ROW"
}

The run that produced this example returned 100 postings on the default input (company = ["ramp"], maxItemsPerCompany = 100); the board listed 146.

Fields on every posting row

No column is always empty: every field in the table below is filled by at least one vendor, and the table says which.

FieldMeaningAshbyGreenhouseLeverWorkableRecruitee
platformWhich vendor answeredashbygreenhouseleverworkablerecruitee
official_urlPublic posting URL (link)jobUrlabsolute_urlhostedUrlurlcareers_url
titleJob titletitletitletexttitletitle
company_nameEmployer's display nameslug in title casecompany_nameslug in title caseboard namecompany_name
seniorityLevel the title statestitletitletitletitletitle
posted_datePublished timepublishedAtfirst_publishedcreatedAtpublished_onpublished_at
locationWorkplace text as publishedlocationlocation.namecategories.locationcity, state, countrylocation
cityCityaddressLocalityread from locationread from locationcitycity
regionState, province or regionaddressRegionread from locationread from locationstatestate_name
countryTwo-letter country codeaddressCountryread from locationcountrycountryCodecountry_code
is_remoteRemote postings only: hybrid and on-site read false; null when the vendor says nothingworkplaceType is Remote (isRemote when there is no workplace type)word Remote in location, else nullworkplaceTypetelecommutingremote
workplace_typeremote, hybrid or onsite, as the vendor writes it (Ashby capitalises: Hybrid)workplaceTypenullworkplaceTypeworkplaceremote / hybrid / on_site
descriptionFull posting text, plain or HTML as the vendor gives itdescriptionPlaincontentdescriptionPlaindescription + requirements + benefitsdescription + requirements
job_typeEmployment type in the vendor's wordsemploymentTypenullcategories.commitmentemployment_typeemployment_type_code
departmentDepartment or teamdepartmentdepartments[0].namecategories.departmentdepartmentdepartment
job_idThe vendor's own posting ididididshortcodeid
salary_minimumPublished pay floorcompensation minValuethe posting's pay ranges, else pay stated in the posting textsalaryRange.minpay stated in the posting textsalary.min
salary_maximumPublished pay ceilingcompensation maxValueas abovesalaryRange.maxas abovesalary.max
salary_currencyISO code of the published paycurrencyCodeas abovesalaryRange.currencyas abovesalary.currency
pay_intervalyear, month, week, day or hourintervalas abovesalaryRange.intervalas abovesalary.period
salary_textThe pay as published, as textpay summarythe range as writtenbuilt from salaryRangethe range as writtenbuilt from salary
has_equityThe pay package includes equityequity componentnullnullnullnull
compensationThe vendor's whole pay object, unchangedcompensationpay_input_rangessalaryRangenullsalary
company_slugThe slug that answeredslugslugslugaccountcompany
addressThe vendor's structured location, unchangedaddressnullnullcity, state, countrycity, region, country
apply_urlWhere a person applies (link)applyUrlposting URLapplyUrlapplication_urlcareers_apply_url
row_typeROW on a posting, ITEM_STATUS on an entry this Actor does not read or cannot find, NO_MATCHING_LISTINGS when no posting matched, STOPPED_EARLY when a spend cap ended the run
reasonStatus rows only: why there were no postings, why the run stopped early, or why an entry was not read (a vendor this Actor does not read, a board on the removal list, a board whose robots.txt disallows the feed, or no public board found, naming the vendors tried)
statusEntry-note rows only, and these two values are the only ones: vendor_not_read when the board is not read (a vendor this Actor does not read, a board on the removal list, or a Recruitee board whose robots.txt disallows the offers feed; reason says which), no_board_found when no vendor has a public board for the entry
entryEntry-note rows only: the company entry exactly as you gave it
rowsFetchedStatus rows only: postings received before de-duplication and the cap
rowsReturnedStatus rows only: rows written to the dataset before this status row, uncharged entry notes included
rowsRemainingStatus rows only: fetched postings not returned

A null in a cell above means that vendor does not publish the value on its public feed. The row still carries the column, as null, so every vendor's rows have the same shape.

Pay. Ashby, Lever and Recruitee publish pay as fields on many postings. Greenhouse and Workable publish it only inside the posting text, if at all. There the Actor reads a range only when it sits next to a pay word and carries a currency. It copies that range to salary_text exactly as written. The pay is always the posting's own figure: on sales roles an employer often publishes on-target earnings (base plus commission), and the row carries that range as published, not a base salary. A figure that is not a pay range (a funding round, a customer count) is not read. How often pay is stated depends on the employer: boards hiring in US states with pay-transparency laws state it on most postings, others rarely.

Location. city, region and country come from the vendor's structured location where it has one. Greenhouse and Lever give a text such as San Francisco, CA. The Actor splits it only when its shape is plain, and reads a US state or Canadian province code as that country. A text naming several places, or only Remote, leaves city null.

Seniority is read from the title alone: Intern, Junior, Senior, Staff, Principal, Lead, Manager, Director, Head of, VP and Chief titles, in English, German and French. A title that states no level (Software Engineer, Product Manager) is null, not assumed to be mid.

Pricing

Pay-per-event: $0.0012 per listing-returned, one posting written to the dataset. The platform also charges apify-actor-start at $0.00005 per GB of run memory, at least one per run. At this Actor's 256 MB default that is one per run.

Status rows (ITEM_STATUS, NO_MATCHING_LISTINGS, STOPPED_EARLY) and dropped duplicates are not charged. Postings removed by a filter are never read in full and never charged.

Postings writtenlisting-returnedStart (default)Total (those two)
100$0.12$0.00005$0.12005
1,000$1.20$0.00005$1.20005
10,000$12.00$0.00005$12.00005

Platform compute is billed separately by Apify according to memory and duration. A run of 100 Ramp postings finished in about 11 seconds on the platform, measured at 1024 MB. A buyer's run uses the 256 MB default unless you raise it, and the time at 256 MB has not been measured, so a run there may take longer. Workable descriptions cost one request per kept posting; a run of 100 such postings takes about half a minute more.

How do I use Greenhouse Jobs Scraper?

  1. Open the Actor on Apify and press Start. The default input reads Ramp's board.
  2. In company, add one entry per company: a company name (Hugging Face), its careers-page URL (https://careers.bunq.com), a slug (ramp), a tagged slug (greenhouse:stripe), or a public board URL. Or pick a preset list.
  3. Optionally set titleKeyword, keywords, departments, locationKeyword, remoteOnly or postedWithinDays to keep only the postings you want, maxItemsPerCompany (default 100), and onlyNew to skip what an earlier run already returned.
  4. Download the dataset. RUN_SUMMARY in the default key-value store has the counts.

Example input, the one this page's sample row came from:

{
"company": ["ramp"],
"maxItemsPerCompany": 100
}

Worked examples

Use it to pull every open job at companies you know only by name. The Actor turns each name into its likely board slugs and tries them on every vendor.

{
"company": ["Hugging Face", "Scale AI", "https://careers.bunq.com"],
"maxItemsPerCompany": 50
}

Use it to find engineering jobs at AI startups posted this week, from a preset list with several title words and one department filter.

{
"preset": "ai-startups",
"keywords": ["engineer", "researcher", "scientist"],
"departments": ["engineering", "research"],
"postedWithinDays": 7,
"maxItemsPerCompany": 30
}

Use it to build a list of senior remote jobs with published pay. Filter on the board, then keep rows where salary_text is filled and seniority is senior or staff/principal in your spreadsheet.

{
"company": ["ramp", "greenhouse:stripe", "lever:zoox"],
"remoteOnly": true,
"maxItemsPerCompany": 100
}

Daily new jobs only. See the next section.

Daily new jobs only

Turn on onlyNew and run the Actor on a daily schedule (Apify Console, Schedules, cron 0 7 * * *). The first run returns every current posting and remembers each one it returned; every later run returns only postings that appeared since. Add postedWithinDays to keep the first run small.

Use it to get a daily feed of only the new jobs at fintech companies.

{
"preset": "fintech",
"onlyNew": true,
"postedWithinDays": 2,
"maxItemsPerCompany": 100
}

The memory is a named key-value store in your account, greenhouse-lever-ashby-job-seen, keyed by posting URL. A posting is remembered only after it was written to your dataset, so a run cut short by a spend limit leaves the rest for the next day. Delete that store to start over. Only the postings returned are charged, so a day with nothing new costs one start event and no posting events.

How to find a company's slug

Usually you do not need to. Put the company's name or its careers-page URL in company and the Actor tries the likely slugs (Scale AI gives scaleai and scale-ai) on all five vendors. The order is Ashby, Greenhouse, Lever, Workable, Recruitee. The company's own website is never fetched; only the vendors' public feeds are asked. The log says which board answered, and every row carries platform, company_slug and company_name so you can check it is the right employer.

When a name finds nothing, or finds a different company with the same slug, find the slug by hand:

  1. Open the company's careers page and click any job.
  2. Read the job's address. The slug is the part right after the vendor's host:
    • jobs.ashbyhq.com/ramp/... is ashby:ramp
    • boards.greenhouse.io/stripe/jobs/... or job-boards.greenhouse.io/stripe/... is greenhouse:stripe
    • jobs.lever.co/zoox/... is lever:zoox
    • apply.workable.com/nuvei/... is workable:nuvei
    • bunq.recruitee.com/o/... is recruitee:bunq
  3. If the careers page shows jobs inside the company's own site, the vendor's address is often in the apply button's link.
  4. Paste the job address itself into company: any vendor board URL is read directly.

Tag the slug with its vendor (greenhouse:stripe) to skip the other vendors and to stop a same-named board on another vendor from answering first.

API (replace the token):

https://api.apify.com/v2/acts/Pradio~greenhouse-lever-ashby-job/runs?token=YOUR_TOKEN

with body {"company":["ramp"],"maxItemsPerCompany":20}.

Input

InputTypeDefaultRequiredWhat it does
companylist of strings["ramp"]noOne entry per company: name, careers-page URL, slug, vendor:slug, or public board URL
presetchoice(none)noAdd a bundled list: ai-startups (21 companies) or fintech (12 companies)
maxItemsPerCompanyinteger100noMost posting rows per company; each board is capped on its own
maxItemsinteger(none)noOverall cap across the run, on top of the per-company cap
titleKeywordstring(empty)noKeep postings whose title contains this text, case-insensitive
keywordslist of strings(empty)noKeep postings whose title contains any of these, case-insensitive
departmentslist of strings(empty)noKeep postings whose department contains any of these, case-insensitive
locationKeywordstring(empty)noKeep postings whose location text, city, region, country or structured address contains this text
remoteOnlybooleanfalsenoKeep only postings the vendor marks remote; an unclassified posting is dropped, not guessed
postedWithinDaysinteger(none)noKeep postings published in the last N days; a posting with no date is dropped
onlyNewbooleanfalsenoSkip postings an earlier run under your account already returned
includeDescriptionbooleantruenoRead the per-posting description on Workable (one request per kept posting)

With neither company nor preset, the run reads Ramp's board.

company

Accepted forms, one per entry:

  • Company name: Hugging Face, Scale AI. Turned into likely slugs and tried on every vendor.
  • Careers-page URL or domain: https://careers.bunq.com, stripe.com. The domain's name is tried as a slug on every vendor; the page itself is not fetched.
  • Bare slug: ramp, tried on Ashby, Greenhouse, Lever, Workable and Recruitee in that order until one answers.
  • Tagged: ashby:ramp, greenhouse:stripe, lever:spotify, workable:nuvei, recruitee:bunq. Pin the vendor when two of them know the same slug.
  • Board URLs: https://jobs.ashbyhq.com/ramp, https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify, https://apply.workable.com/nuvei/, https://bunq.recruitee.com/, and the vendors' API URLs for the same boards.

It does not accept applicant Data API URLs, Harvest tokens, or login cookies.

preset

A bundled list of companies, each board checked on its vendor's public feed on 2026-09-24 and confirmed to be the named company's. It adds to company; a board in both is read once.

  • ai-startups: OpenAI, Anthropic, Cohere, Perplexity, ElevenLabs, Harvey, Replit, Cursor, LangChain, Deepgram, Synthesia, Sierra, Modal, Character.AI, Writer, Pinecone, Scale AI, Together AI, AssemblyAI, Glean, Hugging Face.
  • fintech: Stripe, Ramp, Plaid, Brex, Chime, Robinhood, Coinbase, Affirm, SoFi, Monzo, Gusto, bunq.
{
"preset": "fintech",
"titleKeyword": "engineer"
}

maxItemsPerCompany and maxItems

Each company keeps at most maxItemsPerCompany postings after the filters, so a board of 300 never starves the next one on the list. maxItems is an extra ceiling on the whole run; leave it empty unless you want one.

titleKeyword, keywords, departments, locationKeyword, remoteOnly, postedWithinDays

Substring matches, case-insensitive. titleKeyword is one text the title must contain. keywords is a list, and the title must contain at least one of them. When both are set a posting must pass both. departments keeps postings whose department contains any of its entries. locationKeyword reads the location text, the city, region and country, and the structured address. remoteOnly keeps only postings whose vendor marks them remote. postedWithinDays keeps postings whose stated posting date is within the last N days. A posting the board gives no department or no date for is dropped by that filter, not guessed. All of them run before any per-posting description is read, so filtered-out postings cost nothing.

{
"company": ["greenhouse:anthropic"],
"keywords": ["engineer", "research"],
"departments": ["AI Research"],
"postedWithinDays": 30
}

onlyNew

Postings this Actor has returned under your account are remembered in a named key-value store, greenhouse-lever-ashby-job-seen, by posting URL. A posting is added only after it was actually returned, so a run cut short by a spend cap leaves the rest for next time. Delete that store to forget everything.

includeDescription

Ashby, Greenhouse, Lever and Recruitee include the description in the board response. Workable publishes it on a per-posting endpoint, one request per kept posting. Set this to false for a cheaper title-and-link run on Workable; its description is then null.

Output

  • Posting rows carry row_type: "ROW" and every field in the table above (a value the vendor does not publish is null, never omitted). Duplicate official_url values are dropped before charge.
  • An entry this Actor does not read (SmartRecruiters or Personio): one uncharged row with row_type: "ITEM_STATUS", status: "vendor_not_read", the entry as you gave it and a reason. The other entries in the run are read as usual.
  • An entry with no public board (a misspelt slug, or a company none of the five vendors hosts): one uncharged row with row_type: "ITEM_STATUS", status: "no_board_found", the entry as you gave it and a reason naming the vendors tried. The other entries in the run are read as usual.
  • Zero postings: one uncharged row with row_type: "NO_MATCHING_LISTINGS" and a reason. The dataset is never empty. Its rowsReturned counts the entry notes written before it, 0 when there are none.
  • Spend cap: one uncharged STOPPED_EARLY row with rowsReturned and rowsRemaining.
  • On both status rows rowsReturned is the number of rows written before that row, entry notes included: the same count RUN_SUMMARY calls rowsPushed.
  • RUN_SUMMARY in the default key-value store: rowsFetched, rowsPushed, rowsCharged, duplicatesDropped, stoppedEarly, and skippedSeen when onlyNew is on.

An HTTP error, a JSON parse failure, or a 429 that still fails after retries fails the run. That is deliberate: a refused read is not an empty board.

What can you do with the data?

A researcher compiling every open engineering role across a list of portfolio companies passes their slugs in company with titleKeyword set to engineer. The export carries title, department, location, apply_url and pay where published.

A sourcer watching Stripe's Greenhouse board and Spotify's Lever board sets locationKeyword to London and onlyNew to true. Each week they get only the postings that appeared since the last run.

A pipeline that already stores company slugs maps each one to this Actor, writes rows into a warehouse, and joins on official_url or job_id as the stable posting key.

An agent asks for one company by name and reads rectangular fields instead of learning five vendor dialects.

Use Greenhouse Jobs Scraper with AI agents

claude mcp add --transport http apify "https://mcp.apify.com?tools=Pradio/greenhouse-lever-ashby-job"

Paste that line to give an MCP client this Actor as a tool (the tool name is the Store identity Pradio/greenhouse-lever-ashby-job).

Personal data

Each row describes a job posting, not a person. There are no name, email or phone columns. The one place a person can appear is description, which is the employer's own posting text, unchanged: some employers name a recruiter or the hiring manager there. The Actor never pulls those names out into columns of their own: no field extracts a person's name, email or phone from the description. Names that appear inside a description stay inside it, and there is no hiring_manager or recruiter_email column.

You decide what to do with the rows, so you are the controller of any personal data in them, and you need a lawful basis for keeping and using it (for example legitimate interest under the GDPR or the UK GDPR).

The rows are meant for job market research and for finding jobs: who is hiring, for what, where, and at what pay. Do not use them to build profiles of the people a posting names.

Every row carries platform, official_url and company_slug, so you can always say which public job board a posting came from.

If you run a job board, or you are named in a posting, and want it left out of future runs, open an issue on the Actor's Issues tab with the board or the posting URL. The board or posting goes on a removal list that every run reads before anything is fetched. A removed board returns one uncharged ITEM_STATUS row with status vendor_not_read and a reason saying it was removed on request.

The descriptions are the employers' own job adverts, reproduced for reference and linked to the original posting. Do not republish them as your own content, and do not use these rows to train AI models. Lever's site asks that its postings be used for reference only and not for AI training, and Workable's asks that they not be used for AI training.

Limits

  • Public job-board feeds only. Ashby posting-api, Greenhouse boards-api, Lever postings, Workable's widget and v2 job endpoints, and Recruitee's public offers feed. No Harvest, no authenticated Data APIs, no apply POST, no shared ATS accounts, no HTML scrape of careers sites.
  • Polite by each vendor's own rules. Lever rows are read at most one request per second, following the Crawl-delay line in Lever's robots.txt. A Recruitee board whose robots.txt disallows the offers feed is not read.
  • Five vendors, named. SmartRecruiters and Personio are not read, and an entry naming either returns one uncharged row saying so. Workday, iCIMS and Taleo are not read: they have no logged-out job-board feed. A company whose board lives on one of those is tried on the five and found on none. That entry returns one uncharged no_board_found row naming it rather than a guess, and when no other entry returned postings the run ends with the uncharged NO_MATCHING_LISTINGS row as well.
  • Finding a board by name is a best guess on the slug. A company whose board uses a slug unlike its name is not found that way. A different company with the same slug can answer first. Check company_name, and tag the slug when it matters (see How to find a company's slug).
  • A list of company boards per run, not a search engine across every company on a vendor.
  • No browser, no proxy. If a host refuses the GET, the run fails (with backoff on HTTP 429).
  • Pay only when the posting publishes it. Greenhouse publishes a pay range only on boards that turn it on, and Workable publishes no pay fields. Otherwise their pay is read only from a range the posting text states next to a pay word and a currency. A posting without one carries null pay fields.
  • remoteOnly drops the unclassified. Greenhouse has no remote flag, so a Greenhouse posting passes remoteOnly only when its location text says Remote.
  • Not affiliated with Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, or any employer whose board you read. Re-read each vendor's public API docs and site terms before you rely on a high-volume schedule; stop if they object.

Adjacent Actors from the same publisher: Authentic Jobs Listings Scraper for that board's public listings feed, and Voice Over Jobs Monitor for voice-over castings. This Actor is only the five vendors' public job-board feeds.

Report problems on the Actor's Issues tab on Apify.

Troubleshooting

I got fewer rows than maxItemsPerCompany. The board had fewer postings after the filters, or Ashby skipped isListed: false items. That is the board running out, not a silent error. Check RUN_SUMMARY.rowsFetched.

I got one row and no jobs. Read row_type. NO_MATCHING_LISTINGS means every vendor tried for that slug answered and there were no postings, or none passed the filters, or onlyNew had already returned them all. That one row is the answer; it is not billed.

The run failed instead of returning empty titles. A 401/403/5xx or truncated JSON on any board fails the whole run, and nothing is written or billed: postings are written only once every board is read. Take the refusing board off your list and run again, or wait out a 429. Empty-looking success rows are not produced on a refused read.

A bare slug or a name found the wrong company. Two vendors can know the same slug. Check company_name, then pin it: greenhouse:your-slug, workable:your-account.

A company name found nothing. Its board uses a slug unlike its name. Follow How to find a company's slug and pass the tagged slug or a job's URL.

A SmartRecruiters entry returned one row and no jobs. SmartRecruiters is not read: its robots.txt allows only one named crawler. A smartrecruiters: entry or a SmartRecruiters URL returns one uncharged ITEM_STATUS row with status vendor_not_read, and the rest of the run goes on.

FAQ

Can I use integrations with Greenhouse Jobs Scraper?

Yes. Apify integrations can start this Actor and pass any of the inputs above. Chain it by storing the dataset and pointing the next Actor at that dataset URL.

Can I use Greenhouse Jobs Scraper with the Apify API?

Yes. Start runs against Pradio/greenhouse-lever-ashby-job (Pradio~greenhouse-lever-ashby-job in the path). The input JSON is the same as the Console. Dataset items and RUN_SUMMARY are the same records as a Console run.

Can I use Greenhouse Jobs Scraper through an MCP server?

Yes. Use the snippet in Use Greenhouse Jobs Scraper with AI agents so the client exposes this Actor as a tool.

Can I run it on a schedule?

Yes. In the Apify Console open Schedules, add one with a cron such as 0 7 * * * and pick this Actor with your input. Turn on onlyNew and each scheduled run returns only the postings it has not returned before; see Daily new jobs only above.

This Actor only GETs the vendors' public job-board / posting feeds (logged-out JSON), the same endpoints their own careers-page embeds read. It does not use Harvest or applicant APIs and it does not collect recruiter emails. You are responsible for each vendor's current public API rules and terms, for your jurisdiction, and for stopping if a host objects. This page is not legal advice. The Actor is not an official product of any vendor named here. See Personal data for how the rows may be used.

Release notes

  • 0.1.24, 2026-09-25: on the zero-postings row rowsReturned now counts the uncharged entry notes written before it, as STOPPED_EARLY already did; it no longer reads 0 beside notes.
  • 0.1.16, 2026-09-25: SmartRecruiters boards are no longer read: its robots.txt allows only one named crawler. A smartrecruiters: entry or a SmartRecruiters URL now returns one uncharged ITEM_STATUS row that names the entry and says why. Wise leaves the fintech preset, which now lists 12 companies. Lever boards are read at most once a second, as Lever's robots.txt asks. Each Recruitee company's robots.txt is read first, and a board it disallows returns one uncharged row. Boards and postings can be removed from every run on request.
  • 0.1.15, 2026-09-24: Personio boards are removed pending a review of Personio's terms. A personio: entry or a Personio board URL now returns one uncharged ITEM_STATUS row that names the entry and says why; every other vendor is unchanged.
  • 0.1.14, 2026-09-24: Recruitee boards are read. Give a company name or careers-page URL instead of a slug, or a preset list of AI or fintech companies. New columns company_name, seniority, salary_text, pay_interval, has_equity, city, region and country; pay stated in the posting text is now read on Greenhouse, Workable and SmartRecruiters (SmartRecruiters stopped being read in 0.1.16). New filters keywords, departments and postedWithinDays. compensation and address are unchanged, and every earlier input still works; company is no longer required.
  • 0.1.13, 2026-09-24: remoteOnly now keeps remote postings only. Ashby marks hybrid roles as remote-allowed, and those came back before; is_remote now follows the posting's workplace type. company_name is renamed company_slug, which is what it holds.
  • 0.1.10, 2026-09-10: Ashby, Greenhouse, Lever, Workable and SmartRecruiters, a list of companies per run, title, location and remote filters, only-new, and a per-company cap.

Not affiliated

Greenhouse Jobs Scraper is an independent tool. It is not affiliated with, endorsed by, or maintained by Greenhouse Software, Lever (Employ Inc.), Ashby, Workable, SmartRecruiters, Recruitee, or any employer whose public job board you request. Job content belongs to the posting company.