# Job Board Scraper: Greenhouse, Lever, Ashby & Workday (`glitchbound/job-board-scraper`) Actor

Pull open roles straight from companies' own career boards across five applicant tracking systems: Greenhouse, Lever, Ashby, SmartRecruiters and Workday. Title, location, department, remote flag, salary where published, posted date and a direct apply link, in one consistent shape.

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

## Pricing

from $1.30 / 1,000 jobs

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

## Job Board Scraper: Greenhouse, Lever, Ashby, SmartRecruiters & Workday

Pull open roles **straight from companies' own career boards**. Give it a list of companies; it works out which of five systems each one uses and returns every job in a single consistent shape.

### Why these sources

All five publish **official public job-board APIs**: companies expose them deliberately so their openings can be syndicated. That means no blocking, no login, and no grey area, unlike scraping a job aggregator.

It also means the data is **first-party**: straight from the employer, before it's rewritten or delayed by an aggregator.

### Auto-detect

You rarely know which ATS a company uses. Enter the board name from their careers URL and the Actor works it out:

| Careers URL | Enter |
|---|---|
| `boards.greenhouse.io/stripe` | `stripe` |
| `jobs.lever.co/acme` | `acme` |
| `jobs.ashbyhq.com/ramp` | `ramp` |
| `jobs.smartrecruiters.com/Visa` | `Visa` |
| `nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` | the whole URL |

### Filter before you pay

```json
{
  "companies": ["stripe", "ramp", "figma"],
  "titleKeywords": ["engineer"],
  "remoteOnly": true,
  "includeDescription": true
}
```

Filters run before billing, **you are charged only for jobs actually returned**, not for everything scanned.

### Do you need an API key? No. Is there a free tier? Yes.

The two things people search for in this category, measured, are **free** and
**API key**: `job board api free`, `job board api key`.

So, plainly:

- **No API key.** Nothing to register for, nothing to rotate, no key to leak in
  a repo. The source is a public API published deliberately by its owner.
- **No proxy setup.** The source does not bot-wall datacenter addresses, so the
  default works.
- **Pay per result, not per month.** There is no subscription and no minimum.
  Rows that error or that your filters drop are **not charged**.
- **Free to try.** Run it with the prefilled input and see real rows before
  deciding anything.

### What you get per job

Always: `company` · `ats` · `jobId` · `title` · `location` + `locations` · `remote` · `url` · `description` (clean text, HTML stripped)

Where the ATS publishes it: `department` + `departments` · `postedAt` · `updatedAt` · `employmentType` (Lever, Ashby, SmartRecruiters; Greenhouse does not expose it) · `compensation` (Ashby) · `seniority` (SmartRecruiters) · `postedAgo` (Workday, which publishes "Posted 3 Days Ago" rather than a date)

The split matters: a flat list reads as a guarantee, and a customer who writes code against `employmentType` will get null on every Greenhouse row.

### Use cases

- **Hiring-signal intelligence**: a company suddenly opening 12 sales roles is a growth signal; schedule this weekly and watch headcount plans
- **Job boards & aggregators**: build a niche board from first-party listings
- **Recruiting**: track which competitors are hiring the roles you're filling
- **Sales prospecting**: companies hiring for a stack are buying tools for it
- **LLM pipelines**: descriptions come through as clean text, ready to summarise or classify

### Which ATS, and how the board is found

Five applicant tracking systems, covering startups through to the largest
enterprises. Every one of these publishes its job board openly, because that is
how a company's own careers page renders its listings, so no key is involved
anywhere:

| ATS | Public board endpoint | Set `ats` to | Typical company |
|---|---|---|---|
| **Greenhouse** | `boards-api.greenhouse.io` job board API | `greenhouse` | startups and scale-ups |
| **Lever** | `api.lever.co` postings API | `lever` | startups and scale-ups |
| **Ashby** | Ashby's public job board API | `ashby` | newer startups |
| **SmartRecruiters** | `api.smartrecruiters.com` postings API | `smartrecruiters` | mid-market and enterprise |
| **Workday** | the career site's own `wday/cxs` endpoint | `workday` | large enterprises |

**Workday is the one that reaches the big companies.** Most of the Fortune 500
posts there rather than on a startup ATS, so a competitor-hiring watch that
skips Workday misses exactly the companies you most want to watch. NVIDIA alone
lists around 2,000 open roles through it.

Leave `ats` on `auto` and each company is tried against Greenhouse, Lever, Ashby
and SmartRecruiters, so a mixed list resolves without you knowing which system
anyone uses.

**Workday needs its careers URL, not a company name.** Its address carries three things
that a company name cannot produce: a host label, a data-centre number and a
career-site name, as in
`nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`. Guessing across those
would mostly generate 404s and bill you for the attempts, so instead you paste
the careers URL you already have and it is parsed for you.

You do not have to set `ats` for it, though. A Workday address identifies
itself, so `auto` recognises one on sight and routes it straight there. Mix
Workday URLs and plain board slugs in the same list and each is handled the
right way.

**A Greenhouse job board API key is not required.** The board endpoint is public
by design, since it is what the company's own careers page calls to render the
listings. The `companies` input takes the board token from the careers URL, so
`boards.greenhouse.io/stripe` means `stripe`.

Every job posting comes back with title, location, department, employment type,
remote flag, posted date, compensation when the company publishes it, and a
direct apply URL.

### Notes

- Descriptions are HTML-stripped into plain text, capped at 5,000 characters.
- Companies with no public board on any of the five systems return a clear `error` row naming the problem. **Error rows are never charged.**
- Public job postings only, no candidate data, no personal data.

# Actor input Schema

## `companies` (type: `array`):

One per line. For Greenhouse, Lever, Ashby and SmartRecruiters this is the board token from the careers URL, so boards.greenhouse.io/stripe means "stripe". For Workday, paste the whole careers URL, e.g. https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite. You can paste the URL instead of the identifier, e.g. https://boards.greenhouse.io/stripe works.

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

Only keep jobs whose title or department contains one of these (e.g. "engineer", "sales"). Leave empty for all. You are only charged for jobs actually returned.

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

Only keep jobs matching one of these locations (e.g. "london", "new york"). Leave empty for all.

## `remoteOnly` (type: `boolean`):

Only return roles flagged remote.

## `includeDescription` (type: `boolean`):

Include the full job description as clean text (HTML stripped), ready for an LLM.

## `ats` (type: `string`):

Which applicant tracking system to read. Auto-detect tries Greenhouse, Lever, Ashby and SmartRecruiters against each company. Workday is not auto-detected, because its address carries a tenant and site name that cannot be derived from a company name: pass the careers URL instead.

## `maxJobsPerCompany` (type: `integer`):

Upper limit of jobs RETURNED per company (after filters), so a small limit plus filters still gives you results. The form is prefilled with 50 so a first run costs cents; the cap when this field is left out entirely is 1000.

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

Proxy settings.

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

A hard ceiling on rows for the entire run, across every target. The per-target limits above cap each one separately, so fifty targets at twenty each is still a thousand rows; this caps the total. The run stops cleanly when it is reached and nothing beyond that point is fetched or charged. Leave empty for no ceiling.

## Actor input object example

```json
{
  "companies": [
    "stripe"
  ],
  "remoteOnly": false,
  "includeDescription": true,
  "ats": "auto",
  "maxJobsPerCompany": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Open roles from company Greenhouse, Lever and Ashby boards.

# 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 = {
    "companies": [
        "stripe"
    ],
    "maxJobsPerCompany": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("glitchbound/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 = {
    "companies": ["stripe"],
    "maxJobsPerCompany": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("glitchbound/job-board-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "stripe"
  ],
  "maxJobsPerCompany": 50
}' |
apify call glitchbound/job-board-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=glitchbound/job-board-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/3cNHRmfh2urgdifbY/builds/eyXgutPleFMTckuM9/openapi.json
