# ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workable & more (`developing_developer/ats-jobs-scraper`) Actor

Get open jobs from company careers pages on Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio and Breezy HR. Normalized salary, remote/hybrid, employment type. Filter by keyword, location and date. Monitor mode returns only new jobs.

- **URL**: https://apify.com/developing_developer/ats-jobs-scraper.md
- **Developed by:** [Đăng lê](https://apify.com/developing_developer) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 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.

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

## ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workable & more

Get every open job from company careers pages hosted on **Greenhouse**, **Lever**, **Ashby**, **SmartRecruiters**, **Workable**, **Recruitee**, **Personio** and **Breezy HR**, in one clean format. Paste careers page URLs or company slugs, pick an industry (Fintech, AI, Healthcare, Developer Tools…), **or search all 1,500+ companies in the built-in directory by job title**, e.g. every remote "data engineer" job, without knowing a single company. Filter by title, location, workplace type and date, and turn on **monitor mode** to receive only jobs that are new since your last run.

The Actor reads the official public job board APIs that these platforms provide for careers pages. No login, no cookies, no browser.

### What you get

- **Search jobs across 1,500+ companies**: turn on `searchAllCompanies`, add title keywords, and the Actor checks every job board in its directory (about 50,000 open jobs on October 27, 2026).
- **Find companies by industry**: 759 Y Combinator startups in the directory carry industry labels. No need to know a single company slug.
- **One format for all eight platforms**: title, company, company website, industries, department, team, locations, workplace type, employment type, salary, posting date, job URL and apply URL.
- **Normalized fields**: `workplaceType` is always `remote`, `hybrid`, `onsite` or `null`; `employmentType` is `full-time`, `part-time`, `contract`, `internship`, `temporary` or `null`.
- **Structured salary** when the company publishes it (min, max, currency, interval).
- **Filters**: title keywords, excluded words, locations, workplace type, posted within N days.
- **Monitor mode**: schedule the Actor daily and get only new jobs.
- **Optional full description** as HTML and plain text.

### Supported platforms

| Platform | Careers page URL you can paste | Or use |
|---|---|---|
| Greenhouse | `https://job-boards.greenhouse.io/airbnb` | `greenhouse:airbnb` |
| Lever | `https://jobs.lever.co/palantir` | `lever:palantir` |
| Ashby | `https://jobs.ashbyhq.com/notion` | `ashby:notion` |
| SmartRecruiters | `https://jobs.smartrecruiters.com/Ubisoft2` | `smartrecruiters:ubisoft2` |
| Workable | `https://apply.workable.com/huggingface` | `workable:huggingface` |
| Recruitee | `https://bunq.recruitee.com` | `recruitee:bunq` |
| Personio | `https://ottonova.jobs.personio.de` | `personio:ottonova` |
| Breezy HR | `https://remote.breezy.hr` | `breezy:remote` |

### Use cases

- Track hiring at competitors, customers or target accounts.
- Find sales leads: every fintech startup hiring a "Head of Security" right now, with the company website.
- Build a niche job board or newsletter (remote jobs, AI startups, a city or a stack).
- Feed fresh job data to recruiting tools, CRMs or AI agents.
- Research which teams a company is growing.

### Input

| Field | Description |
|---|---|
| `companies` | Careers page URLs from any supported platform (see the table above), or `ats:slug` such as `workable:huggingface`. A plain slug like `notion` is checked on all eight platforms. Optional when `industries` or `searchAllCompanies` is set. |
| `industries` | Industry or tag labels from the company directory, e.g. `Fintech`, `AI`, `Developer Tools`. Every directory company with one of these labels is added to `companies`. Exact label, case-insensitive. |
| `searchAllCompanies` | Check every job board in the company directory (1,500+) and keep the jobs that pass your filters. Combine with `keywords`, `locations`, `workplaceTypes` or `postedWithinDays`. |
| `keywords` | Keep jobs whose title contains any of these words. |
| `excludeKeywords` | Drop jobs whose title contains any of these words. |
| `locations` | Keep jobs whose location contains any of these texts, e.g. `London`, `Germany`, `Remote`. |
| `workplaceTypes` | `remote`, `hybrid`, `onsite`. |
| `postedWithinDays` | Only jobs posted in the last N days. |
| `includeDescription` | Add the full job description. |
| `maxJobs` | Stop after this many jobs. |
| `onlyNewJobs` + `monitorName` | Monitor mode. The first run returns all matching jobs and saves them as the baseline; later runs return only new ones. |

Example:

```json
{
  "companies": ["https://job-boards.greenhouse.io/airbnb", "lever:palantir", "ashby:notion"],
  "keywords": ["engineer", "developer"],
  "workplaceTypes": ["remote", "hybrid"],
  "postedWithinDays": 14
}
```

Search all companies in the directory for remote data engineering jobs:

```json
{
  "searchAllCompanies": true,
  "keywords": ["data engineer", "analytics engineer"],
  "workplaceTypes": ["remote"],
  "postedWithinDays": 30
}
```

Find companies by industry instead:

```json
{
  "industries": ["Fintech"],
  "keywords": ["security"],
  "postedWithinDays": 30
}
```

### Company directory

The directory has 1,542 job boards that were hiring when it was built, from two public sources:

- **Y Combinator startups** (759 companies, rebuilt October 25, 2026), from the public YC company list. Each job board was found and checked to belong to the company: Greenhouse, Lever and Ashby boards must mention the company's name or website; SmartRecruiters, Recruitee, Personio and Breezy HR careers pages must link to the company's website. These companies have industry labels.
- **Companies hiring on Hacker News** (783 job boards, built October 27, 2026): careers page links that companies posted themselves in Hacker News comments, mostly the monthly "Ask HN: Who is hiring?" threads, through the official Hacker News search API. Only boards that still had open jobs were kept. The company name comes from the job board itself. These companies have no industry labels, so they are used by `searchAllCompanies` and for `companyName` / `companyWebsite`, not by `industries`.

Popular labels for `industries` (number of companies):

| | | | |
|---|---|---|---|
| `B2B` (449) | `AI` (243) | `SaaS` (158) | `Fintech` (136) |
| `Healthcare` (92) | `Developer Tools` (84) | `Industrials` (69) | `Infrastructure` (69) |
| `Consumer` (68) | `Engineering, Product and Design` (68) | `Marketplace` (38) | `Productivity` (37) |
| `Machine Learning` (34) | `API` (32) | `Health Tech` (32) | `Open Source` (30) |
| `Healthcare IT` (28) | `Sales` (28) | `Payments` (27) | `Marketing` (26) |
| `Manufacturing and Robotics` (25) | `Security` (25) | `Operations` (23) | `Robotics` (22) |
| `Supply Chain and Logistics` (22) | `Climate` (21) | `Digital Health` (21) | `Generative AI` (21) |
| `Compliance` (20) | `Finance and Accounting` (20) | `Analytics` (19) | `Enterprise Software` (19) |
| `HR Tech` (18) | `Aviation and Space` (17) | `Consumer Finance` (17) | `Data Engineering` (17) |

Any other label from the directory works too (255 labels in total). If a label is not found, the run log suggests similar ones.

Jobs from directory companies (whether you searched all companies, picked an industry or entered the company yourself) also get `companyName` and, when known, `companyWebsite` and `companyIndustries`.

### Output

```json
{
  "id": "ashby:openai:8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3",
  "ats": "ashby",
  "companySlug": "openai",
  "companyName": null,
  "companyWebsite": null,
  "companyIndustries": null,
  "title": "Technical Program Manager, Compute Infrastructure",
  "department": "Technical Program Management",
  "team": "Technical Program Management",
  "employmentType": "full-time",
  "workplaceType": null,
  "locations": ["San Francisco"],
  "salary": { "min": 257000, "max": 335000, "currency": "USD", "interval": "year", "text": "$257K - $335K" },
  "postedAt": "2026-03-12T16:38:15.322Z",
  "updatedAt": null,
  "url": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3",
  "applyUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3/application",
  "scrapedAt": "2026-10-21T04:20:00.000Z"
}
```

Fields the platform does not provide are `null`; nothing is guessed. A run summary (boards found, boards not found, jobs matched) is saved to the `SUMMARY` record in the key-value store.

### Pricing

You pay per job returned: **$1.50 per 1,000 jobs** ($0.0015 per job) plus $0.00005 per run. Platform usage (compute) is included; there is no separate cost for checking job boards.

| Example run | Jobs returned | Cost |
|---|---|---|
| 3 companies, all jobs, `maxJobs: 100` | 100 | $0.15 |
| `searchAllCompanies` + "data engineer" + remote (1,500+ boards checked) | 62 | about $0.09 |
| Daily monitor (`onlyNewJobs`) on 50 companies, 20 new jobs that day | 20 | $0.03 |

Jobs filtered out, duplicates and jobs already returned in monitor mode are free. Set `maxJobs` or a spending limit on the run to cap the cost.

### Notes

- `companyName` comes from the platform or from the company directory. Lever and Ashby do not publish it in their job board API, so it is `null` for their companies outside the directory; use `companySlug`.
- `companyWebsite` and `companyIndustries` are filled only for companies in the directory. `companyIndustries` is `null` for companies from Hacker News; `companyWebsite` is set only when the job board or the company's own post links to a domain matching the company name.
- Greenhouse salary ranges are not included yet.
- Greenhouse and Lever boards hosted in the EU region are not supported yet.
- Industry search (`industries`) does not include Workable boards. `searchAllCompanies` includes the Workable boards found on Hacker News; any other Workable company can be added by URL or slug.
- `searchAllCompanies` checks 1,500+ job boards on every run, so it takes a few minutes. Add a date filter and title keywords; you pay only for the jobs returned.
- Descriptions: SmartRecruiters needs one extra request per job, so `includeDescription` is slower there (only jobs that pass your filters are fetched). Breezy HR does not publish descriptions in its job board feed, and many Personio boards leave them out, so `descriptionText` can be missing for those.
- Recruitee and Personio boards on a custom domain (e.g. `careers.bunq.com`) cannot be recognized from the URL; use `recruitee:slug` or `personio:slug` with the company's platform subdomain.

### FAQ

**Is this legal?** The Actor only reads public job postings through the job board APIs and feeds that each platform publishes for careers pages. It does not log in or collect personal data about candidates.

**I don't know which companies to track.** Turn on `searchAllCompanies` and add title keywords, or use `industries`. Start with one label and a few title keywords, look at `SUMMARY` (`boardsFromIndustries`) and the results, then narrow down.

**How do I find a company's slug?** Open the company's careers page. The slug is the first part of the path (`jobs.lever.co/palantir` → `palantir`) or the subdomain (`bunq.recruitee.com` → `bunq`). You can also paste the whole URL.

**Why did a company return nothing?** It may use another ATS (Workday, iCIMS, Taleo…) or a custom careers site. Check `companiesNotFound` in the `SUMMARY` record.

# Actor input Schema

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

Careers page URLs (job-boards.greenhouse.io/..., jobs.lever.co/..., jobs.ashbyhq.com/..., jobs.smartrecruiters.com/..., apply.workable.com/..., <company>.recruitee.com, <company>.jobs.personio.de, <company>.breezy.hr), or "ats:slug" such as "workable:huggingface" (ats = greenhouse, lever, ashby, smartrecruiters, workable, recruitee, personio, breezy). A plain slug such as "notion" is checked on all eight platforms. Optional when you pick industries below.

## `industries` (type: `array`):

Don't know the companies? Pick industries or tags, e.g. "Fintech", "Healthcare", "AI", "Developer Tools", "SaaS", "Climate". The Actor adds every company from its built-in directory of Y Combinator startups (verified job boards on Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee, Personio and Breezy HR) with that label (exact label, case-insensitive). See the README for the full list. Combine with title keywords to keep the result small.

## `searchAllCompanies` (type: `boolean`):

Search every company in the built-in directory (Y Combinator startups plus companies that posted their job board on Hacker News, 1,000+ job boards) and keep jobs that match your filters below. Use it to search jobs by title keyword without knowing the companies, e.g. keywords "data engineer" + workplace type Remote. Add title keywords, locations or a date filter to keep the result small.

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

Keep jobs whose title contains at least one of these words (case-insensitive). Leave empty to keep all.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains any of these words, e.g. "intern", "senior".

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

Keep jobs whose location contains at least one of these texts, e.g. "London", "Germany", "Remote".

## `workplaceTypes` (type: `array`):

Keep only these workplace types. Jobs with unknown workplace type are dropped when this is set.

## `postedWithinDays` (type: `integer`):

Keep jobs posted in the last N days. 0 = no date filter.

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

Add the full description as HTML and plain text. Makes results much larger.

## `maxJobs` (type: `integer`):

Stop after this many jobs. 0 = no limit.

## `onlyNewJobs` (type: `boolean`):

Return only jobs not returned by earlier runs with the same monitor name. The first run returns everything and saves it as the baseline. Use with a schedule to get a daily feed of new jobs.

## `monitorName` (type: `string`):

Separate monitors keep separate history. Use letters, numbers and hyphens.

## Actor input object example

```json
{
  "companies": [
    "https://job-boards.greenhouse.io/airbnb",
    "lever:palantir",
    "ashby:notion",
    "workable:huggingface"
  ],
  "searchAllCompanies": false,
  "postedWithinDays": 0,
  "includeDescription": false,
  "maxJobs": 0,
  "onlyNewJobs": false,
  "monitorName": "default"
}
```

# Actor output Schema

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

One item per job: title, company, locations, workplace type, employment type, salary, dates and URLs.

## `summary` (type: `string`):

Boards found, boards that failed, companies not found and job counts.

# 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": [
        "https://job-boards.greenhouse.io/airbnb",
        "lever:palantir",
        "ashby:notion",
        "workable:huggingface"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("developing_developer/ats-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 = { "companies": [
        "https://job-boards.greenhouse.io/airbnb",
        "lever:palantir",
        "ashby:notion",
        "workable:huggingface",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("developing_developer/ats-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 '{
  "companies": [
    "https://job-boards.greenhouse.io/airbnb",
    "lever:palantir",
    "ashby:notion",
    "workable:huggingface"
  ]
}' |
apify call developing_developer/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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