# Greenhouse, Lever & Ashby Jobs Scraper (`santamaria-automations/greenhouse-lever-ashby-jobs-scraper`) Actor

Scrape every open job from Greenhouse, Lever and Ashby company boards: title, company, location, department, salary where stated, apply URL and full description. Filter by keyword, location and date. Pay per result.

- **URL**: https://apify.com/santamaria-automations/greenhouse-lever-ashby-jobs-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Greenhouse, Lever & Ashby Jobs Scraper

Get every open job of any company that hires through [Greenhouse](https://www.greenhouse.com), [Lever](https://www.lever.co) or [Ashby](https://www.ashbyhq.com). Paste a company board URL (or just the company name) and receive title, location, department, employment type, remote flag, salary where the posting states one, apply URL and the full job description. No login, no API key. Fast, with clean rows.

One actor for the three most common applicant tracking systems of startups and tech companies. It reads the public job board endpoints of each system, so the data is live at run time.

### What you can do with it

- Pull all open roles of a list of target companies for lead generation or recruiting research.
- Track hiring at competitors: run it on a schedule with `postedWithinDays` and `sortBy: newest` to see only new postings.
- Build a job board or alert feed from the boards of companies you care about.
- Collect stated salary ranges (Greenhouse pay transparency, Lever salary range, Ashby compensation) for market research.

### Two ways to run it

A run is in exactly one mode, decided from your input and written to the run log.

| Your input | Mode | What happens |
|------------|------|--------------|
| `companies` (with or without `keywords`) | **Company mode** | Reads exactly the boards you list. `keywords` only filter their jobs. |
| `keywords` and no `companies` | **Keyword search** | Searches the jobs of many companies at once, from a built-in list of 10,550 companies on Greenhouse, Lever and Ashby, biggest hirers first. |
| nothing (`{}`) | Company mode | Reads four sample boards. |

Keyword search is for questions such as "which companies are hiring a data engineer in Germany right now" when you do not know the companies in advance. It matches the job title, the same as company mode. Each company is read once and jobs are pushed as the companies are scanned, so you see rows early. Use `countries`, `location`, `postedWithinDays` and `maxCompanies` to narrow the search, and `maxResults` to stop early. The built-in list is verified live when it is generated and refreshed with each release; a company that has since changed system is skipped.

Every row has the same fields in both modes, and duplicates are removed before anything is charged.

### Input

| Field | Description |
|-------|-------------|
| `companies` | Company mode. Board URLs or bare company names. Strings, `{"url": "..."}` objects, a single string, or several separated by commas or new lines. Empty (and no keywords) = four sample boards. |
| `ats` | Only for bare company names: `auto` (default, tries Greenhouse, then Lever, then Ashby), or `greenhouse`, `lever`, `ashby`. In keyword search it limits the scan to that system. |
| `keywords` | Keep only jobs whose title matches at least one keyword. With no `companies` it starts keyword search. |
| `location` | Keep only jobs in this city, region or country (`London`, `Germany`, `DE`). |
| `includeRemoteWithoutRegion` | boolean | Only with a country filter: also keep remote jobs that state no country or region (they may not be open to applicants in that country). | `false` |
| `countries` | Keyword search only. ISO-2 codes such as `["DE", "CH"]`: skips companies known not to hire there and keeps only jobs in these countries (jobs whose country cannot be determined are left out). |
| `maxCompanies` | Keyword search only. How many companies of the built-in list are scanned, biggest hirers first. Default 500. |
| `postedWithinDays` | Drop jobs older than this many days. |
| `sortBy` | `newest` (default) or `relevance` (the board's own order). In keyword search, newest first within each company. |
| `maxJobsPerCompany` | Cap per company, counted after the filters. `0` = all. Default 50. |
| `maxResults` | Cap for the whole run. The run stops cleanly when it is reached. `0` = no limit. Default 100. |
| `includeDescription` | Include the full description HTML. Default `true`. |

Remote jobs under a country filter: a country filter is the `location` input when it is a country (`Germany`, `DE`). A remote job is kept when its text names that country (`Remote - Germany`, `Remote (DE)`, `Germany (Remote)`), names a region that contains it (EMEA, Europe, EU, DACH for DE/AT/CH, Americas or North America for US/CA, LATAM, APAC, UK & Ireland) or says it is open worldwide (`Worldwide`, `Anywhere`, `Global`). A remote job that names another country or a region without your country is dropped. A job that says only `Remote` (also `Remote OK`, `Fully remote`, or a remote flag with no place) does not state where it can be filled from, so it is left out by default and not charged; the run status says how many were left out. Turn on `includeRemoteWithoutRegion` to keep them anyway (they may not be open to applicants in your country). Jobs with a physical place are judged by that place as before.

#### Example: keyword search

```json
{
  "keywords": ["data engineer", "product manager"],
  "countries": ["DE", "CH"],
  "postedWithinDays": 14,
  "maxResults": 100
}
```

#### Example: board URLs

```json
{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "https://jobs.lever.co/palantir",
    { "url": "https://jobs.ashbyhq.com/openai" }
  ],
  "keywords": ["engineer", "data"],
  "postedWithinDays": 14,
  "sortBy": "newest",
  "maxJobsPerCompany": 25
}
```

#### Example: bare company names

```json
{
  "companies": ["airbnb", "palantir", "openai"],
  "maxResults": 60
}
```

Each name is looked up on Greenhouse, Lever and Ashby in that order and the first board that exists is used. If you already know the system, set `"ats": "lever"` and the lookup is skipped.

Only Greenhouse, Lever and Ashby boards are read. A URL of any other job system (Workday, Workable, SmartRecruiters and so on) is skipped with a log line and is never charged; for Workday use the [Workday Jobs Scraper](https://apify.com/santamaria-automations/workday-jobs-scraper), and for 40 more systems use [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper).

#### Supported URL formats

- Greenhouse: `https://boards.greenhouse.io/{company}`, `https://job-boards.greenhouse.io/{company}`, a posting URL of those, or the board API URL.
- Lever: `https://jobs.lever.co/{company}`, `https://jobs.eu.lever.co/{company}` (EU instance), or a posting URL.
- Ashby: `https://jobs.ashbyhq.com/{company}` or a posting URL.

### Output

One dataset row per job. Duplicates are removed before anything is charged, so the number of rows is the number of results you pay for.

```json
{
  "id": "ashby-7b2865a7-1f148786-2e00-472a-96b9-0b29015980e1",
  "ats_job_id": "1f148786-2e00-472a-96b9-0b29015980e1",
  "title": "Product Data Scientist - Youth, Families and Learning",
  "company": "Openai",
  "ats_platform": "ashby",
  "location": "San Francisco",
  "city": "San Francisco",
  "country": "US",
  "department": "Data Science",
  "employment_type": "Full-time",
  "remote": true,
  "description": "<p>About the Team ...</p>",
  "apply_url": "https://jobs.ashbyhq.com/openai/1f148786-2e00-472a-96b9-0b29015980e1/application",
  "job_url": "https://jobs.ashbyhq.com/openai/1f148786-2e00-472a-96b9-0b29015980e1",
  "language": "en",
  "created_at": "2026-10-20T21:21:22Z",
  "salary_text": "$401K - $510K",
  "salary_min": 401000,
  "salary_max": 510000,
  "salary_currency": "USD",
  "salary_period": "year",
  "salary_source": "stated",
  "scraped_at": "2026-10-21T04:37:09Z"
}
```

`salary_*` fields are filled only when the posting states a salary; they are never estimated. `created_at` is the posting date (Greenhouse `first_published`, Lever `createdAt`, Ashby `publishedAt`).

### Pricing

Pay per result. You pay the platform start fee per run and then only for the jobs you receive. Filtered-out and duplicate jobs are never charged.

| Event | When | Price |
|---|---|---|
| `job-result` | one job from company mode (you list the companies) | $0.001 |
| `job-result-keyword-search` | one job from keyword search across companies | $0.0015 |

The pricing box on the actor page always shows the current rates.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client, such as Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

**Example prompts once connected:**

> "Use `greenhouse-lever-ashby-jobs-scraper` to get all open engineering roles at Airbnb, Palantir and OpenAI posted in the last 14 days. Return a table with title, location and apply URL."

> "Use `greenhouse-lever-ashby-jobs-scraper` for the company names stripe, ramp and notion and list the roles that state a salary."

> "Use `greenhouse-lever-ashby-jobs-scraper` keyword search for `data engineer` in Germany and Switzerland, posted in the last 14 days, and return the 30 newest with company and apply URL."

Configure the MCP server with the Greenhouse, Lever & Ashby Jobs Scraper preconfigured at `mcp.apify.com?tools=santamaria-automations/greenhouse-lever-ashby-jobs-scraper`:

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/greenhouse-lever-ashby-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}
```

See the auto-generated API tab on the actor page for language-specific examples (cURL, JavaScript, Python, and more).

### FAQ

**Do I need an API key for Greenhouse, Lever or Ashby?**
No. The actor reads the public job board endpoints these systems provide for career pages and job aggregators.

**How do I find out which system a company uses?**
Open the company's careers page and look at the URL of a job: `boards.greenhouse.io`, `jobs.lever.co` and `jobs.ashbyhq.com` are the three this actor reads. Or give the company name and let the actor look it up. The [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor) finds the careers page and the job system of any company website.

**What if a company is not found?**
The run continues with the other companies. The run status line names the company and the reason (for example `board_not_found`), and nothing is charged for it.

**Which companies does keyword search cover?**
A built-in list of 10,550 companies that publish their jobs on Greenhouse, Lever or Ashby, built from our company directory, the public YC company list and public company lists, and checked live (the job board answered and had at least one open job) when the list was generated. It is not every company on these systems. If a company you need is missing, pass its board URL in `companies` instead.

**Why did I get fewer jobs than `maxJobsPerCompany`?**
The caps apply after your filters, and a board can simply have fewer open jobs. Companies are read in the order you list them, and the run stops once `maxResults` is reached.

### Related actors

- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper): the same engine for 40+ job systems (Workday, SmartRecruiters, Personio, Workable and more).
- [Workday Jobs Scraper](https://apify.com/santamaria-automations/workday-jobs-scraper): jobs of any Workday job site.
- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): any company website to its careers page, job system and jobs.
- [Indeed Scraper](https://apify.com/santamaria-automations/indeed-http-scraper): Indeed job listings in 60+ countries.
- [Glassdoor Scraper](https://apify.com/santamaria-automations/glassdoor-scraper): Glassdoor jobs with employer ratings and salary estimates.

### Support

- **Questions or issues?** Email contact@nanoscrape.com, we typically reply within 6 hours, or open a ticket in the Issues tab on the actor page.
- **Need a scraper for a job board we don't cover yet?** Email contact@nanoscrape.com with the target site and your rough usage volume.

# Actor input Schema

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

COMPANY MODE. Company job boards to read. Pass board URLs such as https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir or https://jobs.ashbyhq.com/openai, as strings or as {"url": "..."} objects (a single string, or several separated by commas or new lines, also works). A bare company name such as "airbnb" is looked up on Greenhouse, then Lever, then Ashby (set ATS below to skip the lookup). A posting URL is reduced to its board. URLs of other job systems are skipped with a log line and are never charged. With no companies and no keywords the actor runs four sample boards (an empty input does this too). With keywords and no companies it runs KEYWORD SEARCH instead (see Keywords). If you give both companies and keywords, it reads only your companies and the keywords filter their jobs.

## `ats` (type: `string`):

Only used for bare company names (not URLs). auto tries Greenhouse, then Lever, then Ashby and uses the first board that exists.

## `keywords` (type: `array`):

Return only jobs whose TITLE matches at least one of these words or phrases (OR). Case and accents are ignored. A keyword of 4 or more characters matches anywhere inside the title; a keyword of 3 or fewer characters (for example QA, PM) must match as a whole word. Example: \["engineer", "manager"]. KEYWORD SEARCH MODE: when you give keywords and leave Companies empty, the actor searches the jobs of many companies at once, from a built-in list of 10,550 companies that use Greenhouse, Lever and Ashby, biggest hirers first (see Max Companies). With no keywords and no companies, it runs the four sample boards.

## `location` (type: `string`):

Optional. Return only jobs in this city, region or country, for example "London", "Germany" or "DE". Country names and ISO codes match in both directions. In keyword search mode it filters the jobs found at every company.

## `includeRemoteWithoutRegion` (type: `boolean`):

Only matters when you filter by country (the Location input is a country, or a query carries a country). Off (default): a remote job counts for the country only when it names it ("Remote - Germany"), names a region that contains it (EMEA, Europe, EU, DACH, Americas, APAC) or is open worldwide. Remote jobs that say only "Remote" are left out and are not charged. On: those jobs are kept too, but they may not be open to applicants in the chosen country.

## `countries` (type: `array`):

Only used by keyword search (keywords given, no companies). ISO 3166-1 alpha-2 codes such as \["DE", "CH"]. Skips companies of the built-in list that are known not to hire in these countries, and returns only jobs located in these countries (jobs whose country cannot be determined are left out). Ignored when you list companies.

## `maxCompanies` (type: `integer`):

Only used by keyword search. How many companies of the built-in list (10,550 in total) are scanned, biggest hirers first (by open jobs). A smaller number is faster; the run also stops as soon as Max Results is reached.

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

Optional. Drop jobs posted more than this many days ago. Jobs without a posting date are kept.

## `sortBy` (type: `string`):

"newest" returns the most recently posted jobs of each company first, so maxJobsPerCompany keeps the newest ones. "relevance" keeps the site's own order. In company mode, companies are read in the order you list them. In keyword search mode, rows are pushed as each company is scanned (biggest hirers first) and are ordered newest first within each company.

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

Maximum number of jobs returned per company, counted after the filters (filtered-out jobs are never returned or charged). 0 = all jobs. In keyword search mode this also limits how many matching jobs one company can contribute, so no single company fills the result.

## `maxResults` (type: `integer`):

Maximum number of jobs returned in total across all companies. The run stops cleanly once it is reached. 0 = no limit.

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

Include the full job description (HTML) in the output. Switch off for a smaller, faster run.

## Actor input object example

```json
{
  "ats": "auto",
  "keywords": [
    "data engineer"
  ],
  "includeRemoteWithoutRegion": false,
  "maxCompanies": 500,
  "sortBy": "newest",
  "maxJobsPerCompany": 10,
  "maxResults": 50,
  "includeDescription": true
}
```

# Actor output Schema

## `items` (type: `string`):

Job listings from Greenhouse, Lever and Ashby company job boards

# 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 = {
    "keywords": [
        "data engineer"
    ],
    "maxJobsPerCompany": 10,
    "maxResults": 50,
    "includeDescription": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/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 = {
    "keywords": ["data engineer"],
    "maxJobsPerCompany": 10,
    "maxResults": 50,
    "includeDescription": True,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/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 '{
  "keywords": [
    "data engineer"
  ],
  "maxJobsPerCompany": 10,
  "maxResults": 50,
  "includeDescription": true
}' |
apify call santamaria-automations/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,santamaria-automations/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/2Ovm75RhH8g69oS7V/builds/xRi2rQEkzk0PCEBAn/openapi.json
