# ATS Jobs Scraper \[$2/1k💰] | 116+ Platforms | Hiring Data (`ahmed_jasarevic/multi-ats-jobs-scraper`) Actor

Scrape live job postings from 116+ ATS platforms - Greenhouse, Lever, Ashby, Workday and more for hiring-intelligence monitoring, sales prospecting, and job board data. Auto-detect the ATS from any company name or careers URL at $0.002 per result.

- **URL**: https://apify.com/ahmed\_jasarevic/multi-ats-jobs-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.97 / 1,000 results

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?

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

## Multi-ATS Jobs Scraper — Extract Job Postings from 116+ ATS Platforms

Extract live job postings from **116+ applicant tracking systems (ATS)** — Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Personio, Workable, BambooHR, Jobvite and 100+ more — for **job board data, hiring-intelligence monitoring, and career-site automation**. Paste a company's careers URL or just its name: the ATS is auto-detected and the right API is used, with all results normalized into a single schema for **$0.002 per saved job**.

### Main Use Cases

- **Competitor hiring monitoring** — detect open roles, department growth, and expansion signals across your competitive set, on a schedule.
- **Sales prospecting & lead generation** — open roles are buying signals; pair them with account lists to time outreach.
- **Building job databases & job-board APIs** — ingest structured roles from hundreds of companies without one integration per ATS.
- **Talent intelligence & recruiting research** — analyze hiring velocity, remote vs. onsite mix, and departmental openings across companies or geographies.
- **Remote & hybrid job tracking** — filter any company's live roles by remote status, location, title, department, or posting date.
- **Careers-page data for AI agents & LLM apps** — feed clean, normalized job postings to internal tools, agents, or RAG pipelines.

### How the ATS Auto-Detection Works

Most scrapers need you to know the platform in advance. This actor reads the URL itself: `boards.greenhouse.io` → Greenhouse, `jobs.lever.co` → Lever, `jobs.ashbyhq.com` → Ashby, `*.myworkdayjobs.com` → Workday, plus SmartRecruiters, Personio, Workable, BambooHR, Jobvite and 116+ more. Pass a bare company name like `stripe` or `ramp` and the correct ATS board is detected and queried automatically. No manual integration per company.

Each platform has its own optimized fetcher module:

- **Lever** → Lever's official public Postings API (one request returns all postings)
- **Greenhouse** → the public Greenhouse board API
- **Ashby** → the public Ashby jobs API
- **SmartRecruiters** → the public SmartRecruiters company API
- **100+ others** → optimized requests to each platform's public careers JSON/API

All requests run through the **Apify proxy** (on by default) and every module retries with exponential backoff.

### Build Business-Talent Databases Without One Integration Per ATS

Every platform's results are normalized to a single output schema, so one run can mix Greenhouse, Lever, Ashby, Workday and smaller ATS boards and still produce one clean dataset. That means:

- One schema to document, store, and expose to your team or an AI agent
- Filters that run **server-side**, so you only pay for the rows you keep
- Output you can export as **JSON, CSV, Excel or HTML** from the Apify dataset

### Input

The actor takes ATS board URLs and/or company names. All fields below come from the input schema (`required: ["sites"]`).

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `sites` | array\<string> | ✅ | — | ATS board URLs or company slugs, e.g. `["https://boards.greenhouse.io/stripe", "https://jobs.lever.co/spotify"]`. ATS auto-detected. |
| `organizations` | array\<string> | – | `[]` | Bare company names/slugs, e.g. `["stripe", "notion", "ramp"]`. ATS auto-detected from the name. |
| `maxJobsPerSite` | integer | – | `0` | Max postings per site/company. `0` = all. |
| `maxSites` | integer | – | `0` | Max sites to process from the combined list. `0` = all. |
| `maxJobsTotal` | integer | – | `0` | Hard ceiling on job rows for the whole run (billing control). `0` = unlimited. |
| `includeFullDescription` | boolean | – | `true` | Keep full HTML description. When `false`, only plain text is kept. |
| `maxConcurrency` | integer | – | `10` | Sites in parallel. Note: the current build processes sites sequentially regardless. |
| `titleKeyword` | string | – | `""` | Keep only jobs whose title contains this text (case-insensitive). |
| `keywords` | string | – | `""` | Keep only jobs matching these terms across title **and** description. Space-separated terms are AND-ed. |
| `location` | string | – | `""` | Keep only jobs whose location contains this text, e.g. `"London"`, `"New York"`, `"remote"`. |
| `department` | string | – | `""` | Keep only jobs whose department contains this text. |
| `employmentType` | string | – | `""` | Keep only jobs matching employment type, e.g. `"full"`, `"part"`, `"contract"`. |
| `remoteOnly` | boolean | – | `false` | Keep only jobs flagged as remote. |
| `postedAfter` | string | – | `""` | Keep only jobs published on/after `YYYY-MM-DD`. |
| `includeRawJson` | boolean | – | `false` | Attach the original ATS job object to each row (under the `raw` field). |
| `proxyConfiguration` | object | – | Apify proxy on | Route requests through the Apify proxy. Default `{"useApifyProxy": true}`. |
| `stateKey` | string | – | `""` | Accepted input for change detection; see note below. |
| `onlyNewOrUpdated` | boolean | – | `false` | Accepted input (requires `stateKey`); see note below. |
| `excludeBoilerplate` | boolean | – | `false` | Accepted input to strip boilerplate sections; see note below. |
| `translateToEnglish` | boolean | – | `false` | Accepted input for translation; see note below. |
| `enrichEmails` | boolean | – | `false` | Accepted input for company contact-email enrichment; see note below. |

> ⚠️ **Note on optional flags:** `stateKey`, `onlyNewOrUpdated`, `excludeBoilerplate`, `translateToEnglish` and `enrichEmails` are part of the input schema but are **not yet implemented in the current build** — they do not change the output today. Use the implemented filters (`titleKeyword`, `keywords`, `location`, `department`, `employmentType`, `remoteOnly`, `postedAfter`), `includeRawJson`, and the cap fields for reliable behavior.

### Output

Each dataset item is **one job posting**, normalized across all 116+ ATS platforms.

| Field | Type | Description |
|---|---|---|
| `id` | string | Unique posting ID from the source ATS |
| `title` | string | Job title |
| `company` | string | Company name |
| `site` | string | Site/company slug |
| `department` | string | Department or team |
| `team` | string | Team (when provided by the source) |
| `location` | string | Primary location |
| `allLocations` | array\<string> | All posting locations |
| `remote` | string | Workplace type: `remote`, `hybrid`, `onsite` or `null` |
| `isRemote` | boolean | Fully remote? |
| `employmentType` | string | Commitment, e.g. `Full-time`, `Contract` |
| `description` | string | Full HTML description (when `includeFullDescription` is on) |
| `descriptionPlain` | string | Plain-text description |
| `applyUrl` | string | Direct application URL |
| `hostedUrl` | string | Canonical posting URL on the ATS board |
| `country` | string | ISO country code of the primary location (when available) |
| `createdAt` | string | Posting creation date (ISO 8601) |
| `source` | string | ATS platform, e.g. `greenhouse`, `lever`, `ashby`, `workday` |
| `raw` | object | Original ATS payload (only when `includeRawJson: true`) |

### Example Input

```json
{
  "sites": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "organizations": ["notion"],
  "maxJobsPerSite": 100,
  "maxJobsTotal": 300,
  "remoteOnly": false,
  "includeFullDescription": true,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Example Output

```json
{
  "id": "ac978161-6f46-4f6b-ad9e-a258e642751c",
  "title": "Administrative Business Partner",
  "company": "Palantir Technologies",
  "site": "palantir",
  "department": "Administrative",
  "team": "Administrative",
  "location": "London, United Kingdom",
  "allLocations": ["London, United Kingdom"],
  "remote": "hybrid",
  "isRemote": false,
  "employmentType": "Full-time",
  "description": "<div>...</div>",
  "descriptionPlain": "...",
  "applyUrl": "https://jobs.lever.co/palantir/ac978161-6f46-4f6b-ad9e-a258e642751c/apply",
  "hostedUrl": "https://jobs.lever.co/palantir/ac978161-6f46-4f6b-ad9e-a258e642751c",
  "country": "GB",
  "createdAt": "2024-03-25T21:10:16.463Z",
  "source": "lever"
}
```

### Scrape Jobs Across 116+ ATS Platforms for $0.002 per Result

This actor is pay-per-result: **$0.002 per saved dataset item** (plus the standard actor-start event). Server-side filters and the `maxJobsPerSite` / `maxJobsTotal` / `maxSites` caps are the main billing controls — a filtered run only charges you for the rows you actually keep.

Free Apify accounts get a **capped preview** (the first 10 results) so you can validate output and schema before paying anything.

### Integrations & Automation

- **Apify API** — run the actor and pull datasets programmatically (REST, Python or JavaScript).
- **Scheduling** — run **daily or weekly** from Apify Console to keep a hiring-intelligence feed fresh; pair with `postedAfter` to surface only new roles. Recurring monitoring is the standard pattern for competitor-hiring and talent-intelligence use cases.
- **Webhooks** — notify your CRM, Slack, or internal tool on each run completion.
- **Dataset export** — JSON, CSV, Excel, XML, RSS from the Apify dataset, ready for job boards and analytics.

### Related Actors

- [**LinkedIn Jobs Scraper** (curious\_coder/linkedin-jobs-scraper)](https://apify.com/curious_coder/linkedin-jobs-scraper) — the most-used job scraper on Apify; LinkedIn board coverage.
- [**Job Board Scraper** (openclawai/job-board-scraper)](https://apify.com/openclawai/job-board-scraper) — LinkedIn, Indeed, Glassdoor, Google Jobs and ZipRecruiter in one actor.
- [**Indeed Job Scraper** (ahmed\_jasarevic/indeed-job-scraper)](https://apify.com/ahmed_jasarevic/indeed-job-scraper) — salary and company data from Indeed.
- [**Glassdoor Scraper Pro** (ahmed\_jasarevic/glassdoor-scraper)](https://apify.com/ahmed_jasarevic/glassdoor-scraper) — reviews, jobs and salaries to enrich talent research.
- [**Wellfound Scraper** (ahmed\_jasarevic/wellfound-scraper)](https://apify.com/ahmed_jasarevic/wellfound-scraper) — startup jobs, salary and equity data.

Use this actor for **company-owned career sites and ATS boards** (the freshest, most complete source of open roles) and pair it with the board scrapers above for a full market view.

### FAQ

#### Why use this actor instead of the official Greenhouse or Lever API?

Those APIs are per-company: you integrate once per employer and per ATS, and you still need to know which ATS each company uses. This actor auto-detects the ATS from a URL or company name and normalizes 116+ platforms into one schema, so one integration covers every company's careers page — with server-side filters and no per-company code.

#### What are the alternatives to this actor?

Alternatives depend on coverage: [career-site-job-listing-api](https://apify.com/fantastic-jobs/career-site-job-listing-api) covers 54+ ATS from an aggregated index (higher per-result price); [job-board-scraper](https://apify.com/openclawai/job-board-scraper) covers LinkedIn/Indeed/Glassdoor boards rather than career sites; single-platform actors exist for Greenhouse only. This actor's edge is coverage (116+ ATS, including long-tail platforms) plus direct-from-careers-page freshness at $0.002/result.

#### How do I scrape Greenhouse jobs?

Pass a `boards.greenhouse.io` URL or the company name in `sites`/`organizations` — e.g. `"https://boards.greenhouse.io/stripe"`. The actor detects Greenhouse and uses the Greenhouse board API. Any company on Greenhouse works identically.

#### Can it scrape Workday jobs?

Yes — `*.myworkdayjobs.com` URLs (e.g. `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`) are detected and scraped. Workday powers thousands of enterprise career sites, so this is the go-to path for Fortune-500 roles.

#### Can I get remote jobs only?

Yes — set `remoteOnly: true`. Combined with `location: "remote"` and `employmentType`, you can build a clean remote/hybrid job feed.

#### How much does scraping 100 jobs cost?

$0.002 per saved result → **$0.20 for 100 jobs**, plus the standard actor-start event. Filters and caps keep runs below effective billing.

#### How do I build a job board or job database from this?

Run with a list of `sites`/`organizations`, keep `includeFullDescription` on, export the dataset as JSON/CSV, and schedule the run daily for fresh postings. `maxJobsTotal` bounds each run's cost.

#### How accurate and fresh is the data?

Because rows come from each company's own ATS board/API, postings are as fresh as the source — typically updated within hours of a role being opened or closed, with no third-party aggregation lag.

### SEO Keywords

ats jobs scraper, career site job listing api, ats job scraping, greenhouse job scraper, greenhouse job board api, lever jobs api, ashby jobs scraper, workday jobs scraper, smartrecruiters jobs api, company career page scraper, scrape company career pages, hiring signal data, competitor hiring monitoring, hiring data api, job posting data, talent intelligence, job board api, job aggregator api, remote jobs scraper, remote job data, careers page data, job data export, startup jobs api, recruiting data, 116 ats platforms

### For AI Agents & LLM Apps

If you're calling this actor from an agent (via the Apify MCP server or the Apify API), here's the operational reference:

- **Purpose:** returns one normalized dataset item per open job posting from any of 116+ ATS platforms, given ATS board URLs or company names.
- **Minimal working input:**
  ```json
  { "sites": ["https://boards.greenhouse.io/stripe"] }
  ```
- **Variant inputs (real modes):**
  - Bare company names: `{ "organizations": ["ramp", "notion"], "maxJobsPerSite": 50 }`
  - Filtered/remote feed: `{ "sites": ["https://jobs.lever.co/spotify"], "remoteOnly": true, "location": "Berlin", "maxJobsTotal": 100 }`
- **Output field list:** `id, title, company, site, department, team, location, allLocations, remote, isRemote, employmentType, description, descriptionPlain, applyUrl, hostedUrl, country, createdAt, source` (+ `raw` when `includeRawJson: true`).
- **Behaviors an agent should know:**
  - **Key facts about the input schema:** `sites` is **required**; `organizations` is optional and merged with `sites` (then sliced by `maxSites`).
  - **Filter fields are applied server-side after fetch** — filters *reduce* billed dataset rows, so prefer setting `titleKeyword`/`keywords`/`location`/`department`/`employmentType`/`remoteOnly`/`postedAfter` over post-processing to control cost.
  - **Free (non-paying) runs are capped at 10 dataset rows** regardless of input.
  - Runs process sites sequentially (not in parallel) — `maxConcurrency` has no effect in the current build; plan long lists accordingly.
  - `includeRawJson` adds the full original ATS object per row — heavier output, useful for debugging or extra fields.
  - Default proxy is on (`useApifyProxy: true`) — keep it unless you know you don't need it.
  - Billing: **PAY\_PER\_EVENT** — $0.002 per dataset result + $0.0005 actor-start event (per GB). Use `maxJobsTotal`/`maxJobsPerSite`/`maxSites` to bound agent-triggered runs.

### Legal & Compliance Disclaimer

This actor scrapes publicly available job postings from third-party applicant tracking systems (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, and others). It is an **independent tool and is not affiliated with, endorsed by, or sponsored by** any of these platforms. It only reads publicly published career-page and job-board data — no login bypass, no CAPTCHA solving. Users are responsible for complying with each platform's Terms of Service and with applicable law in their jurisdiction when using this data. Output contains job-posting information (not personal contact data); if you use it for outreach, ensure you comply with applicable marketing and data-protection rules.

# Actor input Schema

## `sites` (type: `array`):

ATS board URLs or company slugs. Supports Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Personio, Workable, BambooHR, Jobvite, and 100+ more platforms. ATS is auto-detected from the URL.

## `organizations` (type: `array`):

Bare company names/slugs like \["stripe", "notion", "ramp"]. The ATS platform is auto-detected and the correct API is used.

## `maxJobsPerSite` (type: `integer`):

Maximum number of job postings to scrape per site/company. 0 = all postings.

## `maxSites` (type: `integer`):

Maximum number of sites to process. 0 = all sites in the list.

## `maxJobsTotal` (type: `integer`):

Hard ceiling on job rows across the entire run. Leave empty for no global cap.

## `includeFullDescription` (type: `boolean`):

Include the full HTML description on each row. When disabled, only plain text is kept.

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

How many sites to process in parallel. Higher = faster but more rate-limit risk.

## `titleKeyword` (type: `string`):

Keep only jobs whose title contains this text (case-insensitive).

## `keywords` (type: `string`):

Keep only jobs matching these keywords across title and description. Space-separated terms are ALL required (AND).

## `location` (type: `string`):

Keep only jobs whose location contains this text, e.g. "remote", "London", "New York".

## `department` (type: `string`):

Keep only jobs whose department contains this text.

## `employmentType` (type: `string`):

Keep only jobs whose employment type matches. E.g. "full", "part", "contract".

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

Keep only jobs flagged as remote.

## `postedAfter` (type: `string`):

Keep only jobs published on or after this date (YYYY-MM-DD).

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

Any name to enable incremental/change detection across runs.

## `onlyNewOrUpdated` (type: `boolean`):

Requires a state key above. Drops unchanged jobs from output.

## `excludeBoilerplate` (type: `boolean`):

When enabled, drops company description sections from the combined description.

## `includeRawJson` (type: `boolean`):

Attach the original ATS job object to each row under a raw field.

## `translateToEnglish` (type: `boolean`):

Auto-translate non-English titles/descriptions to English.

## `enrichEmails` (type: `boolean`):

Enrich each company with a contact email by discovering its website.

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

Route requests through the Apify proxy. The proxy keeps your IP hidden and avoids rate limits.

## Actor input object example

```json
{
  "sites": [
    "https://boards.greenhouse.io/lattice",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "organizations": [],
  "maxJobsPerSite": 0,
  "maxSites": 0,
  "maxJobsTotal": 0,
  "includeFullDescription": true,
  "maxConcurrency": 10,
  "titleKeyword": "",
  "keywords": "",
  "location": "",
  "department": "",
  "employmentType": "",
  "remoteOnly": false,
  "postedAfter": "",
  "stateKey": "",
  "onlyNewOrUpdated": false,
  "excludeBoilerplate": false,
  "includeRawJson": false,
  "translateToEnglish": false,
  "enrichEmails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "sites": [
        "https://boards.greenhouse.io/lattice",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp"
    ],
    "organizations": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/multi-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 = {
    "sites": [
        "https://boards.greenhouse.io/lattice",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/ramp",
    ],
    "organizations": [],
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/multi-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 '{
  "sites": [
    "https://boards.greenhouse.io/lattice",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "organizations": []
}' |
apify call ahmed_jasarevic/multi-ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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