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

Scrape open jobs straight from company career boards on Greenhouse, Lever, Ashby, Workable and SmartRecruiters: title, location, remote, department, posted date, apply link, full description and parsed salary range. Only-new mode for job alerts. No login, no proxy. Pay only per job delivered.

- **URL**: https://apify.com/scrapemole/ats-jobs-scraper.md
- **Developed by:** [ScrapeMole](https://apify.com/scrapemole) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 job delivereds

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/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 and SmartRecruiters jobs with salaries

Scrape **open jobs straight from company career boards** on **Greenhouse, Lever, Ashby, Workable and SmartRecruiters**. Paste board links (or just company names) and get every job's **title, location, remote/hybrid, department, employment type, posted date, apply link, full description** and a **parsed salary range** (min, max, currency, per year/month/hour).

Schedule it with **Only new jobs since the last run** and you get, and pay for, only the jobs you haven't seen yet: a job-alert feed for any list of companies.

**You only pay for jobs delivered.** Unknown companies, invalid links and "no new jobs" notices are reported as clear rows and never charged.

### Why this jobs scraper

- **First-party data, not a search engine.** Jobs come from each company's own applicant tracking system (ATS) through its public job-board API, so they are complete, current and have the real apply link. No login, no CAPTCHAs.
- **Five ATSs, one schema.** Greenhouse, Lever (US and EU), Ashby, Workable and SmartRecruiters rows all have the same fields.
- **Salaries parsed for you.** Uses the ATS's own pay data when the company publishes it (Ashby, Greenhouse pay ranges), otherwise finds the range in the description: `$120k–$150k`, `€60.000 - €75.000 per year`, `£25/hour`, `90 000 – 110 000 EUR`. `salarySource` tells you which.
- **Auto-detects the ATS.** Type `ramp` or `notion` and the Actor finds the board.
- **Fast and cheap.** No browser and no proxy: 700 Stripe jobs take a couple of seconds.

### What you get

| Field | Description |
|---|---|
| `jobId`, `title`, `url`, `applyUrl` | The job and where to apply |
| `companyName`, `company`, `ats` | Company, its board slug and the ATS |
| `location`, `locations`, `country` | All locations the job lists |
| `remote`, `workplaceType` | `true` for remote jobs; `remote`, `hybrid` or `onsite` when the ATS says |
| `department`, `team`, `employmentType` | Org and contract type |
| `postedAt`, `updatedAt` | ISO dates (when the ATS shows them) |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `salaryText`, `salarySource` | Parsed pay range |
| `description` | Plain text (e-mail addresses removed) |
| `isNew` | `true` in only-new mode |

### How to scrape company job boards

1. Add **companies**: board links such as `https://boards.greenhouse.io/stripe`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/notion`, `https://apply.workable.com/huggingface`, `https://jobs.smartrecruiters.com/ServiceNow`, or `greenhouse:stripe`, or just `stripe`.
2. Optional: filter by **title keywords**, **excluded keywords**, **locations**, **remote only** or **posted within N days**.
3. Optional: turn on **Only new jobs since the last run** and schedule the Actor.
4. Click **Start** and download JSON, CSV or Excel, or use the API.

#### Input example

```json
{
  "companies": ["https://boards.greenhouse.io/stripe", "https://jobs.lever.co/spotify", "notion", "ramp"],
  "keywords": ["engineer", "data"],
  "excludeKeywords": ["intern"],
  "locations": ["New York", "Remote"],
  "onlyNew": true
}
```

#### Output example

```json
{
  "status": "ok",
  "ats": "ashby",
  "company": "notion",
  "companyName": "Notion",
  "title": "Software Engineer, Developer Platform",
  "url": "https://jobs.ashbyhq.com/notion/8c0bf773-e536-45c9-9a6c-8ee478148cc8",
  "applyUrl": "https://jobs.ashbyhq.com/notion/8c0bf773-e536-45c9-9a6c-8ee478148cc8/application",
  "location": "San Francisco, California",
  "locations": ["San Francisco, California", "New York, New York"],
  "country": "United States",
  "remote": false,
  "workplaceType": "hybrid",
  "department": "Engineering",
  "employmentType": "FullTime",
  "postedAt": "2026-10-19T17:28:06.956Z",
  "salaryMin": 179000,
  "salaryMax": 200000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salaryText": "$179,000 – $200,000",
  "salarySource": "description",
  "description": "WHO WE ARE\n\nNotion is the collaborative AI workspace…"
}
```

### Only new jobs (job alerts)

With **Only new jobs since the last run** on, the Actor remembers the job IDs it delivered for each company in a named key-value store on your Apify account (`scrapemole-ats-jobs-state-<memory name>`). The first run returns all matching jobs; later runs return only jobs you haven't received. Closed jobs are forgotten automatically.

- Use a different **memory name** for each saved search (for example `eng-berlin` and `sales-us`).
- Jobs cut off by *Max jobs per company* are not marked as seen, so they arrive in a later run.
- When nothing is new you get one free `NO_DATA` row per company, so you can tell "no new jobs" from "broken".
- Connect a webhook, Slack, Make or Zapier to the run to get the new jobs pushed to you.

### Pricing

Pay per event, no start fee:

| Event | Free | Starter (Bronze) | Scale (Silver) | Business (Gold) |
|---|---|---|---|---|
| `job`: one job delivered | $0.0015 | $0.0012 | $0.001 | $0.0008 |

1,000 jobs cost $1.20 on the Starter plan. A daily alert for 20 companies usually costs a few cents, because only new jobs are charged. Unknown companies, invalid input and "no new jobs" rows are free. Set a maximum cost per run and the Actor stops cleanly at that budget.

### Use cases

- **Job boards and aggregators:** fresh, first-party listings with apply links and salaries.
- **Sales and recruiting signals:** which companies are hiring which roles, where, and how fast.
- **Salary benchmarks** by role, location and company.
- **Personal job alerts** for your target companies.
- **Datasets for AI** and labor-market research.

### API, Python and AI agents

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("scrapemole/ats-jobs-scraper").call(run_input={"companies": ["stripe", "notion"], "keywords": ["engineer"]})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["companyName"], job["title"], job.get("salaryMin"), job["url"])
```

Works with schedules, webhooks, Make, Zapier, n8n and Apify's MCP server for AI agents.

### FAQ

**Which companies work?** Any company whose careers page runs on Greenhouse, Lever, Ashby, Workable or SmartRecruiters. Check the link of the company's "Apply" page: `boards.greenhouse.io`, `job-boards.greenhouse.io`, `jobs.lever.co`, `jobs.eu.lever.co`, `jobs.ashbyhq.com`, `apply.workable.com` or `jobs.smartrecruiters.com`.

**A company comes back `NOT_FOUND`.** The slug doesn't exist on that ATS, or the company uses a different ATS or a custom domain. Paste the exact board link from the company's careers page.

**Do I need a proxy?** No. These are public job-board APIs. Leave the proxy off to keep runs cheap.

**Why is `salaryMin` empty?** Many companies don't publish pay. Where laws require it (for example in several US states), it's usually found.

**Is this legal?** The Actor reads jobs that companies publish for anyone to see through their public job-board APIs, and removes e-mail addresses from descriptions. You are responsible for how you use the data; check the terms that apply to you.

### More from ScrapeMole

ScrapeMole builds focused, reliable scrapers for public data: pay per result, no start fees, clear error rows that are never charged, and a `RUN_SUMMARY` on every run.

- [YouTube Transcript & Subtitles Scraper](https://apify.com/scrapemole/youtube-transcript-scraper)
- [Google Trends Scraper](https://apify.com/scrapemole/google-trends-scraper)
- [YouTube Scraper](https://apify.com/scrapemole/youtube-video-channel-scraper)
- [YouTube Comments Scraper](https://apify.com/scrapemole/youtube-comments-scraper)
- [Telegram Channel Scraper](https://apify.com/scrapemole/telegram-channel-scraper)
- [Amazon Product & Search Scraper](https://apify.com/scrapemole/amazon-product-scraper)
- [Google Jobs Scraper](https://apify.com/scrapemole/google-jobs-scraper)
- [YouTube Shorts Scraper](https://apify.com/scrapemole/youtube-shorts-scraper)
- [YouTube Channel Scraper](https://apify.com/scrapemole/youtube-channel-scraper)

Building an AI agent with its own wallet? The YouTube and Google Trends data is also sold per call over [x402](https://www.x402.org) (USDC on Base, no account): see [scrapemole.pages.dev](https://scrapemole.pages.dev). Questions or a missing field? Open an issue on this Actor. ScrapeMole is the maker of this Actor.

# Actor input Schema

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

Job-board links such as https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/notion, https://apply.workable.com/huggingface or https://jobs.smartrecruiters.com/ServiceNow. Also accepts "ats:slug" (e.g. greenhouse:stripe, lever-eu:acme) or a bare slug (e.g. ramp), which is looked up on all five systems.

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

Only jobs whose title contains any of these words (case-insensitive), e.g. engineer, designer, sales. Empty = all jobs.

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

Skip jobs whose title contains any of these, e.g. intern, senior, manager.

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

Only jobs whose location contains any of these (city, state, country or code), e.g. Berlin, London, United States, DE.

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

Only jobs marked remote by the ATS or with "remote" in the location.

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

Only jobs first published in the last N days (when the ATS shows a date).

## `onlyNew` (type: `boolean`):

Remember which jobs you already received (per company, in a named key-value store on your account) and return only jobs you haven't received yet. The first run returns everything that matches. Schedule it daily for job alerts; you pay only for new jobs.

## `stateKey` (type: `string`):

Separate memories for separate searches, e.g. "eng-berlin" and "sales-us". Letters, digits and dashes.

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

Add the full job description as plain text (e-mail addresses redacted). Salary parsing uses the description either way. SmartRecruiters needs one extra request per job for this.

## `maxDescriptionChars` (type: `integer`):

Cut descriptions after this many characters. 0 = full text.

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

Newest first. Big employers have thousands of open jobs.

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

How many boards to read at once.

## `maxRetries` (type: `integer`):

Retries for timeouts and server errors.

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

Not needed: these are public job-board APIs. Leave off to keep runs cheap.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ],
  "keywords": [
    "engineer"
  ],
  "remoteOnly": false,
  "onlyNew": false,
  "stateKey": "default",
  "includeDescription": true,
  "maxDescriptionChars": 0,
  "maxJobsPerCompany": 1000,
  "maxConcurrency": 4,
  "maxRetries": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All dataset rows (status ok or error).

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

JSON summary: processed/ok/failed counts, error codes, events charged, HTTP stats.

# 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://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion"
    ],
    "keywords": [
        "engineer"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapemole/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://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion",
    ],
    "keywords": ["engineer"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapemole/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://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ],
  "keywords": [
    "engineer"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapemole/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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