# Job Search & ATS Jobs Scraper: Workday, Greenhouse, Lever (`clean_feeds/ats-jobs-scraper`) Actor

Search 500k+ jobs by keyword & location, straight from 14,000+ company career sites, or get every job from any company. An Indeed & LinkedIn Jobs scraper alternative: no login, no proxies. 12 ATSs incl. Workday, Greenhouse, Lever, Ashby. Salaries, remote flags, new-jobs monitor.

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

## Pricing

from $2.00 / 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.

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

## Job Search & ATS Jobs Scraper: 500k+ jobs from company career sites

Two ways to get jobs, both **straight from employers' own career sites** (Workday, Greenhouse, Lever, Ashby and 8 more ATSs), never via job boards:

- 🔍 **Search jobs** by keyword and location across **500,000+ jobs from 14,000+ companies**, refreshed daily. Like Indeed or LinkedIn search, but every result comes from the employer's own job board.
- 🏢 **Get every job from any company.** Type `Ramp`, `stripe.com` or paste a careers URL; the Actor detects the ATS and pulls all open roles.

Plus everything you'd expect:

- ✅ **12 ATS platforms, one schema.** Workday, Oracle Cloud HCM, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor, Rippling, Breezy HR, from startups to the Fortune 500 (NVIDIA, JPMorgan, Salesforce, Stripe, OpenAI…)
- 💰 **Salaries.** Min, max, currency and interval when the employer publishes them
- 🏠 **Remote / hybrid / onsite** flags and normalized employment types
- ✔️ **Live-checked results.** Search results are re-read from the employer's board at run time: closed jobs are dropped and full descriptions included
- 🔔 **Monitor mode.** Schedule it daily and get only *new* jobs; already-seen jobs are never charged again
- ⚡ **Fast and reliable.** Official public JSON feeds, not browser scraping: no logins, proxies or CAPTCHAs, nothing to break

### Search mode: an Indeed & LinkedIn Jobs scraper alternative

Set **Mode** to **Search jobs**, enter title keywords and locations, and get matching jobs from our daily index of company career sites:

```json
{
  "mode": "search",
  "keywords": ["python", "data engineer"],
  "locations": ["Berlin", "Germany"],
  "remoteOnly": false,
  "maxResults": 100
}
```

- **Newest first**, at most 5 jobs per company by default (`maxJobsPerCompany`) so one big employer can't fill your results.
- **Aggregators and staffing agencies that bulk-repost other companies' jobs are skipped**, so every result is a real opening at the employer (turn on `includeAggregators` to keep them).
- **Live check** (`liveVerify`, on by default): each matching company's board is re-read during your run, so you never get jobs that closed since the daily index refresh, and you get full descriptions.
- Combine with **Only new jobs** and a daily schedule for a "new remote Python jobs" feed into Slack, email or Sheets.
- Typical searches finish in about 10 seconds.

**Coverage:** the index holds 500,000+ jobs from 14,000+ companies on Greenhouse, Ashby, Lever, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor, Rippling and Breezy, refreshed daily (each board at least every few days). Workday and Oracle employers are available in Companies mode (paste their careers URL). Missing a company? Add it in Companies mode; any company on a supported ATS works there.

### Why career sites beat scraping Indeed or LinkedIn

Looking for an Indeed or LinkedIn Jobs scraper? Most jobs on those sites are first posted on the company's own career page, which usually runs on one of the ATSs this Actor covers. Getting them from the source has real advantages:

| | Company career pages (this Actor) | Scraping Indeed / LinkedIn |
|---|---|---|
| Freshness | Live data straight from the company's board, often before it's syndicated elsewhere | Depends on syndication and reposting |
| Salary data | Structured min/max/currency where the company publishes it | Often missing or free text |
| Duplicates & reposts | One record per real opening, with a stable ID | Promoted reposts and agency duplicates |
| Reliability | Official public feeds: no login, cookies, proxies or CAPTCHAs | Aggressive bot blocking, login walls, frequent breakage |
| Terms of service | Feeds the ATSs provide for publishing jobs | Their terms prohibit scraping |

**What you won't get:** jobs from companies that only post on job boards, or use an ATS we don't support yet (iCIMS, Taleo…). For tech and enterprise hiring, career pages cover most openings.

*This Actor is not affiliated with Indeed or LinkedIn. "Indeed" and "LinkedIn" are trademarks of their respective owners.*

### Use cases

- **Job boards & aggregators.** Keep a niche board (remote, AI, Web3, security…) automatically filled
- **Recruiting & sales intelligence.** Hiring is a buying signal. See which target accounts are hiring for which teams
- **Job seekers.** Watch your dream companies and get new openings first
- **Market research.** Track hiring trends, salary ranges and team growth across competitors

### Input

| Field | Description |
|---|---|
| `mode` | `companies` (default): jobs from the companies you list. `search`: keyword/location search across the index |
| `companies` | Company names, domains, careers-page URLs, ATS board URLs, or `ats:slug` (e.g. `greenhouse:airbnb`) |
| `keywords` / `excludeKeywords` | Whole-word title filters, e.g. `engineer`, `security` / `intern` |
| `locations` | Keep jobs whose location contains any of these (`London`, `Germany`, `Remote`) |
| `remoteOnly` | Only remote jobs |
| `postedWithinDays` | Only jobs published in the last N days |
| `onlyNewJobs` | Monitor mode: skip jobs returned by earlier runs |
| `includeDescription` | Full description as HTML and plain text (default on) |
| `maxJobsPerCompany` | Cap results per company (search mode default: 5) |
| `maxResults` | Search mode: max jobs returned (default 100) |
| `liveVerify` | Search mode: re-check matches on the employer's board (default on) |
| `includeAggregators` / `searchAts` | Search mode: keep aggregator boards / limit to some ATSs |

Companies mode example:

```json
{
  "companies": ["Ramp", "https://jobs.lever.co/spotify", "greenhouse:airbnb", "huggingface"],
  "keywords": ["engineer"],
  "remoteOnly": true,
  "onlyNewJobs": true
}
```

### Output

Every job has the same fields, whatever the ATS:

```json
{
  "id": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "ats": "ashby",
  "company": "Ramp",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "team": "Backend",
  "location": "New York, NY (HQ)",
  "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
  "country": "USA",
  "workplaceType": "hybrid",
  "isRemote": true,
  "employmentType": "full-time",
  "salaryMin": 211400,
  "salaryMax": 290600,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salaryText": "$211.4K – $290.6K • Offers Equity",
  "postedAt": "2026-04-07T17:12:35.753000Z",
  "url": "https://jobs.ashbyhq.com/ramp/34413f8d-...",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-.../application",
  "descriptionText": "About Ramp…",
  "descriptionHtml": "<h1>About Ramp</h1>…"
}
```

Export to JSON, CSV, Excel, or send to Google Sheets, Slack, Zapier, Make or a webhook via Apify integrations.

### Pricing

Pay only for what you use:

- **$2 per 1,000 jobs** returned ($0.002 per job)
- **Companies mode only: $0.005 per company job board** scanned, whatever your filters keep (reading a board is the expensive part, especially big Workday and Oracle boards)
- **Search mode: no per-board fee**, just the jobs you get. 100 search results cost $0.20

Examples: all 300 jobs at one company cost about $0.61. A daily monitor of 20 companies costs $0.10 a day for scanning, plus $0.002 for each new job. Set **Maximum cost per run** in the run options to cap any run.

### Monitor mode: a daily feed of new jobs

1. Turn on **Only new jobs**.
2. Create a **Schedule** (e.g. every morning).
3. Connect an integration (Slack, email, Google Sheets, webhook).

The Actor remembers which jobs it already returned for that company list. Set **Monitor key** if you want to keep the history after editing the list.

### FAQ

**Which companies does search cover?** 14,000+ companies on 10 ATSs, discovered from public web data and refreshed daily. The list grows over time. Companies mode works for **any** company on a supported ATS, even if it isn't in the search index.

**Which companies are supported in Companies mode?** Any company whose careers page runs on Workday, Oracle Cloud HCM, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor, Rippling or Breezy HR, which covers tens of thousands of companies, from startups to the Fortune 500. If a name isn't detected, paste the company's careers-page or job-board URL instead. **For Workday and Oracle, always paste the careers URL** (it contains `myworkdayjobs.com`, `myworkdaysite.com` or `oraclecloud.com/hcmUI/CandidateExperience`), because those boards can't be guessed from a company name.

**Is this legal?** The Actor reads the public job-board feeds that these ATS platforms provide so companies can publish their openings. For Workday and Oracle, it reads the same public JSON the company's own career site loads in your browser (no login), and Workday's robots.txt allows it. It doesn't log in, bypass protections or collect candidate data.

**Why is `workplaceType` sometimes empty?** Some ATSs (mainly Greenhouse) only include it when the company sets it up. If the posting doesn't say onsite, hybrid or remote, the field stays empty instead of being guessed. For Greenhouse, `employmentType` is taken from the company's custom fields or the job title (intern, contract, part-time…) and defaults to `full-time` otherwise.

**Why is a company missing?** It may use a different ATS (iCIMS, Taleo, SuccessFactors…) or have no open roles.

**Why are Workday and Oracle runs slower?** Their list feeds lack some fields (Workday: locations; Oracle: employment and remote type), so the Actor makes one extra request per job for those and the description, and it paces itself to respect Workday's rate limits. Large boards (2,000+ jobs) are split automatically, so no jobs are missed. To speed things up, use title keywords or `maxJobsPerCompany`, or turn off **Include job descriptions**: with no location/remote/date filters, Workday and Oracle then skip the per-job request (fast list-only mode: title, link and posted date, plus department and locations on Oracle).

**Found a bug or need another ATS?** Open an issue on the Actor's Issues tab and we'll usually reply within a day.

***

Made by [Clean Feeds](https://apify.com/clean_feeds): clean, structured data from official sources.

# Actor input Schema

## `mode` (type: `string`):

Companies: every job from the companies you list (any company, any of the 12 ATSs). Search jobs: search by keyword and location across our daily index of thousands of company career sites (no company list needed), like a job board but straight from the source.

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

Companies mode. One per line. Any of: company name ("Hugging Face"), domain ("stripe.com"), careers page URL, ATS board URL ("https://jobs.lever.co/spotify"), or explicit "ats:slug" ("greenhouse:airbnb"). For Workday and Oracle companies paste the careers URL (e.g. "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" or "https://jpmc.fa.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1001"). The ATS is detected automatically.

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

Keep jobs whose title contains ANY of these words (whole-word match, case-insensitive), e.g. "python", "data engineer". In Search mode this is the main search box.

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

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

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

Keep jobs whose location contains ANY of these strings, e.g. "London", "Germany", "US", "Remote".

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

Only keep jobs marked remote by the ATS.

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

Only keep jobs published in the last N days. Leave empty for any age.

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

Return only jobs not returned by previous runs with the same company list. Schedule the Actor daily to get a feed of fresh openings - you only pay for new jobs.

## `monitorKey` (type: `string`):

Optional name for the monitor-mode memory. Set it to keep the same history after you edit the company list.

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

Include the full description as HTML and plain text.

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

Cap the number of jobs returned per company. Companies mode: no limit by default. Search mode: 5 by default, so one big employer can't fill your results.

## `maxResults` (type: `integer`):

Search mode: stop after this many jobs (newest first). Each job is billed, so this caps the cost.

## `liveVerify` (type: `boolean`):

Search mode: re-read each matching company's board right now, so jobs closed since the daily index refresh are dropped and full descriptions are included. Turn off for faster, description-less results straight from the index.

## `searchAts` (type: `array`):

Search mode: limit the search to some platforms, e.g. "greenhouse", "ashby", "lever". Leave empty for all.

## `includeAggregators` (type: `boolean`):

Search mode: by default, boards that bulk-repost other companies' jobs (aggregators, staffing agencies) are skipped so every result comes straight from the employer.

## Actor input object example

```json
{
  "mode": "companies",
  "companies": [
    "greenhouse:airbnb",
    "https://jobs.lever.co/spotify",
    "Ramp",
    "https://mastercard.wd1.myworkdayjobs.com/CorporateCareers"
  ],
  "remoteOnly": false,
  "onlyNewJobs": false,
  "includeDescription": true,
  "maxResults": 100,
  "liveVerify": true,
  "includeAggregators": false
}
```

# Actor output Schema

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

All scraped jobs as JSON, with title, company, location, workplace type, salary, dates, URLs and descriptions.

# 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": [
        "greenhouse:airbnb",
        "https://jobs.lever.co/spotify",
        "Ramp",
        "https://mastercard.wd1.myworkdayjobs.com/CorporateCareers"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("clean_feeds/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": [
        "greenhouse:airbnb",
        "https://jobs.lever.co/spotify",
        "Ramp",
        "https://mastercard.wd1.myworkdayjobs.com/CorporateCareers",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("clean_feeds/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": [
    "greenhouse:airbnb",
    "https://jobs.lever.co/spotify",
    "Ramp",
    "https://mastercard.wd1.myworkdayjobs.com/CorporateCareers"
  ]
}' |
apify call clean_feeds/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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