# Career Page Jobs Scraper - Greenhouse, Lever, Ashby, Workday (`upendra_11/ats-jobs-scraper`) Actor

Get every open job from company career pages on Greenhouse, Lever, Ashby, Workday, Workable, Recruitee, BambooHR, Personio and Teamtailor. Enter company websites or names; the hiring system is detected automatically. Salary, location, remote type, dates and new-job monitoring.

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

## Pricing

Pay per event

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

## Career Page Jobs Scraper: Greenhouse, Lever, Ashby, Workday & more

Get **every open job directly from company career pages**. Give it a list of companies (websites, names, or job-board links) and it **automatically detects which hiring system each company uses**, then returns all their jobs in **one clean, consistent format**.

**Supported hiring systems (ATS):** Greenhouse · Lever · Ashby · Workday · Workable · Recruitee · BambooHR · Personio · Teamtailor

**Highlights:**

- ✅ **Just paste company websites:** `stripe.com`, `notion.so`, `linear.app`. No need to know which ATS they use.
- ✅ **9 hiring systems, one output format:** title, department, team, locations, remote/hybrid/onsite, employment type, **salary range** where published, posted date, job and apply links, and the full description (optional).
- ✅ **Straight from the source:** jobs come from each company's official job board, so they're fresher and more complete than job-board reposts.
- ✅ **Monitoring mode:** schedule it daily and get **only new jobs** ("hiring signals").
- ✅ **Filters:** title keywords, locations, departments, remote only, posted within N days.
- ✅ **Fast and reliable:** uses the hiring systems' public job APIs and feeds. No browser, no login, no personal data.

### Who uses it

- 💼 **Sales & growth teams:** spot companies hiring for roles that signal a need for your product (for example, "hiring 3 data engineers").
- 🧑‍💼 **Recruiters & staffing agencies:** track openings at target accounts the moment they're posted.
- 🔎 **Job boards & aggregators:** fill niche job boards (remote, AI, climate, startups) with fresh, structured jobs.
- 📊 **Market & talent research:** hiring trends by company, department, location and salary.
- 🤖 **AI agents:** one dependable tool for "list open ML engineering roles at these 50 companies".

### How to use

1. Add **Companies**, one per line, in any of these forms:
   - a **website**: `stripe.com`
   - a **name**: `Hugging Face`
   - a **job board / careers URL**: `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/openai`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`
2. Optionally add filters: **keywords**, **locations**, **departments**, **remote only**, **posted within**.
3. Click **Start**. Download the jobs as JSON, CSV or Excel, or use the API.

**How detection works:** URLs of supported systems are recognized instantly. For websites, the Actor scans the homepage and careers pages for job-board links. If none are found, it can try the company name as the job board name on each system. It validates every match against the live job board, checks the company name where the system reports one, and skips empty, abandoned boards. Each job records how its board was found in `detectedBy` (`url`, `careers-page` or `name-guess`).

**Workday tip:** large employers on Workday often load their job links with JavaScript. If a Workday company isn't detected from its website, paste its `*.myworkdayjobs.com` link (shown after clicking "Search jobs" on their careers page).

### Input example

```json
{
  "companies": ["stripe.com", "notion.so", "Spotify", "https://jobs.lever.co/palantir"],
  "keywords": ["engineer", "data"],
  "locations": ["London", "remote"],
  "postedWithinDays": 14,
  "maxJobsPerCompany": 1000,
  "includeDescription": false
}
```

| Field | What it does | Default |
|---|---|---|
| `companies` | Websites, names or job-board URLs | required |
| `keywords` | Keep jobs whose title contains any of these | all |
| `locations` | Keep jobs whose location contains any of these; `remote` matches remote jobs | all |
| `departments` | Keep jobs in matching departments or teams | all |
| `remoteOnly` | Only fully remote jobs | `false` |
| `postedWithinDays` | Only jobs posted in the last N days (0 = any) | `0` |
| `maxJobsPerCompany` | Cap per company, before filters | `1000` |
| `includeDescription` | Add the full description as plain text | `false` |
| `platforms` | Limit detection to some hiring systems | all 9 |
| `guessFromCompanyName` | Allow validated name guesses | `true` |
| `onlyNewSinceLastRun` / `monitorName` | Monitoring mode | `false` |

### Output example

```json
{
  "id": "ashby:openai:240d459b-696d-43eb-8497-fab3e56ecd9b",
  "ats": "ashby",
  "company": "openai",
  "title": "Research Engineer",
  "department": "Research",
  "team": "Research",
  "locations": ["San Francisco"],
  "workplaceType": null,
  "employmentType": "full_time",
  "salaryMin": 250000,
  "salaryMax": 445000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": "$250K - $445K",
  "postedAt": "2025-04-05T00:03:20+00:00",
  "url": "https://jobs.ashbyhq.com/openai/240d459b-696d-43eb-8497-fab3e56ecd9b",
  "applyUrl": "https://jobs.ashbyhq.com/openai/240d459b-696d-43eb-8497-fab3e56ecd9b/application",
  "detectedBy": "name-guess",
  "scrapedAt": "2026-10-26T10:00:00+00:00"
}
```

**All output fields:**

- **Identity:** `id`, `ats`, `input`, `detectedBy`, `company`, `companySlug`, `jobId`
- **Role:** `title`, `department`, `team`, `employmentType` (full_time / part_time / contract / internship / temporary / other), `employmentTypeRaw`
- **Location:** `locations`, `location`, `country`, `workplaceType` (remote / hybrid / onsite), `isRemote`
- **Salary:** `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryText`
- **Dates:** `postedAt`, `postedDateApproximate`, `updatedAt`, `scrapedAt`
- **Links and text:** `url`, `applyUrl`, `description`

Each run also saves a **detection report** (the `COMPANIES` record in the key-value store), with one row per company: hiring system, how it was found, jobs found and saved, and any error. It's handy for checking a long list.

**Good to know:**

- Fields a company doesn't publish are `null`. Salary appears only where the company publishes it, which is most common on Ashby, Lever and Recruitee.
- Workday shows relative dates ("Posted 3 Days Ago"), so those `postedAt` values are approximate (`postedDateApproximate: true`).

### Pricing

**$1.50 per 1,000 jobs**, plus a tiny per-run start fee. No monthly rental.

- 500 jobs ≈ $0.75
- A daily monitor of 100 companies that returns ~40 new jobs a day ≈ $1.80/month

Set a **maximum cost per run** in the run options, and the Actor stops cleanly when it's reached.

### FAQ

**Is this legal?**
The Actor only reads public job postings (company and job information) through the job-board APIs and feeds that these hiring systems publish for job distribution. It checks each site's robots.txt before fetching, uses polite request rates, and collects no personal data. Use the data responsibly and in line with applicable terms and laws.

**Why isn't SmartRecruiters (or my company's ATS) supported?**
SmartRecruiters' robots.txt disallows automated access, so it's excluded. Other systems may be added; open an issue with the career page link.

**Why was a company not found?**
It may use an unsupported system, or load its job links with JavaScript (common with Workday). Paste the job board URL instead; the detection report tells you what happened.

**Can it run on a schedule?**
Yes. Turn on **Only new jobs since last run**, give the monitor a name, and add a **Schedule** in Apify Console. Connect Slack, Google Sheets, email or a webhook to receive new jobs automatically.

# Actor input Schema

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

One per line. Use a company website (stripe.com), a company name (Hugging Face), or a careers/job board URL (https://jobs.lever.co/palantir, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite). The hiring system is detected automatically.

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

Optional. Keep only jobs whose title contains at least one of these words (e.g. 'engineer', 'sales', 'data'). On Workday the search runs on Workday's side, which is much faster for large employers.

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

Optional. Keep only jobs whose location contains one of these (e.g. 'London', 'New York', 'Germany'). Add 'remote' to include remote jobs.

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

Optional. Keep only jobs in departments or teams containing one of these words (e.g. 'Engineering', 'Marketing').

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

Keep only jobs marked as fully remote.

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

Keep only jobs posted in the last N days. 0 = any date. (Workday shows relative dates such as '3 Days Ago', so its dates are approximate.)

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

Upper limit of jobs collected from each company before filters.

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

Add the full job description as clean text. Some systems need one extra request per job for this, so runs take longer.

## `platforms` (type: `array`):

Limit automatic detection to these systems. All are enabled by default.

## `guessFromCompanyName` (type: `boolean`):

When no careers link is found, try the company name as the job board name on each system and keep validated matches. Turn off if you only want boards found via URLs or the company's website.

## `onlyNewSinceLastRun` (type: `boolean`):

Return only jobs this Actor has not returned before in your account. Schedule it daily to get new openings (hiring signals) automatically.

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

Use a different name for each separate monitor so they track already-seen jobs independently.

## Actor input object example

```json
{
  "companies": [
    "stripe.com",
    "notion.so",
    "https://jobs.lever.co/palantir",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "Hugging Face"
  ],
  "keywords": [],
  "locations": [],
  "departments": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "maxJobsPerCompany": 1000,
  "includeDescription": false,
  "platforms": [
    "greenhouse",
    "lever",
    "ashby",
    "workday",
    "workable",
    "recruitee",
    "bamboohr",
    "personio",
    "teamtailor"
  ],
  "guessFromCompanyName": true,
  "onlyNewSinceLastRun": false,
  "monitorName": "default"
}
```

# Actor output Schema

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

No description

## `companies` (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 = {
    "companies": [
        "stripe.com",
        "notion.so",
        "https://jobs.lever.co/palantir",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "Hugging Face"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("upendra_11/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": [
        "stripe.com",
        "notion.so",
        "https://jobs.lever.co/palantir",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "Hugging Face",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("upendra_11/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": [
    "stripe.com",
    "notion.so",
    "https://jobs.lever.co/palantir",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "Hugging Face"
  ]
}' |
apify call upendra_11/ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

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