# Cheapest Greenhouse Scraper with Job Monitoring (`clintsa/greenhouse-job-board-scraper`) Actor

The cheapest Greenhouse ATS scraper with persistent job-change monitoring in our August 19, 2026 Store comparison. Extract roles, descriptions, locations, departments, and apply URLs without browser or default proxy fees. Only $0.25 per 1,000 results plus $0.001 per run.

- **URL**: https://apify.com/clintsa/greenhouse-job-board-scraper.md
- **Developed by:** [Andy Besos](https://apify.com/clintsa) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / 1,000 greenhouse job events

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Scrape live job listings from public **Greenhouse ATS job boards** and turn them into structured recruiting data. This Greenhouse jobs scraper supports multiple companies per run, full job descriptions, location and department filters, API access, and persistent monitoring for new, updated, and removed vacancies.

The Actor calls Greenhouse's public Job Board API directly—no Greenhouse account, API key, browser, or residential proxy is required.

### Why use this Greenhouse jobs scraper?

- Scrape one or hundreds of public Greenhouse company boards in a single run.
- Export job titles, locations, departments, offices, apply URLs, IDs, timestamps, and metadata.
- Include full job descriptions as both original HTML and clean plain text.
- Track newly posted, updated, unchanged, and removed jobs across scheduled runs.
- Filter Greenhouse vacancies by location or department.
- Download results as JSON, CSV, Excel, XML, or RSS through Apify Dataset exports.
- Run from Apify Console, the REST API, JavaScript/Python clients, schedules, webhooks, Make, or Zapier.

The direct HTTP implementation is lightweight and includes retries with exponential backoff for temporary Greenhouse API or rate-limit errors. If one company board fails, the remaining boards continue; the run fails only when every requested board fails.

### Cheapest Greenhouse scraper pricing

The default direct-API mode costs **$0.001 per run plus $0.00025 per job or monitoring event**. There is no browser or proxy charge in the default configuration.

| Results | Actor event price |
| ---: | ---: |
| 1 | $0.00125 |
| 100 | $0.026 |
| 1,000 | $0.251 |
| 10,000 | $2.501 |

In our August 19, 2026 comparison, this was the **cheapest Greenhouse scraper with persistent job-change monitoring** for a 1,000-result run among the first 50 relevant Apify Store results checked. Competitor prices can change, so the exact formula above is included for transparent comparison.

Prices above cover the Actor's chargeable run and dataset events. Standard Apify charges for retaining or downloading data after a run may apply. Enabling the optional Apify Proxy can also add proxy usage costs; direct mode is recommended and enabled by default.

### How to scrape Greenhouse job listings

Add one or more entries to `boards`. Each entry can be:

- A board token such as `airbnb`
- A public board URL such as `https://boards.greenhouse.io/airbnb`
- A modern job-board URL such as `https://job-boards.greenhouse.io/airbnb`
- An individual job URL such as `https://job-boards.greenhouse.io/airbnb/jobs/123`
- A Greenhouse API board URL

The Actor extracts and normalizes the company board token automatically.

#### Quick start: scrape one Greenhouse board

```json
{
  "boards": ["airbnb"],
  "includeContent": true,
  "maxItemsPerBoard": 100
}
```

Set `maxItemsPerBoard` to `0` to return every matching live job. The prefilled example returns one item so the first test stays fast and inexpensive.

#### Scrape multiple company career pages

```json
{
  "boards": [
    "airbnb",
    "https://boards.greenhouse.io/figma",
    "https://job-boards.greenhouse.io/stripe"
  ],
  "includeContent": true,
  "maxItemsPerBoard": 0
}
```

#### Filter Greenhouse jobs by location and department

Filters are case-insensitive substring matches applied to the public Greenhouse fields after a board is fetched.

```json
{
  "boards": ["airbnb", "figma"],
  "locationQuery": "Germany",
  "departmentQuery": "Engineering",
  "includeContent": true,
  "maxItemsPerBoard": 0
}
```

### Monitor new, updated, and removed jobs

Every successful run stores the current active-job snapshot in a named key-value store. Run the Actor on an Apify schedule with the same `monitorId`, boards, and filters to create a Greenhouse job change feed.

```json
{
  "boards": ["airbnb", "figma"],
  "monitorId": "target-companies-daily",
  "onlyChangesSince": "2026-08-01T00:00:00.000Z",
  "includeContent": true,
  "maxItemsPerBoard": 0
}
```

The first run creates a baseline and labels every active vacancy as `new`. Later runs compare the latest public job data with that baseline:

| `changeType` | Meaning |
| --- | --- |
| `new` | The job did not exist in the previous successful snapshot. |
| `updated` | One or more monitored fields changed; `changedFields` lists them. |
| `unchanged` | The job is still active and its monitored data is unchanged. |
| `removed` | A previously active job disappeared from the public board. |

When `onlyChangesSince` is set, unchanged records are excluded. A removal event is emitted once, on the run that first detects the missing job.

Use a different `monitorId` for each independent company list or filter configuration. Mixing different board lists under one monitor ID can make deliberately omitted boards look removed.

### Greenhouse Jobs API example

You can run the scraper from any HTTP client. Replace `YOUR_APIFY_TOKEN` with an Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/clintsa~greenhouse-job-board-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "boards": ["airbnb"],
    "includeContent": true,
    "maxItemsPerBoard": 10
  }'
```

For longer bulk runs, start the Actor asynchronously and fetch items from its default dataset after the run succeeds.

### Input options

| Field | Type | What it controls |
| --- | --- | --- |
| `boards` | string array | Required Greenhouse board tokens, board URLs, or job URLs. |
| `includeContent` | boolean | Adds `descriptionHtml` and `descriptionText`. |
| `locationQuery` | string | Keeps jobs whose location contains the supplied text. |
| `departmentQuery` | string | Keeps jobs whose department contains the supplied text. |
| `maxItemsPerBoard` | integer | Active jobs exported per board; `0` means no limit. |
| `monitorId` | string | Persistent namespace used for change tracking. |
| `onlyChangesSince` | ISO timestamp | Returns only new, updated, and removed events detected since the timestamp. |
| `requestDelayMillis` | integer | Optional delay between company-board requests. |
| `useApifyProxy` | boolean | Enables Apify Proxy as an optional network fallback. |
| `proxyConfiguration` | object | Proxy settings used when `useApifyProxy` is enabled. |

### Greenhouse job data output

One Apify Dataset item is created for every matching active job or removal event. A typical result looks like this:

```json
{
  "boardToken": "airbnb",
  "jobId": 7995199,
  "internalJobId": 7151791,
  "requisitionId": "REQ-123",
  "title": "Software Engineer",
  "location": "Berlin, Germany",
  "departments": ["Engineering"],
  "offices": ["Berlin"],
  "url": "https://job-boards.greenhouse.io/airbnb/jobs/7995199",
  "updatedAt": "2026-08-18T09:30:00Z",
  "metadata": [],
  "sourceUrl": "https://boards-api.greenhouse.io/v1/boards/airbnb/jobs",
  "scrapedAt": "2026-08-19T10:38:56.000Z",
  "descriptionHtml": "<p>Build products used around the world.</p>",
  "descriptionText": "Build products used around the world.",
  "changeType": "new",
  "changeDetectedAt": "2026-08-19T10:38:56.000Z",
  "firstSeenAt": "2026-08-19T10:38:56.000Z",
  "lastSeenAt": "2026-08-19T10:38:56.000Z"
}
```

The run also writes a `SUMMARY` record containing requested, successful, and failed board counts; exported job count; change totals; proxy usage; and completion time.

### Greenhouse scraper use cases

- Build or refresh a job board with current Greenhouse vacancies.
- Monitor competitor hiring and headcount signals.
- Create recruiting, sales, or investment-intelligence feeds.
- Detect new roles for alerts and workflow automations.
- Track removed job postings and hiring changes over time.
- Analyze hiring by company, location, office, or department.
- Supply structured live job data to AI agents and data pipelines.

### FAQ

#### Is this the cheapest Greenhouse jobs scraper with monitoring?

Yes in our August 19, 2026 Store comparison: its $0.251 listed Actor event price for a 1,000-result run was the lowest among relevant results checked that also advertised persistent new, updated, and removed job monitoring. Because marketplace prices change, use the exact formula—$0.001 per run plus $0.00025 per result—for future comparisons.

The low price is possible because the Actor calls Greenhouse's public API directly with 256 MB memory. It does not launch a browser or use a proxy by default.

#### Does Greenhouse have a public jobs API?

Greenhouse exposes published job-board data through its public Job Board API. This Actor handles board URL parsing, multi-company runs, retries, normalized datasets, exports, and change monitoring around that API.

#### Do I need a Greenhouse API key?

No. The Actor reads only publicly published Greenhouse job-board data. Private candidates, applications, scorecards, and employer account data are not accessible.

#### Can I scrape several Greenhouse companies at once?

Yes. Add multiple board tokens or URLs to `boards`. Results retain `boardToken`, so each job can be attributed to its company board.

#### Can this Actor detect deleted or closed jobs?

It detects a removal when a vacancy present in the previous snapshot is absent from the next successful run using the same `monitorId`. This means the job is no longer published on that board; it does not reveal the employer's internal reason.

#### Does the Greenhouse scraper require a proxy?

Usually not. It calls the public API directly. Apify Proxy is available as an explicit fallback but remains disabled by default.

#### Why did a board return no data?

Check that the company actually uses a public Greenhouse job board and that its token is correct. A branded careers page may redirect to Greenhouse while hiding the token in a `for` query parameter; you can paste that full Greenhouse URL and let the Actor normalize it.

### Limitations and responsible use

- Only publicly published Greenhouse Job Board API data is returned.
- Output completeness depends on what each employer exposes publicly.
- Location and department filters match Greenhouse's published text; they do not infer geography or job taxonomy.
- Job removal is an observed board-state change, not proof that a position was filled.
- Respect applicable laws and the terms governing how you use exported data.

### Local development

```bash
npm install
mkdir -p storage/key_value_stores/default
printf '{"boards":["airbnb"],"maxItemsPerBoard":1}' > storage/key_value_stores/default/INPUT.json
npm start
```

Run the unit tests with `npm test`. Deploy from this directory with `apify push`; keep access tokens outside the source code.

# Actor input Schema

## `boards` (type: `array`):

Required. Add one entry per company. Accepted formats include `airbnb`, `https://boards.greenhouse.io/airbnb`, and an individual URL such as `https://job-boards.greenhouse.io/airbnb/jobs/123`. URLs are converted to board tokens automatically.

## `includeContent` (type: `boolean`):

Return each description as both `descriptionHtml` and clean `descriptionText`. Leave disabled for smaller and faster datasets.

## `locationQuery` (type: `string`):

Optional case-insensitive substring, for example `Germany`, `Berlin`, or `Remote`. Jobs whose public location does not contain this text are excluded.

## `departmentQuery` (type: `string`):

Optional case-insensitive substring, for example `Engineering`, `Sales`, or `Marketing`.

## `maxItemsPerBoard` (type: `integer`):

Limit the number of active matching jobs returned for each company. Set to `0` for every matching job. The prefilled health-check input returns one job.

## `monitorId` (type: `string`):

Persistent namespace for job-change tracking. Keep the same value for the same boards and filters. Use another value for an independent monitor or schedule.

## `onlyChangesSince` (type: `string`):

Optional ISO 8601 timestamp such as `2026-08-01T00:00:00.000Z`. When set, the dataset contains only jobs detected as new, updated, or removed since that time. The first run creates the baseline.

## `requestDelayMillis` (type: `integer`):

Optional delay between company requests. Usually unnecessary because the Actor already retries temporary Greenhouse API errors with backoff.

## `useApifyProxy` (type: `boolean`):

Greenhouse's public API normally works without a proxy. Enable this only as a network fallback.

## `proxyConfiguration` (type: `object`):

Optional proxy configuration used only when `useApifyProxy` is enabled.

## `startUrls` (type: `array`):

Optional compatibility alias. Entries are normalized and combined with `boards`; new integrations should use `boards`.

## Actor input object example

```json
{
  "boards": [
    "airbnb"
  ],
  "includeContent": false,
  "maxItemsPerBoard": 1,
  "monitorId": "default",
  "requestDelayMillis": 0,
  "useApifyProxy": false
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "boards": [
        "airbnb"
    ],
    "maxItemsPerBoard": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("clintsa/greenhouse-job-board-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 = {
    "boards": ["airbnb"],
    "maxItemsPerBoard": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("clintsa/greenhouse-job-board-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 '{
  "boards": [
    "airbnb"
  ],
  "maxItemsPerBoard": 1
}' |
apify call clintsa/greenhouse-job-board-scraper --silent --output-dataset

```

## MCP server setup

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