# Greenhouse Jobs Scraper & Monitor (`cliqtomedia/greenhouse-jobs-monitor-scraper`) Actor

Greenhouse jobs scraper for known public boards with snapshots, exact details and explicit change monitoring.

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

## Pricing

from $0.19 / 1,000 greenhouse job results

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 & Monitor

This Greenhouse jobs scraper reads public boards you already know. Export a
current snapshot, fetch exact job details, or compare two snapshots to find
changes.

The Actor calls public Greenhouse Job Board GET endpoints. It needs no
Greenhouse account, browser, or proxy. It never submits job applications.

### Quick start

This input reads one public board without job descriptions:

```json
{
  "mode": "snapshot",
  "boards": ["figma"],
  "includeContent": false,
  "maxJobsPerBoard": 500,
  "maxJobsTotal": 500
}
```

You can use a raw board token or a supported Greenhouse board URL:

```json
{
  "mode": "snapshot",
  "boards": [
    "airbnb",
    "https://job-boards.greenhouse.io/figma",
    "https://job-boards.eu.greenhouse.io/proton"
  ],
  "includeContent": true,
  "titleKeywords": ["engineer"],
  "locations": ["remote"]
}
```

Filters are case-insensitive. Filters run before output limits. A board that
hits a limit is marked partial, so it cannot produce false removal events.

### Fetch exact job details

Use the board token and numeric Greenhouse job-post ID:

```json
{
  "mode": "details",
  "jobs": ["airbnb/1234567"],
  "includeContent": true,
  "includeQuestions": true,
  "includePayTransparency": true
}
```

Questions and pay ranges are optional. Each option adds one detail request for
each relevant job. Values appear only when the employer exposes them.

### Monitor job changes

First, create a snapshot:

```json
{
  "mode": "monitor",
  "boards": ["proton"]
}
```

The run saves `SNAPSHOT` in its default key-value store. It reports that store
ID in `RUN_SUMMARY.currentSnapshotKeyValueStoreId`.

Pass the store ID to a later run:

```json
{
  "mode": "monitor",
  "boards": ["proton"],
  "baselineKeyValueStoreId": "PRIOR_RUN_KVS_ID",
  "monitorOutput": "changes_only"
}
```

The Actor never changes the prior store. Several runs can compare against the
same snapshot. Set `monitorOutput` to `all` to include unchanged jobs.

Monitor rows can be `baseline`, `new`, `updated`, `unchanged`, or `removed`.
A removal appears only when both board snapshots are complete and compatible.
The removal time is when the absence was observed, not an employer closure
time.

An inaccessible, expired, incompatible, or damaged baseline fails closed. The
Actor does not invent changes or silently create a replacement baseline.

### Output

Each Dataset item is one current job or one verified removal tombstone. Its
stable ID is `{lowercaseBoardToken}:{greenhouseJobPostId}`.

Important fields include:

- source job, internal and requisition IDs;
- title, location, departments and offices;
- source and Greenhouse URLs;
- first-published and updated timestamps;
- optional HTML plus separate plain text;
- optional public questions and structured pay ranges;
- change status, changed fields and versioned hashes;
- source request evidence.

Example:

```json
{
  "schemaVersion": 1,
  "recordType": "job",
  "stableId": "exampleco:1234567",
  "boardToken": "exampleco",
  "jobId": "1234567",
  "title": "Software Engineer",
  "location": { "name": "Remote" },
  "changeStatus": null,
  "changedFields": [],
  "updatedAt": "2026-09-10T09:30:00.000Z",
  "absoluteUrl": "https://example.invalid/jobs/1234567"
}
```

The default key-value store contains two records:

- `RUN_SUMMARY` explains coverage, limits, retries, output, baseline and charge
  counts for every input.
- `SNAPSHOT` contains versioned state for a later monitor run.

Always inspect `RUN_SUMMARY`. A successful platform status alone does not prove
that every source input was complete.

### How charging works

Apify charges USD 0.001 once after valid input is accepted. Each useful job or
verified monitoring change saved to Dataset has one `job-result` charge.

The row price depends on your Apify plan:

- FREE: USD 0.000240;
- BRONZE: USD 0.000230;
- SILVER: USD 0.000210;
- GOLD, PLATINUM and DIAMOND: USD 0.000190.

Empty boards, failed inputs and rows that are not saved have no row charge.

### Outcomes and retries

Each input ends as `COMPLETE`, `EMPTY`, `NOT_FOUND`, `PARTIAL`, `DRIFTED`,
`FAILED`, or `UNPROCESSED`.

- `EMPTY` and `NOT_FOUND` are valid source outcomes.
- `PARTIAL` means a limit or detail problem left work incomplete.
- `DRIFTED` means the source response no longer matches the supported shape.
- `FAILED` means a technical request failed after bounded retries.
- `UNPROCESSED` means a run-wide stop left the input untouched.

The Actor tries network, 408, 429, and 5xx failures at most three times. Do not
loop on invalid input, 404, source drift, or a damaged baseline.

For support, send the Apify run ID, UTC time, redacted input and `RUN_SUMMARY`.
Never send tokens, cookies, authorization headers, or application answers.

### Limits

- Up to 100 boards per snapshot or monitor run.
- Up to 5,000 matching jobs per board.
- Up to 10,000 matching jobs per run.
- Up to 500 exact jobs in details mode.
- Four boards and eight detail requests can run concurrently.
- Description responses are capped at 64 MiB per board.
- Detail responses are capped at 2 MiB each.

These bounds keep runs predictable. The Actor marks omitted work instead of
claiming more coverage than it observed.

### Limitations

- You must already know each board token or URL.
- This is not a global Greenhouse company index.
- Other applicant tracking systems are not supported.
- Greenhouse can remove a posting without a reason or closure time.
- Source changes, access limits, and network failures can make a run partial.
- You are responsible for lawful downstream retention and republication.

Greenhouse is a trademark of its owner. This project is not affiliated with or
endorsed by Greenhouse Software, Inc.

# Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/greenhouse-jobs-monitor-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

Snapshot lists current jobs; details fetches exact board/job pairs; monitor compares an explicit prior KVS snapshot.

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

For snapshot/monitor. Accepts up to 100 tokens or current/legacy US/EU Greenhouse board URLs.

## `jobs` (type: `array`):

For details mode. Use token/numeric-ID or an allowed Greenhouse job URL.

## `baselineKeyValueStoreId` (type: `string`):

Monitor only. Read SNAPSHOT from a prior run; the prior store is never modified.

## `monitorOutput` (type: `string`):

Emit only changes by default, or include unchanged comparable jobs as well.

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

Adds HTML and normalized text and increases response size.

## `includeQuestions` (type: `boolean`):

Adds one detail request per job; no answers or applications are submitted.

## `includePayTransparency` (type: `boolean`):

Adds one detail request per job; values exist only when the employer exposes them.

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

Keep jobs whose title contains at least one case-insensitive keyword.

## `contentKeywords` (type: `array`):

Keep jobs whose description contains at least one case-insensitive keyword.

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

Keep jobs matching at least one case-insensitive location substring.

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

Keep jobs matching at least one case-insensitive department substring.

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

Keep jobs matching at least one case-insensitive office substring.

## `firstPublishedAfter` (type: `string`):

ISO date or instant, inclusive.

## `updatedAfter` (type: `string`):

ISO date or instant, inclusive.

## `maxJobsPerBoard` (type: `integer`):

Stop output after this many matching jobs per board and report the board as partial.

## `maxJobsTotal` (type: `integer`):

Stop output after this many matching jobs across the run and report omitted work.

## Actor input object example

```json
{
  "mode": "snapshot",
  "monitorOutput": "changes_only",
  "includeContent": false,
  "includeQuestions": false,
  "includePayTransparency": false,
  "maxJobsPerBoard": 5000,
  "maxJobsTotal": 10000
}
```

# Actor output Schema

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

No description

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

No description

## `snapshot` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/greenhouse-jobs-monitor-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/greenhouse-jobs-monitor-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 '{}' |
apify call cliqtomedia/greenhouse-jobs-monitor-scraper --silent --output-dataset

```

## MCP server setup

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