# Greenhouse and Lever Job Board Scraper (`jadeite_geometry/ats-job-boards`) Actor

Open jobs from any company hiring through Greenhouse or Lever: title, location, department, posted date, salary where published and the apply link.

- **URL**: https://apify.com/jadeite_geometry/ats-job-boards.md
- **Developed by:** [Niklesh Kumar](https://apify.com/jadeite_geometry) (community)
- **Categories:** Jobs, Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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?

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 and Lever Job Board Scraper

Open jobs from any company hiring through Greenhouse or Lever: title, location, department, posted date, salary where published and the apply link.

### What does Greenhouse and Lever Job Board Scraper do?

Greenhouse and Lever are hiring systems that thousands of companies use to publish their open jobs. This Actor reads a company's job board through each system's official public job board interface and gives you every open job in one table, whichever system the company uses. You list the companies; it returns their jobs.

It is made for recruiters who watch competitors' hiring, job boards and newsletters that list jobs, and researchers who treat hiring as a signal of what companies are doing.

### What data does it return?

One row per open job.

| Field | Example | Meaning |
|---|---|---|
| `ats` | `greenhouse` | Which hiring system the job came from: `greenhouse` or `lever`. |
| `board` | `figma` | The company's board name, as it appears in its Greenhouse or Lever address. |
| `jobId` | `6131079004` | The job's own ID in that system. |
| `title` | `Brand Designer, Product Launches` | Job title. |
| `company` | `Figma` | Company name. Greenhouse publishes it. Lever doesn't, so for Lever jobs this is the board name. |
| `location` | `San Francisco, CA` | Where the job is, as the company wrote it. Several places are joined with `|`. |
| `department` | `Design` | Department. For a Greenhouse job filed under a sub-department, this is the top-level department. |
| `team` | `Platform` | The team (Lever) or the sub-department (Greenhouse). Empty when the job has none. |
| `employmentType` | `Full-time` | Full-time, contract, internship and so on, in the company's words, when the posting says. Greenhouse shows it only if the company added such a field. |
| `workplace` | `remote` | `remote`, `hybrid` or `onsite`, when the posting says so or its location does. Empty otherwise. |
| `postedAt` | `2026-08-15T00:02:16Z` | When the job was first published (UTC). |
| `updatedAt` | `2026-08-15T00:02:16Z` | When the job was last changed (UTC). Greenhouse only; Lever doesn't publish it, so it is empty. |
| `jobUrl` | `https://boards.greenhouse.io/figma/jobs/6131079004` | Link to the job's own page. |
| `applyUrl` | `https://jobs.lever.co/spotify/.../apply` | Link to the application form. For Greenhouse this is the job page, which holds the form. |
| `salaryMin` | `127000` | Lowest pay the posting publishes, in whole currency units. Empty when the company publishes no pay. |
| `salaryMax` | `269000` | Highest pay the posting publishes. |
| `salaryCurrency` | `USD` | Currency of the pay. |
| `salaryInterval` | `year` | What the pay covers: `hour`, `day`, `week`, `month` or `year`. Lever only. Greenhouse doesn't say, so it is empty. |
| `descriptionSnippet` | `We design Spotify's consumer experience...` | The first 500 characters of the posting as plain text. Only present when you turn on "Add a short description". |

### How to use it

1. Open the Input tab and fill in the fields below. The prefilled values work as they are.
2. Click Start.
3. Download the results as JSON, CSV or Excel, or read them through the Apify API.

| Input | Meaning |
|---|---|
| `boards` | The companies to read. For each one, paste the address of its Greenhouse or Lever job page (for example `https://boards.greenhouse.io/figma` or `https://jobs.lever.co/spotify`) or just the board name from that address (`figma`). A bare name is tried on Greenhouse first, then on Lever, so paste the address when you know which one the company uses. Lever's European addresses (`jobs.eu.lever.co`) work too. |
| `keywords` | Optional. Keep only jobs whose title contains one of these words or phrases. |
| `location` | Optional. Keep only jobs whose location contains this text, for example `Berlin`. |
| `workplace` | Optional. `remote`, `hybrid` or `onsite` keeps only jobs of that type. `any` keeps everything. |
| `includeDescriptions` | Adds `descriptionSnippet`. Greenhouse boards download several times more data with this on, so runs take longer. |
| `maxItems` | Stop after this many results. |

**Finding a company's board name:** open the company's careers page and look at where a job's Apply or View button leads. An address like `boards.greenhouse.io/NAME`, `job-boards.greenhouse.io/NAME` or `jobs.lever.co/NAME` means the board name is NAME. The Actor can't find the name from a careers page on the company's own website; give it the board name instead.

### How much does it cost?

You pay **$2.00 per 1,000 results**, with no monthly fee. Only the jobs that pass your filters are saved, so you pay only for the rows you get. New Apify accounts get free monthly credit, so you can try it at no cost.

### Example output

```json
{
  "ats": "greenhouse",
  "board": "figma",
  "jobId": "6131079004",
  "title": "Brand Designer, Product Launches",
  "company": "Figma",
  "location": "San Francisco, CA • New York, NY • United States",
  "department": "Design",
  "team": null,
  "employmentType": null,
  "workplace": null,
  "postedAt": "2026-08-15T00:02:16Z",
  "updatedAt": "2026-08-15T00:02:16Z",
  "jobUrl": "https://boards.greenhouse.io/figma/jobs/6131079004?gh_jid=6131079004",
  "applyUrl": "https://boards.greenhouse.io/figma/jobs/6131079004?gh_jid=6131079004",
  "salaryMin": 127000,
  "salaryMax": 269000,
  "salaryCurrency": "USD",
  "salaryInterval": null
}
```

### Data source and limits

- **Where the data comes from:** the public job board interfaces of [Greenhouse](https://docs.greenhouse.io/job-board.html) and [Lever](https://github.com/lever/postings-api). Neither needs a key. Greenhouse says "Job Board data is publicly available, so authentication is not required for any GET endpoints." Lever says its published postings "are publicly viewable. These jobs may be scraped by third parties."
- **How fresh it is:** read live on every run, so you get what each company has published at that moment. Neither system lists closed jobs.
- **Rate limits the Actor respects:** one request per second (Lever's robots.txt asks for a one second delay), with automatic back-off whenever a source asks it to slow down. A Greenhouse board takes two requests and a Lever board takes one request for every 100 jobs.
- **Not covered:** other hiring systems such as Ashby or Workday, and job pages that sit on a company's own website rather than on Greenhouse or Lever.
- **Salary is often empty:** it appears only when the company published a pay range with the job.
- **Independent tool:** it isn't affiliated with, endorsed by or sponsored by Greenhouse or Lever. Both names belong to their owners and are used only to say which systems the Actor reads.

The data is public. This Actor doesn't collect personal data, and it removes email addresses and phone numbers from any text it keeps.

### FAQ

**Can I run it on a schedule?** Yes. Use Apify Schedules to run it daily or hourly and send the results to Google Sheets, Slack, a webhook or your own API.

**Why did a company return no jobs?** Either it has no open jobs right now, or the board name is wrong. The run log lists every entry that was skipped and why.

**Is it legal?** It reads only public, non-personal data from official interfaces that allow automated access, at a polite rate. Check that your own use fits the sources' terms.

# Actor input Schema

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

One entry per company. Paste the address of its Greenhouse or Lever job page, such as https://boards.greenhouse.io/figma or https://jobs.lever.co/spotify, or just the board name from that address (figma, spotify). A bare name is tried on Greenhouse first, then on Lever, so paste the address when you know which one the company uses.

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

Optional. Keep only jobs whose title contains at least one of these words or phrases (capital letters don't matter). Leave empty to get every job.

## `location` (type: `string`):

Optional. Keep only jobs whose location text contains this, for example Berlin or United States (capital letters don't matter). Leave empty for all locations.

## `workplace` (type: `string`):

Keep only remote, hybrid or on-site jobs. The type is what the posting says; if it says nothing, the Actor looks for the word remote or hybrid in the location. With a filter on, jobs whose type can't be told are left out.

## `includeDescriptions` (type: `boolean`):

Adds descriptionSnippet, the first 500 characters of each posting as plain text with email addresses and phone numbers removed. Greenhouse boards download several times more data with this on, so runs are slower.

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

Stop after saving this many results. You pay per saved result.

## Actor input object example

```json
{
  "boards": [
    "https://jobs.lever.co/spotify",
    "https://boards.greenhouse.io/figma"
  ],
  "keywords": [],
  "location": "",
  "workplace": "any",
  "includeDescriptions": false,
  "maxItems": 100
}
```

# Actor output Schema

## `results` (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": [
        "https://jobs.lever.co/spotify",
        "https://boards.greenhouse.io/figma"
    ],
    "keywords": [],
    "location": "",
    "workplace": "any",
    "includeDescriptions": false,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("jadeite_geometry/ats-job-boards").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": [
        "https://jobs.lever.co/spotify",
        "https://boards.greenhouse.io/figma",
    ],
    "keywords": [],
    "location": "",
    "workplace": "any",
    "includeDescriptions": False,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("jadeite_geometry/ats-job-boards").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": [
    "https://jobs.lever.co/spotify",
    "https://boards.greenhouse.io/figma"
  ],
  "keywords": [],
  "location": "",
  "workplace": "any",
  "includeDescriptions": false,
  "maxItems": 100
}' |
apify call jadeite_geometry/ats-job-boards --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jadeite_geometry/ats-job-boards"
        }
    }
}
```

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/w82z0X8G9L8ibiphk/builds/EoHYiJO3Vyd4escGO/openapi.json
