# Greenhouse Jobs Scraper (`parsebird/greenhouse-jobs-scraper`) Actor

Search live job postings across 140+ companies on Greenhouse. Filter by title, location, remote/hybrid/onsite, salary, experience level, and company.

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

## Pricing

from $0.49 / 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/platform/actors/running/actors-in-store#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

### Greenhouse Jobs Scraper

Search live job postings across 140+ companies that hire through [Greenhouse](https://www.greenhouse.io/), one of the most widely used applicant tracking systems (ATS) in tech. Filter by job title, location, work model, salary, experience level, and company, and get clean, structured job data ready for analysis or integration.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Query a curated list of 140+ active Greenhouse company boards by keyword, location, work model, employment type, experience level, salary range, and posting date — no ATS API keys or per-company setup required.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Apify Actor: parsebird/greenhouse-jobs-scraper. Scrapes live job postings from 140+ companies on Greenhouse (job-boards.greenhouse.io). Call via ApifyClient: client.actor("parsebird/greenhouse-jobs-scraper").call(run_input={"queries": ["Software Engineer"], "work_models": ["remote"], "page_size": 50}). Key inputs: queries (array, max 5, "-term" excludes), locations, work_models (remote/hybrid/onsite), employment_types, experience_levels, skills_include/skills_exclude (description keyword search), companies_include/companies_exclude, min_salary_usd/max_salary_usd, posted_after/posted_before (ISO date or "7 days ago"), page, page_size (max 100), include_company_details. Returns per job: title, normalized_title, company (name, board_token), locations (city/region/country), compensation (min/max/currency/period), employment_type, workplace_type, experience_level, responsibilities, benefits, description, listing_url, apply_url, date_posted, updated_at, source. Full API spec: https://apify.com/parsebird/greenhouse-jobs-scraper/api. Get your token: https://console.apify.com/settings/integrations.
```

### What does Greenhouse Jobs Scraper do?

Greenhouse doesn't offer a single search endpoint that covers every company that uses it — each employer runs its own isolated job board. This actor solves that by maintaining a curated list of 140+ active Greenhouse company boards (Anthropic, Stripe, Databricks, Airbnb, Coinbase, Figma, Cloudflare, Roblox, SpaceX, and more) and querying all of them for you, so you can search across companies the way you'd search a single job board.

- 🔍 **Keyword search** — match job titles and descriptions, with `-term` exclusions
- 📍 **Location & work model filters** — remote, hybrid, onsite, plus city/region/country
- 💰 **Salary filtering** — parsed directly from disclosed compensation ranges in the posting text, normalized to annual USD
- 🏢 **Company allow/deny lists** — target specific employers or exclude them
- 🎯 **Skill keyword matching** — filter by terms mentioned in the job description
- 📅 **Freshness filters** — `posted_after` / `posted_before`, ISO dates or relative ("7 days ago")

Every field is derived from the same public data Greenhouse's own job board pages show — nothing is invented or estimated with AI. Employment type, workplace type, and experience level are classified with transparent keyword rules (documented below), not a black-box model, so you always know why a job was tagged the way it was.

### What data can you extract from Greenhouse job postings?

| Field | Description |
|-------|-------------|
| `title` / `normalized_title` | Raw posting title and a lightly cleaned version (trailing tags like "(Remote)" stripped) |
| `company` | `name` and `board_token`; with `include_company_details` also `total_open_positions`, `departments`, `offices`, `careers_url` |
| `locations` | Raw location text plus a best-effort `city` / `region` / `country` split |
| `compensation` | `{min, max, currency, period}` parsed from the posting text when the employer discloses a range, else `null` |
| `employment_type` | full-time / part-time / contract / internship / freelance / temporary, from title keywords |
| `workplace_type` | remote / hybrid / onsite, from the location string and posting text |
| `experience_level` | intern / entry / mid / senior / lead / executive, from title keywords |
| `responsibilities` / `benefits` | Bullet lists extracted from the posting's own `<ul>` sections when a matching heading is found |
| `description` | Full job description, HTML stripped |
| `listing_url` / `apply_url` | Canonical Greenhouse listing link |
| `date_posted` / `updated_at` | Employer's original posting date and last-updated timestamp |
| `source` | Always `"greenhouse"` |

### How to use Greenhouse Jobs Scraper

1. Open the actor's **Input** tab on [Apify Console](https://console.apify.com).
2. Enter up to 5 `queries` (job titles or keywords) — leave empty to browse everything.
3. Optionally narrow by `locations`, `work_models`, `employment_types`, `experience_levels`, `companies_include`/`companies_exclude`, `skills_include`/`skills_exclude`, or a salary range.
4. Set `page_size` (up to 100) and `page` to page through results, sorted newest-first by posting date.
5. Click **Start** and download results as JSON, CSV, or Excel — or pull them via the [Apify API](https://docs.apify.com/api/v2) or [Python](https://docs.apify.com/api/client/python/)/[JavaScript](https://docs.apify.com/api/client/js/) client.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/greenhouse-jobs-scraper").call(run_input={
    "queries": ["Software Engineer"],
    "work_models": ["remote"],
    "min_salary_usd": 150000,
    "page_size": 50,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"]["name"], job["compensation"])
```

#### JavaScript

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('parsebird/greenhouse-jobs-scraper').call({
    queries: ['Software Engineer'],
    work_models: ['remote'],
    min_salary_usd: 150000,
    page_size: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((job) => job.title));
```

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `queries` | array (≤5) | No | `[]` | Job titles/keywords, OR'ed. `-term` excludes |
| `locations` | array | No | `[]` | City, region, or country substrings |
| `work_models` | array | No | all | `remote`, `hybrid`, `onsite` |
| `employment_types` | array | No | all | `full-time`, `part-time`, `contract`, `internship`, `freelance`, `temporary` |
| `experience_levels` | array | No | all | `intern`, `entry`, `mid`, `senior`, `lead`, `executive` |
| `skills_include` / `skills_exclude` | array | No | `[]` | Keyword match against the job description |
| `companies_include` / `companies_exclude` | array | No | `[]` | Case-insensitive company name match |
| `min_salary_usd` / `max_salary_usd` | integer | No | — | Annual USD bounds; jobs without a disclosed salary are excluded when set |
| `posted_after` / `posted_before` | string | No | — | ISO 8601 (`2026-01-01`) or relative (`"7 days ago"`) |
| `page` | integer | No | `1` | Page number (1–100) |
| `page_size` | integer | No | `50` | Results per page (1–100) |
| `include_company_details` | boolean | No | `false` | Attach aggregated company profile (open positions, departments, offices) |

### Output example

```json
{
  "id": "acme-4309998",
  "title": "Senior Software Engineer, Backend",
  "normalized_title": "Senior Software Engineer, Backend",
  "company": {
    "name": "Acme Corp",
    "board_token": "acme"
  },
  "locations": [
    { "location": "San Francisco, CA", "city": "San Francisco", "region": "CA", "country": "United States" }
  ],
  "compensation": { "min": 160000.0, "max": 220000.0, "currency": "USD", "period": "yearly" },
  "employment_type": "full-time",
  "workplace_type": "remote",
  "experience_level": "senior",
  "responsibilities": [
    "Design and build backend services powering the core platform",
    "Partner with product and design on new features"
  ],
  "benefits": [
    "Comprehensive health, dental, and vision coverage",
    "Flexible PTO"
  ],
  "description": "We are looking for a senior backend engineer to join our Platform team...",
  "listing_url": "https://job-boards.greenhouse.io/acme/jobs/4309998",
  "apply_url": "https://job-boards.greenhouse.io/acme/jobs/4309998",
  "date_posted": "2026-08-09T13:47:14-04:00",
  "updated_at": "2026-08-09T13:47:14-04:00",
  "source": "greenhouse"
}
```

### Use cases

- **Job search** — Monitor new openings matching your title, salary, and location criteria across dozens of companies at once.
- **Recruiting & sourcing** — Track competitor hiring activity and open headcount by department.
- **Compensation research** — Collect disclosed salary ranges across roles, seniority levels, and companies for benchmarking.
- **Market research** — Analyze hiring trends and in-demand skills across the tech industry.
- **ATS/HR tooling** — Feed structured job data into an internal dashboard, job board, or alerting pipeline via the [Apify API](https://docs.apify.com/api/v2), scheduled runs, or [integrations](https://apify.com/integrations) (Zapier, Make, Slack, Google Sheets).

### How it works

1. **Company crawl** — The actor queries the public [Greenhouse Job Board API](https://developers.greenhouse.io/job-board.html) (`boards-api.greenhouse.io`) for each of the 140+ tracked company boards, concurrently.
2. **Filtering** — Each posting is checked against your `queries`, `locations`, `work_models`, `employment_types`, `experience_levels`, salary bounds, skill keywords, and company filters. Raw per-company data is processed and discarded immediately, so memory use stays low regardless of how many companies are scanned.
3. **Classification** — Employment type, workplace type, and experience level are derived from the title and location using transparent keyword rules. Compensation and responsibility/benefit bullet lists are parsed directly from the posting's own text and HTML structure.
4. **Pagination** — Matches are sorted by posting date (newest first) and sliced according to `page` / `page_size`.
5. **Output** — Results are pushed to the Apify dataset for download in JSON, CSV, or Excel, or via the API.

### How much does it cost to scrape Greenhouse job postings?

| Plan | Price per event | Price per 1,000 |
|------|-----------------|-------------------|
| Free | $0.00199 | **$1.99** |
| Bronze | $0.00149 | **$1.49** |
| Silver | $0.00099 | **$0.99** |
| Gold | $0.00049 | **$0.49** |

One `jobs-scraped` event is charged per job pushed to the dataset. A run returning 200 jobs costs about $0.40 on the Free tier, down to about $0.10 on Gold. Every new Apify account gets free trial credits, so you can test this actor before committing to a paid plan.

### FAQ

**Does this cover every company on Greenhouse?**
No. Greenhouse has no cross-company search API, so this actor maintains a curated list of 140+ verified, currently active company boards. It's not exhaustive — see "How do I add a company?" below.

**How do I add a company that isn't tracked?**
Every board is identified by its Greenhouse token (the slug in `job-boards.greenhouse.io/<token>`). If a company you need isn't covered, open an issue on the actor's Issues tab with the token and it can be added to the list.

**Why is `compensation` `null` for some jobs?**
Only jobs where the employer discloses a salary range in the posting text (common in California, Colorado, New York, and Washington due to pay-transparency laws) have parsed compensation. Fewer than half of all postings disclose a range.

**Why are `responsibilities` or `benefits` sometimes empty?**
They're extracted from `<ul>` lists in the posting that sit under a matching heading (e.g. "What You'll Do", "Benefits"). Postings that use plain paragraphs instead of bullet lists, or non-standard headings, won't have bullets extracted — the field is left empty rather than guessed.

**How are `employment_type`, `workplace_type`, and `experience_level` determined?**
By keyword rules against the job title (and location, for workplace type) — for example, a title containing "Senior" is tagged `senior`; a location containing "Remote" is tagged `remote`. These are not AI predictions, so you can rely on them being consistent and explainable.

**Can I schedule recurring runs?**
Yes — use [Apify's Scheduler](https://docs.apify.com/platform/schedules) to run this actor daily or weekly and monitor new postings automatically, or trigger it via [webhooks](https://docs.apify.com/platform/integrations/webhooks) and the [API](https://docs.apify.com/api/v2).

**What ATS platforms does ParseBird cover besides Greenhouse?**
See [Hiring.cafe Jobs Scraper](https://apify.com/parsebird/hiring-cafe-scraper) for an aggregator covering 46+ ATS platforms, or [Workable Job Scraper](https://apify.com/parsebird/workable-job-scraper) and [Workday Jobs Scraper](https://apify.com/parsebird/workday-jobs-scraper) for other individual ATS platforms.

### Legal and compliance

This actor accesses only publicly available data from Greenhouse's public Job Board API, which is designed for exactly this kind of programmatic access. It does not bypass login walls, access private accounts, or collect personal candidate data. The data collected consists of job postings that companies have intentionally published for public recruitment. Users are responsible for ensuring their use of the collected data complies with applicable laws and each employer's terms of service. See Apify's [guide on the legality of web scraping](https://apify.com/legal/is-web-scraping-legal) for more.

### Related actors

- [Hiring.cafe Jobs Scraper](https://apify.com/parsebird/hiring-cafe-scraper) — job aggregator covering 46+ ATS platforms
- [Workable Job Scraper](https://apify.com/parsebird/workable-job-scraper) — jobs from companies using Workable
- [Workday Jobs Scraper](https://apify.com/parsebird/workday-jobs-scraper) — jobs from companies using Workday

# Actor input Schema

## `queries` (type: `array`):

Up to 5 job titles or keywords, matched against the title and description (OR'ed). Prefix a term with "-" to exclude it, e.g. "-staff".

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

Cities, regions, or countries to filter by. Matched against each posting's raw location text (e.g. "San Francisco", "New York", "Remote").

## `work_models` (type: `array`):

Filter by remote, hybrid, or onsite. Leave empty to include all.

## `employment_types` (type: `array`):

Filter by employment type. Leave empty to include all.

## `experience_levels` (type: `array`):

Filter by seniority, classified from the job title. Leave empty to include all.

## `skills_include` (type: `array`):

Only keep jobs whose description mentions at least one of these terms (case-insensitive keyword search).

## `skills_exclude` (type: `array`):

Drop jobs whose description mentions any of these terms.

## `companies_include` (type: `array`):

Only keep jobs from these companies (case-insensitive match against the company name reported by Greenhouse). Only companies in this actor's tracked list (see README) can be found.

## `companies_exclude` (type: `array`):

Drop jobs from these companies.

## `min_salary_usd` (type: `integer`):

Lower bound on annualized USD compensation. Compensation is parsed from the job description when the employer discloses a range; jobs without a disclosed salary are excluded when this is set.

## `max_salary_usd` (type: `integer`):

Upper bound on annualized USD compensation. Jobs without a disclosed salary are excluded when this is set.

## `posted_after` (type: `string`):

Only keep jobs posted on or after this date. ISO 8601 (e.g. 2026-01-01) or relative (e.g. "7 days ago").

## `posted_before` (type: `string`):

Only keep jobs posted on or before this date. ISO 8601 or relative, same format as Posted after.

## `page` (type: `integer`):

Page number of results (1-100). Results are sorted by posting date, newest first.

## `page_size` (type: `integer`):

Results per page (1-100).

## `include_company_details` (type: `boolean`):

Attach an aggregated company profile (open position count, departments, offices) to each job.

## Actor input object example

```json
{
  "queries": [
    "Software Engineer"
  ],
  "locations": [],
  "work_models": [],
  "employment_types": [],
  "experience_levels": [],
  "skills_include": [],
  "skills_exclude": [],
  "companies_include": [],
  "companies_exclude": [],
  "posted_after": "",
  "posted_before": "",
  "page": 1,
  "page_size": 20,
  "include_company_details": false
}
```

# Actor output Schema

## `dataset` (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 = {
    "queries": [
        "Software Engineer"
    ],
    "locations": [],
    "page": 1,
    "page_size": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/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 = {
    "queries": ["Software Engineer"],
    "locations": [],
    "page": 1,
    "page_size": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/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 '{
  "queries": [
    "Software Engineer"
  ],
  "locations": [],
  "page": 1,
  "page_size": 20
}' |
apify call parsebird/greenhouse-jobs-scraper --silent --output-dataset

```

## MCP server setup

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