# 🌱 Greenhouse Job Scraper (`scraper-engine/greenhouse-job-scraper`) Actor

Greenhouse Job Scraper extracts public job listings, including titles, companies, locations, departments, descriptions, employment types, and application URLs. Build structured datasets for job market research, recruitment, hiring analysis, and career opportunity discovery.

- **URL**: https://apify.com/scraper-engine/greenhouse-job-scraper.md
- **Developed by:** [Scraper Engine](https://apify.com/scraper-engine) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### Greenhouse Job Scraper — Titles, Descriptions and Locations

Greenhouse Job Scraper pulls every open job posting from any Greenhouse-hosted career page — job title, full description, department, office and remote locations, and the posting link — and writes each one to a structured JSON dataset in real time as it's found. No Greenhouse login, API key, or browser automation is required. Paste one board URL or a hundred, start the run below, and watch results land in the **Output** tab as they're scraped.

### What is Greenhouse Job Scraper?

Greenhouse Job Scraper is an Apify Actor that fetches open job postings from one or more Greenhouse-hosted career pages and normalizes them into a consistent JSON schema. It reads directly from Greenhouse's own public, unauthenticated job-board endpoint — no Greenhouse account, recruiter login, or API key is needed to run it. It's built for recruiters, talent-market researchers, HR-tech and ATS developers, and AI agents that need a structured, machine-readable feed of hiring data instead of scraping career-page HTML by hand.

### What Greenhouse job data is publicly available to scrape?

Every hosted job board Greenhouse serves at `job-boards.greenhouse.io` or `boards.greenhouse.io` is public by design — companies publish it so candidates can find and apply to open roles without logging in.

| Data category | Publicly available | Restricted (Greenhouse Recruiting login) |
| --- | --- | --- |
| Job title, description, department | Yes | — |
| Office and remote locations | Yes | — |
| Posting and apply links | Yes | — |
| First-published date | Yes | — |
| Employment type (full-time, contract, etc.) | Only if the company writes it into the description text | Not exposed as a structured field by Greenhouse's public API |
| Compensation figures | Only if included in the description text | Not a structured field on the public API |
| Applicant submissions, resumes, scorecards | No | Restricted to the hiring team logged into Greenhouse Recruiting |
| Draft or unpublished postings | No | Restricted until the company publishes them |

Greenhouse Job Scraper only returns publicly visible data — what any visitor sees. Nothing behind a login wall.

### What data can I extract with Greenhouse Job Scraper?

Greenhouse Job Scraper returns one JSON record per open job posting, covering the posting's own content plus identifiers that make sense of multi-company runs.

| Field name | Description |
| --- | --- |
| `id` | Greenhouse's internal numeric job ID |
| `type` | Employment type as published on the board (see note below) |
| `title` | The job posting's title |
| `description` | Full job description as clean plain text, HTML tags stripped |
| `locations` | One or more office/remote locations for this job |
| `department` | Department(s) this job belongs to, semicolon-joined if more than one |
| `postingUrl` | Public link to the job posting |
| `applyUrl` | Link to apply for the job |
| `publishedAt` | UTC timestamp the job was first published |
| `companySlug` | The Greenhouse board token this job was scraped from |
| `scrapedAt` | UTC timestamp this actor run collected the record |

#### Job details

`title`, `description`, `department`, `locations`, `type`, `postingUrl`, and `applyUrl` describe the posting itself — what the role is, where it's based, and where to read or apply for it.

⚠️ `type` is not sourced per job — Greenhouse's public boards API does not expose a structured employment-type field on any board it was checked against, so this field always returns the fixed value `"Full-time"`. Treat it as informational only, not a scraped fact.

#### Identifiers and tracking

`id`, `publishedAt`, `companySlug`, and `scrapedAt` identify the record and the run that collected it — `companySlug` is what lets you tell rows from different companies apart in a multi-board run, and `publishedAt`/`scrapedAt` let you track how fresh a posting is.

#### 🤖 Add-on: Need additional Greenhouse data?

If a run turns up companies hiring on other applicant-tracking systems, Ats Jobs API covers Greenhouse, Lever, Ashby, Workable, and SmartRecruiters boards in one Actor. Once you know which companies and departments are hiring, LinkedIn People Profile Scraper can help source candidates for those open roles.

### Why not build this yourself?

Greenhouse's job-board data sits behind a public, unauthenticated JSON endpoint (`boards-api.greenhouse.io`), so calling it directly looks simple — until you hit the parts this actor already solves. Job board links come in at least five different URL shapes (`job-boards.greenhouse.io`, `boards.greenhouse.io`, an `/embed/job_board?for=` link, a `?gh_jid=` deep link, or a company's own custom-domain careers page), and resolving a custom domain to its underlying board token means fetching the page and reading a canonical `<link>` or embed tag out of the HTML — logic you'd have to write and maintain yourself. Greenhouse also isn't guaranteed to accept every request: this actor watches for HTTP 403/429 blocks and 5xx errors and walks a fixed proxy ladder (direct → Datacenter → Residential) to work around them, which means provisioning and rotating your own proxies if you build it from scratch. On top of that, you'd need to write the multi-board deduplication, concurrency control, and live dataset output yourself.

### How to use Greenhouse Job Scraper

Greenhouse Job Scraper runs on the Apify platform — there's no separate signup or API key beyond an Apify account.

1. Open **Greenhouse Job Scraper** in Apify Console under **Actors**.
2. Provide the required `urls` input — at least one Greenhouse job board URL.
3. Leave `proxyConfiguration` on its default (`useApifyProxy: true`), or adjust the country/group if you have a reason to.
4. Click **Start**.
5. Open the **Output** tab — results stream in live — or the **Storage → Dataset** tab once the run finishes, and export as JSON or CSV.

#### How to scale to bulk job extraction

`urls` is an array (`stringList` editor) with `minItems: 1` and no declared maximum — paste as many board URLs as you like, one per line, in a single run. Each unique board token is fetched only once and cached even if it's referenced by more than one URL in the list, and up to 5 boards are fetched concurrently (a fixed internal value, not exposed in the input).

### What can you do with Greenhouse job posting data?

- A talent-market researcher tracking competitor hiring uses `department` and `locations` across several `companySlug` values to see where competitors are opening new offices or remote roles.
- A recruiter building a sourcing shortlist uses `title` and `description` to match open roles against a candidate's skill set before reaching out.
- A go-to-market team selling HR or recruiting tools uses `companySlug` and `department` to find companies actively scaling a specific team as warm outbound leads.
- An operations analyst monitoring hiring velocity charts `publishedAt` over time per `companySlug` to see when and how fast a company is adding headcount.
- An AI recruiting agent or RAG pipeline ingests `title`, `description`, and `department` as retrieval context so a chatbot can answer candidate questions about open roles without manual re-entry.

### How does Greenhouse Job Scraper handle rate limits and blocking?

Every request starts on a direct connection — no proxy, no browser rendering, just an HTTP client (`impit`) that impersonates a Chrome browser fingerprint against Greenhouse's own JSON endpoint. If Greenhouse responds with a block (HTTP 403 or 429) or a 5xx server error, the actor escalates one rung on a fixed ladder: NONE → DATACENTER → RESIDENTIAL. NONE and DATACENTER each get exactly one attempt before escalating; once on RESIDENTIAL, a blocked request is retried up to 3 times with backoff before that single request is given up on. The ladder is global and never steps back down for the rest of the run — once any request reaches RESIDENTIAL, every later request in that run starts on RESIDENTIAL too.

⚠️ If a request is still blocked after exhausting the RESIDENTIAL retry budget, that one board or URL is logged as failed and skipped — it does not stop the run. Every other board URL in the same run is processed independently, and the final log line reports how many boards succeeded versus failed.

### ⬇️ Input

Greenhouse Job Scraper takes two input fields — one that does the work, and one safety net that most runs never need to touch.

| Parameter | Required | Type | Description | Example value |
| --- | --- | --- | --- | --- |
| `urls` | Yes | array of strings | One or more Greenhouse job board URLs — any supported URL shape, one per line. `minItems: 1`. | `["https://job-boards.greenhouse.io/webflow"]` |
| `proxyConfiguration` | Yes | object | Apify Proxy configuration, used only if a request is ever blocked and the ladder escalates. Defaults to Apify Proxy enabled. | `{ "useApifyProxy": true }` |

#### Example input

```json
{
  "urls": [
    "https://job-boards.greenhouse.io/webflow"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

### ⬆️ Output

Each open job posting is pushed to the dataset as one typed JSON record, with the same field names on every run regardless of which board it came from. Every Apify dataset can be exported as JSON, CSV, Excel, XML, RSS, or HTML from the **Storage → Dataset** tab, and the Console offers three built-in views — **Overview**, **Full details**, and **By company** — for skimming results without re-exporting. A per-run `RUN_SUMMARY` record (board URLs requested, boards succeeded/failed, jobs collected, HTTP requests made, and the final proxy tier) is also saved to the key-value store and linked from the **Output** tab.

#### Example output

```json
{
  "id": 8122601,
  "type": "Full-time",
  "title": "Senior Site Reliability Engineer",
  "description": "Webflow is looking for a Senior Site Reliability Engineer to help scale the infrastructure behind our visual web development platform. You will own on-call rotations, build monitoring and alerting for core services, and partner with the platform team to improve deployment reliability across environments.",
  "locations": ["San Francisco, CA", "U.S. Remote"],
  "department": "Engineering",
  "postingUrl": "https://job-boards.greenhouse.io/webflow/jobs/8122601",
  "applyUrl": "https://job-boards.greenhouse.io/webflow/jobs/8122601",
  "publishedAt": "2026-08-12T20:08:05.000Z",
  "companySlug": "webflow",
  "scrapedAt": "2026-09-03T09:15:42.000Z"
}
```

### How does it work?

Greenhouse Job Scraper resolves each input URL to a Greenhouse board token — either straight from the URL pattern, or by fetching the page once and reading the canonical link Greenhouse stamps on every hosted page, including custom domains. It then calls that board's public REST endpoint (`boards-api.greenhouse.io/v1/boards/{token}/jobs?content=true`) directly over HTTP, with no headless browser involved. Every request starts on a direct connection; if Greenhouse blocks it, the request escalates through a Datacenter-then-Residential proxy ladder automatically. Because the actor talks to Greenhouse's own JSON API rather than parsing rendered career-page HTML, only publicly visible job data is ever returned, and the output schema stays the same regardless of how a company styles or rebuilds its careers page.

### Integrations

Greenhouse Job Scraper works with whatever you already build with — the Apify API, no-code automation tools, and AI agent frameworks.

#### Calling Greenhouse Job Scraper programmatically

```python
import requests

response = requests.post(
    "https://api.apify.com/v2/acts/YOUR_USERNAME~greenhouse-job-scraper/run-sync-get-dataset-items",
    headers={"Authorization": "Bearer YOUR_APIFY_TOKEN"},
    json={
        "urls": ["https://job-boards.greenhouse.io/webflow"],
        "proxyConfiguration": {"useApifyProxy": True},
    },
)
jobs = response.json()
```

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.

#### MCP integration for AI agents

Greenhouse Job Scraper is reachable through Apify's hosted MCP server at `https://mcp.apify.com` — add it as a custom connector in Claude Desktop, or use the same URL in Cursor's or VS Code Copilot's MCP configuration, and select this Actor as a tool. A local stdio option is also available via `npx @apify/actors-mcp-server` when bearer-token auth is preferred over OAuth.

#### No-code tools (n8n, Make, LangChain)

In n8n, add Apify's native node to a workflow and point it at this Actor to run it and route the returned jobs into the rest of your graph. In Make, use Apify's app connector to add a "Run Actor" and "Get dataset items" module to a scenario. In LangChain, wrap this Actor as a tool using Apify's LangChain integration so an agent can call it directly and pull the resulting job postings into a retrieval or RAG chain.

### Is it legal to scrape Greenhouse job postings?

Yes — scraping publicly available job postings that any visitor can see without logging in is generally lawful. Greenhouse Job Scraper returns only publicly available data: job postings companies have chosen to publish so candidates can find and apply to them. Job postings are business/product data — a company's own listing of open roles — not personal data, so no candidate-facing regime like GDPR or CCPA attaches to this output; the applicable framework instead is the source site's terms of service and, in some jurisdictions, database-rights protections over the compiled board data. Consult legal counsel if your use case involves bulk storage of personal data.

### Frequently asked questions

#### What Greenhouse job posting fields does Greenhouse Job Scraper return?

`title`, `description`, `department`, `locations`, and `publishedAt` are the core fields, alongside `id`, `type`, `postingUrl`, `applyUrl`, `companySlug`, and `scrapedAt`. See the [data fields section](#what-data-can-i-extract-with-greenhouse-job-scraper) above for the full table.

#### Does Greenhouse Job Scraper require a Greenhouse account or login?

No. It calls `boards-api.greenhouse.io`, Greenhouse's own public, unauthenticated endpoint for hosted job boards — you only need an Apify account to run the actor itself.

#### How many job postings can I extract in one run?

There's no fixed cap in the input schema — every currently open posting on every board URL you supply is returned. Boards are fetched up to 5 at a time (a fixed internal concurrency value), and each unique board is only fetched once per run even if it's referenced by more than one input URL.

#### What happens if a job posting or board doesn't exist?

If a board token resolves to a Greenhouse board that doesn't exist, the request returns HTTP 404, the actor logs an error naming the board, marks that URL as failed, and moves on to the rest of the run. If a specific `?gh_jid=` job link points to a job that's closed or was on the wrong board, the actor logs that the job wasn't found on that board and marks the URL as failed — again without affecting any other board in the same run.

#### Can I scrape multiple Greenhouse job boards at once?

Yes. `urls` accepts an array of URLs — paste one company's board per line and they're all processed in the same run, up to 5 boards fetched concurrently.

#### Does Greenhouse Job Scraper work with Claude, ChatGPT, and other AI agent tools?

Yes. It's reachable through Apify's hosted MCP server (`https://mcp.apify.com`) for MCP-compatible clients like Claude Desktop and Cursor, and callable as a plain HTTP endpoint by any other agent framework.

#### Does Greenhouse Job Scraper return job descriptions as clean text or raw HTML?

Clean plain text. Greenhouse ships descriptions as HTML-escaped markup; the actor unescapes entities, replaces tags with spaces so words don't run together, and collapses all whitespace to single spaces before the description is written to the dataset.

#### Does Greenhouse Job Scraper return data in a format LLMs can use directly?

Yes. Every record is typed, normalized JSON with the same field names across runs — no HTML parsing or CSS selectors required. Pass it directly to an LLM, index it into a vector store, or feed it to an agent tool.

#### What happens when Greenhouse changes its layout or anti-bot system?

The actor is maintained and its output schema is designed to stay stable across Greenhouse changes, since it talks to Greenhouse's JSON API rather than parsing rendered career-page HTML for job data. No specific update turnaround is published or promised.

#### Can I use Greenhouse Job Scraper without managing proxies or browser infrastructure?

Yes. There's no headless browser to configure — requests go out over a browser-impersonating HTTP client — and proxies are optional: you only need to supply Apify Proxy credentials in `proxyConfiguration` for the rare case the automatic escalation ladder needs to use them.

#### Which Greenhouse job posting fields work best for AI training data and RAG indexing?

For RAG, index `title`, `description`, and `department` — the highest-information text fields. For training data, `id`, `companySlug`, `publishedAt`, and `locations` are the most consistently structured across every record, and all fields return as typed primitives (strings, numbers, or arrays of strings).

### Related scrapers

| Scraper name | What it extracts |
| --- | --- |
| Ats Jobs API | Job postings from Greenhouse, Lever, Ashby, Workable, and SmartRecruiters company career pages in one run |
| Internshala Scrapper | Internships and jobs listed on Internshala.com by search URL or filter |
| Naukri Job Scraper — India + Gulf | Job postings from Naukri.com and Naukrigulf.com, with up to 41 fields per job |
| Y Combinator Scraper | Companies, founders, and open jobs from the Y Combinator directory |
| LinkedIn People Profile Scraper | LinkedIn profile data — experience, education, skills — for sourcing candidates once you know who's hiring |

### Your feedback

Found a bug or missing a field? Open an issue on this Actor's **Issues** tab in Apify Console, or reach the Scraper Engine team directly at dev.scraperengine@gmail.com. Bug reports and feature requests are what keep this actor's field coverage accurate as Greenhouse changes.

# Actor input Schema

## `urls` (type: `array`):

One or more Greenhouse job board links. Paste any URL shape — job-boards.greenhouse.io/<company>, boards.greenhouse.io/<company>, an embed link, a single ?gh\_jid= job link, or even a company's own custom-domain careers page. 📋 Bulk-paste as many companies as you like — one per line.

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

Every request starts DIRECT (no proxy) for maximum speed. 🔀 If Greenhouse ever rejects or rate-limits a request, the actor automatically escalates: Datacenter proxy → Residential proxy (retried up to 3×) — then stays on Residential for the rest of the run. This field supplies the Apify Proxy credentials/country used only if that fallback ever kicks in. Leave the default on so the safety net is available.

## Actor input object example

```json
{
  "urls": [
    "https://job-boards.greenhouse.io/webflow"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every scraped job, all fields, raw JSON.

## `overview` (type: `string`):

Compact columns: company, title, department, locations, type, published date, link.

## `fullDetails` (type: `string`):

Every field including the full job description.

## `byCompany` (type: `string`):

Company- and department-led column order, for runs covering several companies.

## `csv` (type: `string`):

The full dataset as a CSV download.

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

Boards requested/succeeded/failed, job count, request count and final proxy tier for this run.

# 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 = {
    "urls": [
        "https://job-boards.greenhouse.io/webflow"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper-engine/greenhouse-job-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 = {
    "urls": ["https://job-boards.greenhouse.io/webflow"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scraper-engine/greenhouse-job-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 '{
  "urls": [
    "https://job-boards.greenhouse.io/webflow"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scraper-engine/greenhouse-job-scraper --silent --output-dataset

```

## MCP server setup

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