# Greenhouse, Lever, Ashby, Workable & More Jobs Scraper (`leezx/greenhouse-lever-ashby-jobs-scraper`) Actor

Get open jobs from any company on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee or Personio in one clean format: title, location, remote type, pay range and apply link. Filter by keyword, date or pay, or return only jobs added since your last run.

- **URL**: https://apify.com/leezx/greenhouse-lever-ashby-jobs-scraper.md
- **Developed by:** [Leo Lee](https://apify.com/leezx) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 job returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Company Jobs Scraper: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee & Personio

Get the open jobs of any company that hires through **Greenhouse**, **Lever**, **Ashby**, **Workable**, **SmartRecruiters**, **Recruitee** or **Personio**, in one clean format. Every job comes back with the same fields: title, company, location, remote type, department, posted date, pay range and apply link.

It reads the public job-board feeds these systems offer to career sites. No login, no browser, no proxy.

### Use this Actor when you want to

- **Build a job feed or job board** from a list of companies.
- **Watch target companies for new roles**. Turn on "Only jobs not seen in earlier runs" and put it on a schedule.
- **Find companies that are hiring** for a skill, in a city, or remote. Companies that open sales or engineering roles are often growing.
- **Compare pay** across roles. Pay ranges are included where the company publishes them.
- **Feed an AI agent or spreadsheet** with fresh, structured job data.

### How to use it

1. Add companies. A plain name like `stripe` is tried on all seven systems. You can also paste a job-board link, or the company's own careers-page link:

   | System | Link looks like |
   | --- | --- |
   | Greenhouse | `boards.greenhouse.io/stripe` |
   | Lever | `jobs.lever.co/spotify` (EU: `jobs.eu.lever.co/...`) |
   | Ashby | `jobs.ashbyhq.com/ramp` |
   | Workable | `apply.workable.com/huggingface` |
   | SmartRecruiters | `jobs.smartrecruiters.com/BoschGroup` |
   | Recruitee | `miaplaza.recruitee.com` |
   | Personio | `vivid.jobs.personio.de` |

2. Optionally pick a starter list (AI companies, fintech, developer tools) and set filters.

3. Run. Download the results as JSON, CSV or Excel, or call the Actor from the API.

A plain name is tried everywhere, so a board with the same name that belongs to a different company would come back too. To avoid that, write the system in front (`workable:huggingface`) or paste the board link.

Filters run before billing, so you only pay for jobs that match.

#### Example: remote engineering jobs from the last 7 days

```json
{
    "companies": ["stripe", "lever:spotify", "https://apply.workable.com/huggingface"],
    "titleKeywords": ["engineer", "developer"],
    "remoteOnly": true,
    "postedWithinDays": 7,
    "maxItems": 200
}
```

#### Example: daily new-jobs feed

```json
{
    "presetLists": ["ai"],
    "onlyNewSinceLastRun": true,
    "stateKey": "ai-daily",
    "includeDescription": true
}
```

The first run returns everything that matches. Each later run with the same `stateKey` returns only jobs that were not returned before.

### Output

One job looks like this (made-up values, not a real posting):

```json
{
    "id": "greenhouse:exampleco:1234567",
    "platform": "greenhouse",
    "company": "Example Co",
    "companySlug": "exampleco",
    "title": "Backend Engineer, Payments",
    "department": "Engineering",
    "team": null,
    "location": "Remote in the US",
    "otherLocations": [],
    "workplaceType": "remote",
    "employmentType": null,
    "employmentTypeRaw": null,
    "postedAt": "2026-10-26T09:00:00-04:00",
    "updatedAt": "2026-10-28T15:30:00-04:00",
    "salaryMin": 150000,
    "salaryMax": 210000,
    "salaryCurrency": "USD",
    "salaryInterval": "year",
    "salarySource": "description",
    "salaryText": "$150,000 - $210,000 USD",
    "jobUrl": "https://boards.greenhouse.io/exampleco/jobs/1234567",
    "applyUrl": "https://boards.greenhouse.io/exampleco/jobs/1234567",
    "scrapedAt": "2026-10-29T12:00:00.000Z"
}
```

Newest jobs come first. `platform` tells you which system the job came from. `description` (text) or `descriptionHtml` is added when you turn on "Include the job description".

### Good to know

- **Pay ranges:** Lever, Ashby, Recruitee and Personio give structured pay when the company fills it in (`salarySource: "api"`). Otherwise the Actor looks for a pay range written in the posting text (`salarySource: "description"`). That is a best-effort read, so check the posting. SmartRecruiters shows pay only inside the job page, so there it is found only when descriptions are on (or when you use "Only jobs that show a pay range").
- **SmartRecruiters is slower with descriptions:** its list has no job text, so each job page is read one by one. Jobs you filter out are never read. A company is listed up to 10,000 jobs.
- **Employment type:** Greenhouse does not publish it, so it is empty for Greenhouse jobs.
- **Remote type:** filled in where the system says it. Workable only marks remote jobs, so its other jobs have an empty remote type. Where a system does not say, the field is empty and the job is dropped if you filter on it.
- **Personio:** jobs come in the company's default language.
- **Company name:** Greenhouse, Workable, Recruitee and SmartRecruiters give it. For Lever, Ashby and Personio it is made from the board name, so use `companySlug` as the stable key.
- **Company not found:** a name that does not match a board is skipped and costs nothing. A SmartRecruiters company with no open jobs counts as not found. The run summary (key `SUMMARY`) lists how many boards were found.
- **Careers-page links** work when the page's HTML points to a board on one of the seven systems. If it does not (many sites load their job list with scripts), the Actor tries the site's name, for example `gitlab` from `about.gitlab.com`, on all seven systems, like a plain name. A name that contains a dot, such as `ride.com`, is read as a website address, so write the system first (`lever:ride.com`) to use it as a board name.

### Pricing

You pay per job returned (see the pricing box on this page). A job you filter out is never billed. Set "Maximum jobs to return" to cap your spend. If you also set a maximum cost per run in the run options, the Actor stops returning jobs when that limit is reached and says so in the run summary. In "only jobs not seen in earlier runs" mode, the jobs it held back are not remembered, so they come back on your next run.

### About the data

Job data is read as-is from the companies' public job boards. It may be incomplete or out of date. Check a job on the company's site before relying on it. The Actor returns only what companies publish for job seekers and does not collect any personal data on purpose; job descriptions are the company's own text.

This Actor is not affiliated with or endorsed by Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee or Personio. Their names are trademarks of their owners and are used here only to say which job boards are supported.

Found a bug or a board that does not work? Open an issue on this Actor's page and include the company name.

### Changelog

- **1.1** Added Workable, SmartRecruiters, Recruitee and Personio.
- **1.0** First release: Greenhouse, Lever and Ashby, filters, pay ranges, new-jobs mode, starter lists.

# Actor input Schema

## `companies` (type: `array`):

Company names, job-board links, or a company's own careers-page link. A plain name such as <code>stripe</code> is tried on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee and Personio. Write the system first, for example <code>workable:huggingface</code>, to pick one.

## `presetLists` (type: `array`):

Add a ready-made list of well-known companies on top of the ones above.

## `titleKeywords` (type: `array`):

Keep a job if its title contains at least one of these words or phrases. Not case sensitive. Leave empty for all jobs.

## `excludeTitleKeywords` (type: `array`):

Drop any job whose title contains one of these, for example <code>intern</code> or <code>manager</code>.

## `locationKeywords` (type: `array`):

For example <code>london</code>, <code>germany</code>, <code>new york</code>. Matches the main location and any extra locations.

## `departmentKeywords` (type: `array`):

For example <code>engineering</code> or <code>sales</code>.

## `remoteOnly` (type: `boolean`):

Keep only jobs the company marks as remote.

## `workplaceTypes` (type: `array`):

Keep only these workplace types. Jobs where the company does not say are dropped when you pick any.

## `employmentTypes` (type: `array`):

Greenhouse does not publish this, so Greenhouse jobs are dropped when you pick any.

## `postedWithinDays` (type: `integer`):

Keep only jobs first posted in the last N days. 0 means any date.

## `onlyWithSalary` (type: `boolean`):

Keep only jobs where a salary range was found. SmartRecruiters shows pay only on the job page, so with this option every SmartRecruiters job page is read and the run takes longer.

## `includeDescription` (type: `boolean`):

Adds the full description to every job. Makes the output larger. The price per job stays the same. SmartRecruiters jobs need one extra page read each, so those runs take longer.

## `descriptionFormat` (type: `string`):

Used only when the description is included.

## `onlyNewSinceLastRun` (type: `boolean`):

The first run returns everything that matches. Later runs with the same name below return only jobs that were not returned before. Good for daily or weekly schedules.

## `stateKey` (type: `string`):

Use a different name for each saved search so their memory stays separate. Only used with the option above.

## `maxItems` (type: `integer`):

Newest jobs come first. Set this to control your spend.

## `maxJobsPerCompany` (type: `integer`):

0 means no limit per company.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "onlyWithSalary": false,
  "includeDescription": false,
  "descriptionFormat": "text",
  "onlyNewSinceLastRun": false,
  "stateKey": "default",
  "maxItems": 10,
  "maxJobsPerCompany": 0
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("leezx/greenhouse-lever-ashby-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("leezx/greenhouse-lever-ashby-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "maxItems": 10
}' |
apify call leezx/greenhouse-lever-ashby-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leezx/greenhouse-lever-ashby-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RxTc8OC9xK4l3l1sl/builds/RmuJxVNzzhVR92ewx/openapi.json
