# Greenhouse, Lever, Ashby & Workday Jobs Scraper (`ferncrawl/ats-jobs-scraper`) Actor

Scrape jobs from Greenhouse, Lever, Ashby, Workday, SmartRecruiters & Recruitee in one run. Paste company names or career URLs - ATS auto-detected. One clean schema: salary, remote, dates, description. Only-new-jobs mode.

- **URL**: https://apify.com/ferncrawl/ats-jobs-scraper.md
- **Developed by:** [Fern Crawl](https://apify.com/ferncrawl) (community)
- **Security:** Limited permissions
- **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 returneds

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, Lever, Ashby & Workday Jobs Scraper

**Get every open job from any company's career page — Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Recruitee — in one clean, unified dataset. About $1.50 per 1,000 jobs. No proxy, no login, no browser.**

Paste company names or job board URLs. The Actor detects which applicant tracking system (ATS) each company uses, pulls the jobs from the official public job board APIs, and returns them in **one schema** with title, department, location, remote flag, posted date, **structured salary** (min / max / currency / period), apply link and full description.

Schedule it with **Only new jobs** turned on and you get a daily feed of *newly posted* jobs only — you never pay twice for the same posting.

### Why this jobs scraper

| | This Actor | Typical single-ATS scraper |
|---|---|---|
| Platforms in one run | **6**: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Recruitee | 1 |
| Input | Company name, any board URL, or the company's own careers page | Exact board slug |
| ATS auto-detection | ✅ (`stripe` → Greenhouse, `figma.com/careers` → Greenhouse) | ❌ |
| Only new jobs (monitoring) | ✅ built in, free skips | ❌ / extra Actor |
| Structured salary | ✅ min, max, currency, period (from ATS data or pay text) | text or none |
| Remote flag, posted date in ISO UTC | ✅ normalized across all ATSs | varies |
| Proxy needed | ❌ — fast and cheap | often |
| Bad company in the list | Skipped with a clear reason; the rest still run | run fails |

### Pricing

Pay per event — you pay only for jobs you get:

- **$0.0015 per job returned** (≈ **$1.50 per 1,000 jobs**)
- a tiny Actor-start fee per run

Jobs removed by your filters and jobs skipped by *Only new jobs* are **not charged**. Set a max-cost limit on the run and the Actor stops exactly there.

### How to use

1. Add companies to **Companies**, one per line. Any of these work:
   - `https://job-boards.greenhouse.io/airbnb` · `https://jobs.lever.co/spotify` · `https://jobs.ashbyhq.com/ramp`
   - `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` (any Workday job or search URL)
   - `https://jobs.smartrecruiters.com/BoschGroup` · `https://bunq.recruitee.com`
   - a company careers page that embeds one of them, e.g. `https://www.figma.com/careers/`
   - a plain name like `stripe` or `notion` (looked up on Greenhouse, Lever and Ashby)
   - a forced platform: `lever:spotify`, `lever-eu:acme`, `smartrecruiters:BoschGroup`, `recruitee:bunq`
2. Optional: add filters — keywords, exclude keywords, departments, locations, remote, posted since.
3. Click **Start**. Download as JSON, CSV, Excel, or use the API.

Run with an empty input and you get a small demo (10 Airbnb + 10 Spotify jobs).

#### Example input

```json
{
  "companies": ["stripe", "jobs.lever.co/spotify", "https://jobs.ashbyhq.com/ramp",
                "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],
  "keywords": ["engineer", "data scientist"],
  "remote": "any",
  "postedSince": "7 days",
  "onlyNewJobs": true,
  "maxJobsPerCompany": 200
}
```

#### Example output (one item)

```json
{
  "company": "ramp",
  "ats": "ashby",
  "boardSlug": "ramp",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "location": "New York, NY (HQ)",
  "remote": true,
  "workplaceType": "hybrid",
  "employmentType": "Full-time",
  "salaryMin": 211400,
  "salaryMax": 290600,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": "$211.4K – $290.6K • Offers Equity",
  "jobUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "descriptionText": "About Ramp ...",
  "scrapedAt": "2026-11-03T02:00:00Z"
}
```

### Output fields

| Field | Description |
|---|---|
| `company`, `ats`, `boardSlug` | Company, platform, and board identifier |
| `jobId`, `requisitionId` | Stable job ID on the ATS, and the internal requisition number when published |
| `title`, `department`, `team` | Job title and org unit |
| `location`, `locations`, `country` | Main location, all locations, country |
| `remote`, `workplaceType` | `true/false`, and `remote` / `hybrid` / `onsite` when the ATS says so |
| `employmentType` | Full-time, Part-time, Contract, Intern… |
| `postedAt`, `updatedAt` | ISO-8601 UTC dates |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryText` | Pay range when the company publishes it |
| `jobUrl`, `applyUrl`, `boardUrl` | Links |
| `descriptionText`, `descriptionHtml` | Full description (plain text on by default; HTML optional) |

A run summary (jobs per company, detected ATS, failures with the reason) is saved as the `OUTPUT` record in the key-value store.

### Use cases

- **Job aggregators & job boards** — feed thousands of company career pages into your site daily.
- **Recruiting & sales intelligence** — spot which companies are hiring for which roles (hiring signals for outbound).
- **Job seekers** — get alerted when target companies post new remote engineering roles.
- **Labor-market & salary research** — structured pay ranges by role, location and company.
- **AI agents & RAG** — clean job data with full descriptions for LLM pipelines.

### Only new jobs (monitoring)

Turn on **Only new jobs** and schedule the Actor (e.g. daily). Each run returns only jobs it hasn't returned to you before for that company board; the rest are skipped for free. The memory lives in a named key-value store **`ats-jobs-seen`** in *your* Apify account — delete it to start over.

### FAQ

**Which ATS platforms are supported?** Greenhouse, Lever (US and EU), Ashby, Workday, SmartRecruiters and Recruitee.

**Do I need the exact board slug?** No. Paste the company's careers page or just its name; the ATS is detected. If a name isn't found, the summary tells you so — paste the board URL instead.

**Why do some jobs have no salary?** The salary is only available when the company publishes it (common in the US, required in several states).

**Is this legal?** The Actor reads the public job board APIs that companies use to publish their own openings. It collects no personal data.

**Workday dates?** Workday's list shows "Posted 3 days ago"; the Actor reads each job's exact start date.

Keywords: greenhouse jobs scraper, lever jobs scraper, ashby jobs scraper, workday jobs scraper, smartrecruiters scraper, recruitee scraper, ATS job scraper, careers page scraper, job postings API, job board scraper, company jobs, hiring data, new jobs alert, salary data.

# Actor input Schema

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

One per line. Paste any job board or careers-page URL and the ATS is detected automatically: job-boards.greenhouse.io/airbnb, jobs.lever.co/spotify, jobs.ashbyhq.com/ramp, nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, jobs.smartrecruiters.com/BoschGroup, bunq.recruitee.com, or a company careers page that embeds one of them. A plain name like 'stripe' is looked up on Greenhouse, Lever and Ashby. Force a platform with a prefix: 'lever:spotify', 'smartrecruiters:BoschGroup'. If empty, a small demo runs (Airbnb + Spotify, 10 jobs each).

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

Stop after this many matching jobs per company (0 = all, up to 10,000). You only pay for jobs returned.

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

Keep jobs whose title, department or team contains ANY of these words or phrases (case-insensitive, whole words), e.g. 'engineer', 'sales', 'data scientist'. Filtered-out jobs are free.

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

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

## `departments` (type: `array`):

Keep jobs whose department or team contains any of these texts, e.g. 'Engineering', 'Marketing'.

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

Keep jobs whose location contains any of these texts, e.g. 'New York', 'London', 'Germany', 'Remote'.

## `remote` (type: `string`):

Filter by the remote flag (from the ATS, or 'remote' in the location).

## `postedSince` (type: `string`):

Only jobs posted on/after this date. A date (2026-10-01) or a relative period: '24 hours', '7 days', '2 weeks', '1 month'. Jobs without a posting date are kept.

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

Return only jobs this Actor has not returned to you before (per company board). Schedule it daily to get a feed of newly posted jobs. Already-seen jobs are skipped and NOT charged. The memory is kept in a named key-value store 'ats-jobs-seen' in your own Apify account.

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

Add the full job description as clean plain text (descriptionText). Turn off for smaller, faster exports.

## `includeDescriptionHtml` (type: `boolean`):

Also add the original description HTML (descriptionHtml).

## `maxConcurrency` (type: `integer`):

How many company boards are fetched at the same time.

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

Not needed: all sources are public job board APIs. Only enable if a specific career site blocks you.

## Actor input object example

```json
{
  "companies": [
    "https://job-boards.greenhouse.io/airbnb",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "maxJobsPerCompany": 20,
  "remote": "any",
  "onlyNewJobs": false,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One item per job posting in one schema across Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Recruitee.

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

JSON summary: detected ATS and jobs per company, failed companies with the reason, filtered / already-seen 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",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("ferncrawl/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",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("ferncrawl/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",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "maxJobsPerCompany": 20
}' |
apify call ferncrawl/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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