# Greenhouse Jobs Scraper - Job Board API by Company (`make_no_mistakes/greenhouse-jobs-scraper`) Actor

Scrape open jobs from any company on Greenhouse (boards.greenhouse.io). Type a company name or domain; the board token is found for you. All departments and offices, pay-transparency ranges, requisition ID, apply URL. Delta mode for daily runs.

- **URL**: https://apify.com/make_no_mistakes/greenhouse-jobs-scraper.md
- **Developed by:** [Make No Mistakes LLC](https://apify.com/make_no_mistakes) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 job scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Jobs Scraper: Job Board API by Company

Scrape every open job from any company's Greenhouse job board (`boards.greenhouse.io`,
`job-boards.greenhouse.io`). Type a company name, a domain, a board token or a board URL. The Actor
finds the Greenhouse board token for you and returns each job with its department tree, offices,
pay-transparency ranges, requisition ID, posted and updated dates, full description and apply URL.

| Company | Title | Department | Location | Pay range | Posted | Apply |
|---|---|---|---|---|---|---|
| Airbnb | Account Manager | Business Development | London, United Kingdom | 46,000 - 54,000 GBP / year | 2026-09-09 | [apply](https://careers.airbnb.com/positions/8184174?gh_jid=8184174) |
| Figma | Account Executive, Enterprise | Sales | San Francisco, CA / New York, NY | 165,000 - 190,000 USD / year | 2025-01-28 | [apply](https://boards.greenhouse.io/figma/jobs/5426468004?gh_jid=5426468004) |
| Robinhood | Android Engineer, Government Products | ENG Infrastructure | New York, NY | 166,000 - 195,000 USD / year | 2025-05-08 | [apply](https://boards.greenhouse.io/robinhood/jobs/6669758?t=gh_src=\&gh_jid=6669758) |
| Scale AI | Account Based Marketing Lead | Marketing | San Francisco, CA; New York, NY | 158,400 - 198,000 USD / year | 2026-10-01 | [apply](https://job-boards.greenhouse.io/scaleai/jobs/4739727005) |
| Coinbase | Accountant, Cyprus | Finance & Accounting | Remote - Cyprus | 36,100 EUR / year | 2026-07-09 | [apply](https://www.coinbase.com/careers/positions/8053751?gh_jid=8053751) |

*Real rows from a test run on 2026-10-03.*

**Try it: the default input returns 300 jobs (100 each from Airbnb, Figma and Robinhood) for about
$0.60**, in under 10 seconds. No login, no proxy, no API key: it reads Greenhouse's official public
Job Board API.

### What you get that a generic scraper misses

- **Company name in, board token out.** `Scale AI` resolves to `scaleai`, `figma.com` to `figma`.
  If the name guess misses and you gave a domain, the Actor reads the company's careers page for its
  Greenhouse link (including embedded `boards.greenhouse.io/embed/job_board?for=...` boards).
- **Every pay range, with the right period.** Greenhouse publishes pay-transparency ranges in a
  structured field when the employer opts in. This Actor always requests them (even with
  descriptions switched off), returns **all** ranges in `pay_ranges` (US zones, UK, EU), and reads
  the pay period from the range title: Coinbase's "Hourly Rate: $40" comes back as `HOUR`, not as a
  $40 annual salary. On 10 well-known boards, 1,363 of 2,682 open jobs (51%) carried a pay range,
  and 8 of the 10 employers publish them.
- **The real department tree and office list.** `departments` and `offices` hold every entry, not
  just the first, and the `departments` / `offices` filters match against all of them.
- **Requisition and internal job IDs** to join postings back to the employer's own req, and to
  spot the same requisition posted in several locations.
- **Companies not on Greenhouse are reported, not dropped.** You get a free `company_not_found`
  row naming where the company actually hires, e.g. `not on Greenhouse: this company's job board is
  on Ashby (https://jobs.ashbyhq.com/openai)`.

### Use cases

- **Salary benchmarking:** pull every pay-transparent role at 50 tech companies, filtered to
  `onlyWithPay`, and compare ranges by title, level and location.
- **Recruiting and sourcing:** watch competitor departments (`departments: ["Engineering"]`) and
  get each new requisition the day it opens with delta mode.
- **Sales and market intelligence:** a team that starts hiring "Data Platform" engineers is a
  buying signal for data tooling.
- **Job boards and aggregators:** clean, deduplicated, normalized jobs with real apply URLs.
- **Job seekers:** a daily alert of new roles at your 20 target companies.

### Input

```json
{
  "companies": ["Airbnb", "figma.com", "https://job-boards.greenhouse.io/stripe", "Scale AI"],
  "keywords": ["engineer"],
  "locations": ["New York", "Remote"],
  "remoteOnly": false,
  "postedWithinDays": 14,
  "departments": ["Engineering"],
  "offices": ["New York"],
  "onlyWithPay": true,
  "onlyNewSinceLastRun": false,
  "includeDescription": true,
  "maxItems": 1000,
  "maxItemsPerCompany": 100
}
```

| Field | What it does |
|---|---|
| `companies` | Names, domains, board tokens or board URLs, mixed freely. |
| `keywords` | Keep jobs whose title, department or team contains any of these words. |
| `locations` | Keep jobs whose location contains any of these strings. |
| `remoteOnly` | Keep only jobs whose location says remote. |
| `postedWithinDays` | Keep jobs posted or updated in the last N days (Greenhouse publishes both dates). |
| `departments` | Greenhouse-only: match any of the job's departments, including parents. |
| `offices` | Greenhouse-only: match any of the job's offices. |
| `onlyWithPay` | Greenhouse-only: keep only jobs with a published pay range. |
| `onlyNewSinceLastRun` | Delta mode: only jobs you have not received before (see below). |
| `deltaStateName` | Name of the key-value store that remembers delivered jobs, one per schedule. |
| `includeDescription` | Set false to drop the description fields (pay ranges are still returned). |
| `maxItems` | Total jobs per run, and so your spend cap. |
| `maxItemsPerCompany` | Jobs per company (default 100). Set 0 for whole boards. |

### Output

Every job uses the same normalized schema as the
[Multi-ATS Job Board API](https://apify.com/make_no_mistakes/multi-ats-job-board-api), plus
Greenhouse-specific fields:

```json
{
  "record_type": "job",
  "company": "Figma",
  "title": "Account Executive, Enterprise",
  "department": "Sales",
  "location_raw": "San Francisco, CA • New York, NY • United States",
  "city": "San Francisco",
  "is_remote": false,
  "salary_min": 165000,
  "salary_max": 190000,
  "salary_currency": "USD",
  "salary_period": "YEAR",
  "posted_at": "2025-01-28",
  "updated_at": "2026-07-22",
  "apply_url": "https://boards.greenhouse.io/figma/jobs/5426468004?gh_jid=5426468004",
  "company_slug": "figma",
  "ats": "greenhouse",
  "job_id": "5426468004",
  "source_url": "https://boards-api.greenhouse.io/v1/boards/figma/jobs",
  "greenhouse_board_token": "figma",
  "internal_job_id": "4868517004",
  "requisition_id": "1451",
  "departments": ["Sales"],
  "offices": ["US"],
  "pay_ranges": [
    {"min": 165000, "max": 190000, "currency": "USD", "period": "YEAR", "title": "Annual Base Salary Range:"}
  ],
  "has_pay_range": true,
  "application_deadline": null
}
```

`description_html` and `description_text` carry the full posting, and `raw` keeps the untouched
Greenhouse record. Greenhouse's board API publishes **no employment type**, so `employment_type` is
null by design. `salary_min`/`salary_max` use the USD range when there are several (else the
first); `pay_ranges` has them all.

Dataset views: **Jobs**, **Greenhouse details** and **Companies not on Greenhouse**. `RUN_SUMMARY`
in the key-value store records how each company was resolved and how many jobs came back.

### Delta mode for scheduled runs

Set `onlyNewSinceLastRun: true` and schedule the Actor. The first run returns everything and
remembers it; later runs return only jobs not delivered before, and **never charge twice for the
same job**. State lives in a named key-value store in your own account (`deltaStateName`), one
record per board. Use a different name per independent schedule.

### Pricing

Pay per event, no subscription:

| | Free plan | Bronze | Silver | Gold and up |
|---|---|---|---|---|
| Per job | $0.002 | $0.0015 | $0.001 | $0.0006 |
| Per run start | $0.001 | $0.001 | $0.001 | $0.001 |

- 100 jobs on the Free plan: about **$0.20**. 1,000 jobs: about **$2.00**.
- `company_not_found` rows are free.
- `maxItems` is a hard spend cap. If your run's **Maximum cost per run** is too low for the jobs in
  scope, the run says so on its status line and in `RUN_SUMMARY` instead of silently returning less.

### No login, no proxy, official public API

Greenhouse publishes its Job Board API (`boards-api.greenhouse.io/v1/boards/{token}/jobs`) for
exactly this purpose: public, unauthenticated read access to published jobs. No account, cookies
or proxies are involved.

### Related Actors

- [Multi-ATS Job Board API](https://apify.com/make_no_mistakes/multi-ats-job-board-api): one run
  across nine ATS platforms. Use it when your company list spans Greenhouse, Lever, Ashby, Workday
  and others.
- [Company ATS Detector](https://apify.com/make_no_mistakes/company-ats-detector) (free): which
  ATS does a company use?
- [Workday Jobs Scraper](https://apify.com/make_no_mistakes/workday-jobs-scraper),
  [Ashby Jobs Scraper](https://apify.com/make_no_mistakes/ashby-jobs-scraper) and
  [Lever Jobs Scraper](https://apify.com/make_no_mistakes/lever-jobs-scraper): the same engine for
  the other big platforms.

### API example

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/make_no_mistakes~greenhouse-jobs-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companies": ["airbnb", "figma"], "onlyWithPay": true, "maxItemsPerCompany": 50}'
```

### FAQ

**Does it work with custom-domain careers pages?** Yes, as long as the jobs come from Greenhouse.
Pass the company's domain and the careers-page link is followed; or paste any Greenhouse board URL.

**Why are some companies missing pay?** Pay ranges are published only where the employer opted
into Greenhouse pay transparency (Stripe, for example, does not). Use `onlyWithPay` to keep only
the ones that did.

**Is this affiliated with Greenhouse?** No. This is an independent tool, not affiliated with,
endorsed by or sponsored by Greenhouse Software, Inc. The name only describes which job boards it
reads.

Published by Make No Mistakes LLC. Questions and feature requests: open an issue on this Actor's
Issues tab.

# Actor input Schema

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

Companies whose Greenhouse job boards you want. Accepts company names ("Airbnb"), domains ("stripe.com"), board tokens ("figma") or board URLs ("https://job-boards.greenhouse.io/stripe"), mixed freely. The board token is discovered automatically. A company that is not on Greenhouse comes back as a free company_not_found row naming the ATS it does use. Default: \["airbnb", "figma", "robinhood"].

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

Keep a job when its title, department or team contains any of these words (case-insensitive). Default: empty = every job. Example: \["engineer", "data"].

## `locations` (type: `array`):

Keep a job when any of these strings appears in its location, city, state or country (case-insensitive). Default: empty = every location. Example: \["New York", "London", "US"].

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

Default: false. When true, keep only jobs flagged remote or whose location says remote, anywhere or distributed.

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

Keep only jobs posted (or updated) in the last N days. Default: empty = the whole board. Example: 7.

## `departments` (type: `array`):

Keep a job when any of its Greenhouse departments contains any of these strings (case-insensitive). Unlike keywords, this checks the full department list, including parent departments. Default: empty = every department. Example: \["Engineering", "Product"].

## `offices` (type: `array`):

Keep a job when any of its Greenhouse offices contains any of these strings (case-insensitive). Default: empty = every office. Example: \["San Francisco", "Remote"].

## `onlyWithPay` (type: `boolean`):

Default: false. When true, keep only jobs where the employer published a pay-transparency range on Greenhouse.

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

Default: false. When true, return only jobs this setup has not returned before, so a scheduled run never pays twice for the same posting. State is kept per board in a named key-value store in your own account (see deltaStateName). The first run returns everything and records it. Already-delivered jobs are dropped before they are written and are never charged.

## `deltaStateName` (type: `string`):

Name of the key-value store in your account that remembers delivered jobs. Only used with onlyNewSinceLastRun. Use a different name per independent schedule. Default: "greenhouse-jobs-scraper-delta".

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

Default: true. Set false to drop description_html and description_text, making each item about 10x smaller. The price is the same either way.

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

Maximum jobs returned across all companies, filled in company order. This is also your spend cap: $0.002 per job, so 1,000 jobs = $2.00. Default: 1000. 0 = unlimited.

## `maxItemsPerCompany` (type: `integer`):

Maximum jobs returned per company, so one huge board cannot use up the run. Default: 100. 0 = no per-company cap (a large employer can have several thousand open jobs).

## Actor input object example

```json
{
  "companies": [
    "airbnb",
    "figma",
    "robinhood"
  ],
  "remoteOnly": false,
  "onlyWithPay": false,
  "onlyNewSinceLastRun": false,
  "includeDescription": true,
  "maxItems": 1000,
  "maxItemsPerCompany": 100
}
```

# Actor output Schema

## `jobs` (type: `string`):

One item per open Greenhouse job (record_type = job), plus one free item per input that is not on Greenhouse (record_type = company_not_found).

## `jobsCsv` (type: `string`):

The same items as CSV.

## `runSummary` (type: `string`):

RUN_SUMMARY record: filters used, jobs per company, how each company was resolved, companies not on this platform, delta-mode counts, and whether the run was truncated by a cost limit.

# 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": [
        "airbnb",
        "figma",
        "robinhood"
    ],
    "maxItems": 1000,
    "maxItemsPerCompany": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("make_no_mistakes/greenhouse-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": [
        "airbnb",
        "figma",
        "robinhood",
    ],
    "maxItems": 1000,
    "maxItemsPerCompany": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("make_no_mistakes/greenhouse-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": [
    "airbnb",
    "figma",
    "robinhood"
  ],
  "maxItems": 1000,
  "maxItemsPerCompany": 100
}' |
apify call make_no_mistakes/greenhouse-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,make_no_mistakes/greenhouse-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/EOpXYdec2MwUjFabf/builds/BEvZLcweCL0QTuFJ0/openapi.json
