# Career Site Jobs Scraper: Greenhouse, Lever, Workday & ATS (`rs-automation-labs/career-site-jobs-scraper`) Actor

Get every open job from company career sites. Paste a domain, careers page or ATS link: Greenhouse, Lever, Ashby, Workday, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR are auto-detected. Salary, remote, location, description, filters and new-job monitoring.

- **URL**: https://apify.com/rs-automation-labs/career-site-jobs-scraper.md
- **Developed by:** [RS Automation Labs](https://apify.com/rs-automation-labs) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 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

### What does Career Site Jobs Scraper do?

**Career Site Jobs Scraper** pulls **every open job straight from company career sites** and their applicant tracking systems (ATS). Paste a company website such as `notion.so`, a careers page, or a job board link. The Actor finds the company's job board and returns each opening as one clean, normalized row: title, department, location, country, remote / hybrid / on-site, employment type, **salary**, posting date, apply link and the full description.

Supported ATS (auto-detected): **Greenhouse, Lever, Ashby, Workday, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor and BambooHR**, plus any careers page that publishes schema.org `JobPosting` data. Think of it as a **job board API** for thousands of employers: no login, no browser, no API keys.

Jobs come from the companies' **official public job feeds**, the same data their own careers pages show. So results are fresh (often hours old), complete, and include jobs that never reach LinkedIn or Indeed.

### Why use this career site job scraper?

- 🎯 **Recruiting & sourcing agencies** - watch target companies and get new openings before the job boards do.
- 📈 **Sales & lead generation** - hiring is a buying signal. Find companies hiring "Head of Data", "Salesforce admin" or "SOC analyst".
- 🧭 **Job seekers & job boards** - build a niche job board or a personal feed of remote engineering roles from your dream companies.
- 🔎 **Market & competitor intelligence** - track headcount plans, new offices, salary ranges and departments over time.
- 🤖 **AI agents & data pipelines** - normalized JSON with stable job keys, ready for RAG, matching or analytics.

**Highlights**

- Paste **domains, careers pages, ATS URLs or `ats:slug` shorthands**. The board is detected automatically.
- **One schema for every ATS**: normalized employment type, workplace type, ISO country, salary min/max/currency/period.
- **Salary extraction**: from structured ATS fields or parsed from the description (pay-transparency ranges).
- **Filters**: title keywords (include/exclude), location, country, remote/hybrid/on-site, employment type, posted in the last N days.
- **New-jobs monitor**: run it on a schedule and get only jobs that are **new since the last run**, plus free "closed" rows.
- **Fast and cheap**: public JSON APIs and no headless browser. A 300-job board takes about a second.
- Duplicate inputs, bad domains and companies without a board become **free status rows**, so one bad input never fails the run.
- All Apify platform features: scheduling, API, webhooks, Zapier / Make / n8n, Google Sheets and Slack integrations.

### What data can I extract from company career sites?

| Field | Example |
|---|---|
| `company` | Palantir |
| `title` | Forward Deployed Software Engineer, New Grad |
| `department` / `team` | Engineering |
| `location`, `city`, `region`, `country` | New York, NY · US |
| `workplaceType` / `remote` | remote · hybrid · onsite |
| `employmentType` | FULL_TIME · PART_TIME · CONTRACT · INTERNSHIP |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | 135000 · 145000 · USD · YEAR |
| `postedAt` | 2026-10-22T21:34:28Z |
| `jobUrl`, `applyUrl` | links to the posting and the application form |
| `descriptionText`, `descriptionHtml` | full job description |
| `atsSource`, `atsBoard`, `atsBoardUrl` | lever · palantir · https://jobs.lever.co/palantir |
| `boardJobCount` | open jobs on the whole board |
| `jobKey` | stable unique ID, e.g. `lever:palantir:6ed76ce8-...` |

### How to scrape jobs from company career sites

1. Click **Try for free** and open the **Input** tab.
2. Add companies to **Companies**, one per line: `notion.so`, `https://jobs.lever.co/palantir`, `greenhouse:airbnb`...
3. Optional: add **filters**, for example title contains `engineer` and workplace type `remote`.
4. Set **Max jobs per company** to keep the run small.
5. Click **Start** and download the jobs as JSON, CSV, Excel or HTML, or connect the dataset to Google Sheets.
6. Optional: turn on **Only new jobs** and add a **schedule** (for example daily) to get a new-jobs feed.

#### Which inputs work?

| Input | Example |
|---|---|
| Company domain | `notion.so`, `stripe.com` |
| Careers page | `https://www.example.com/careers` |
| ATS board URL | `https://boards.greenhouse.io/airbnb`, `https://jobs.ashbyhq.com/ramp`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` |
| Shorthand `ats:slug` | `greenhouse:airbnb`, `lever:palantir`, `ashby:ramp`, `smartrecruiters:BoschGroup`, `recruitee:bunq`, `workday:nvidia.wd5/NVIDIAExternalCareerSite` |

For domains, the Actor reads the homepage and careers page to find the ATS link. If there is none, it tries the company name on the public ATS APIs. When the job board link is known, pasting it directly is fastest and most reliable.

### How much does it cost to scrape career site jobs?

This Actor uses **pay-per-event** pricing: **$0.0015 per job returned ($1.50 per 1,000 jobs)**. There is **no start fee**, and **error rows, "no jobs" rows, duplicate inputs and closed-job rows are free**. Platform compute is minimal because the Actor calls public JSON APIs instead of a browser.

| Jobs returned | Price |
|---|---|
| 100 | $0.15 |
| 1,000 | $1.50 |
| 10,000 | $15.00 |

**Worked example:** checking 50 companies with a title filter that matches 20 jobs each returns 1,000 jobs = **$1.50**. Apify's free plan includes **$5 of monthly credit**, which covers about **3,300 jobs** a month.

To control cost:

- Use **filters** and **Max jobs per company**. You only pay for jobs that pass the filters.
- Use **Only new jobs** on scheduled runs. After the first run you pay only for jobs that are new.
- Set **Maximum cost per run** in the run options. The Actor stops cleanly when the limit is reached.

### Input example

```json
{
  "companies": ["notion.so", "https://jobs.lever.co/palantir", "greenhouse:airbnb"],
  "titleKeywords": ["engineer"],
  "workplaceTypes": ["remote", "hybrid"],
  "postedWithinDays": 30,
  "maxJobsPerCompany": 20,
  "includeDescription": true
}
```

See the **Input** tab for all options.

### Output example

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
[
  {
    "status": "ok",
    "company": "Notion",
    "companyDomain": "notion.so",
    "title": "Software Engineer, Developer Platform",
    "department": "Engineering",
    "location": "San Francisco, California",
    "country": "US",
    "workplaceType": "hybrid",
    "remote": false,
    "employmentType": "FULL_TIME",
    "salaryText": "$179,000 – $200,000 per year",
    "salaryMin": 179000,
    "salaryMax": 200000,
    "salaryCurrency": "USD",
    "salaryPeriod": "YEAR",
    "postedAt": "2026-10-19T17:28:06Z",
    "jobUrl": "https://jobs.ashbyhq.com/notion/8c0bf773-e536-45c9-9a6c-8ee478148cc8",
    "applyUrl": "https://jobs.ashbyhq.com/notion/8c0bf773-e536-45c9-9a6c-8ee478148cc8/application",
    "descriptionText": "WHO WE ARE\n\nNotion is the collaborative AI workspace ...",
    "atsSource": "ashby",
    "atsBoard": "notion",
    "atsDetection": "site-link",
    "boardJobCount": 140
  },
  {
    "status": "error",
    "input": "palantir.com",
    "errorCode": "DUPLICATE_INPUT",
    "errorMessage": "Same job board (lever:palantir) as input \"https://jobs.lever.co/palantir\" - read once, not charged twice"
  }
]
```

#### Row status

| `status` | Meaning | Charged |
|---|---|---|
| `ok` | One open job | yes |
| `closed` | Monitor mode: the job disappeared since the last run | free |
| `no-jobs` | The company was checked but has no (matching / new) jobs | free |
| `error` | See `errorCode`, `errorMessage` and `errorHint` | free |

Error codes: `INVALID_INPUT`, `DUPLICATE_INPUT`, `DOMAIN_NOT_FOUND`, `NO_ATS_FOUND`, `BOARD_NOT_FOUND`, `ATS_NOT_SUPPORTED`, `BLOCKED`, `NETWORK_ERROR`, `BAD_RESPONSE`, `TIMEOUT`, `BUDGET_LIMIT`, `INTERNAL_ERROR`.

The run summary (companies, jobs, ATS detected, error codes) is saved as `OUTPUT` in the default key-value store.

### New job alerts: monitor career pages for new jobs

Turn on **Only new jobs since the last run** and schedule the Actor (Schedules → daily). Each run returns only jobs that were not returned before, plus a free `closed` row for every job that was removed. Job history lives in a named key-value store `jobs-feed-monitor-<monitor name>` in your account. Use a different **Monitor name** per task or filter set. Connect a webhook, Slack, email or Google Sheets integration to get alerts.

### Tips

- **Paste the job board URL** if you know it. It skips website discovery and is the most reliable input.
- Workday boards list jobs 20 at a time and need one extra request per job for the description. Use filters and **Max jobs per company** for very large employers.
- Turn off **Include full job description** for faster, smaller exports.
- No proxy is needed for ATS APIs. Enable Apify Proxy only if a company website blocks discovery.

### Use it via API, Python, JavaScript or an AI agent

Every run is available through the [Apify API](https://docs.apify.com/api/v2). Start a run, wait for it to finish and read the dataset in a few lines of Python with the official [`apify-client`](https://docs.apify.com/api/client/python) package:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("rs-automation-labs/career-site-jobs-scraper").call(run_input={
        "companies": [
            "notion.so",
            "https://jobs.lever.co/palantir",
            "greenhouse:airbnb"
        ],
        "maxJobsPerCompany": 20
    })
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

- **JavaScript / cURL:** the **API** tab on this page has ready-to-copy snippets with your token filled in.
- **Schedules and webhooks:** run it daily or weekly with [Apify Schedules](https://docs.apify.com/platform/schedules) and get notified with [webhooks](https://docs.apify.com/platform/integrations/webhooks).
- **No-code:** connect it to Make, Zapier, n8n, Google Sheets or Slack through [Apify integrations](https://apify.com/integrations).
- **AI agents:** call it from Claude, ChatGPT, Cursor or any MCP client through the [Apify MCP server](https://mcp.apify.com).

### FAQ

**Is it legal to scrape company career sites?**
This Actor reads only public job postings that companies publish to attract applicants, using the ATS providers' public job-board endpoints. It does not log in and does not collect personal data about candidates or employees. Our Actors are ethical and do not extract private user data. Your results could still contain personal data, such as a recruiter's name inside a description, which is protected by GDPR and similar laws. Don't use it without a legitimate reason, and consult your lawyers if unsure.

**Which ATS are not supported?**
iCIMS, Taleo, SuccessFactors, Jobvite and other systems without a public feed are reported as `ATS_NOT_SUPPORTED` (free). Their careers pages are still read if they publish schema.org JobPosting data.

**Why did a domain return `NO_ATS_FOUND`?**
The website does not link a supported job board and the company name did not match one. Paste the careers page or job board URL instead.

**Can I use it through the API?**
Yes. See the **API** tab for Python, JavaScript, cURL, and MCP examples for AI agents.

### Other Actors by RS Automation Labs

| Actor | What it does |
|---|---|
| [PageSpeed Insights Bulk Checker](https://apify.com/rs-automation-labs/bulk-pagespeed-core-web-vitals-monitor) | Bulk Lighthouse scores and real-user Core Web Vitals for many URLs or a sitemap |
| [Video Transcript & AI Summary](https://apify.com/rs-automation-labs/video-transcripts-ai-summaries) | Transcripts, subtitles and AI summaries for YouTube, TikTok, Reels, X and podcasts |
| [AI PDF to JSON & Invoice OCR](https://apify.com/rs-automation-labs/ai-document-extractor) | Invoices, receipts, bank statements and any PDF or scan to validated JSON, CSV and Excel |
| [AI Search Visibility & GEO Rank Tracker](https://apify.com/rs-automation-labs/ai-search-visibility-checker) | Whether ChatGPT, Perplexity, Gemini, Claude, Grok and AI Overviews mention and cite your brand |
| [Contact Details Scraper & Company Enrichment](https://apify.com/rs-automation-labs/contact-details-company-enrichment) | E-mails, phones, socials, tech stack and hiring signals from a company domain |

### Support

Found a bug or need another ATS? Open an issue on the **Issues** tab and include the run ID. Feature requests are welcome. Built and maintained by RS Automation Labs.

# Changelog

This Actor's version history is a separate document: https://apify.com/rs-automation-labs/career-site-jobs-scraper/changelog.md

# Actor input Schema

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

One per line. Any of: a company domain (notion.so), a careers page (https://www.example.com/careers), a job board URL (https://jobs.lever.co/palantir, https://boards.greenhouse.io/airbnb, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite) or a shorthand 'ats:slug' (greenhouse:airbnb, lever:palantir, ashby:ramp, workday:nvidia.wd5/NVIDIAExternalCareerSite).

## `titleKeywords` (type: `array`):

Keep only jobs whose title contains at least one of these words, e.g. 'engineer', 'data', 'sales'. Case-insensitive. Leave empty for all jobs.

## `excludeTitleKeywords` (type: `array`):

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

## `locationKeywords` (type: `array`):

Keep only jobs whose location mentions one of these, e.g. 'London', 'New York', 'Germany', 'remote'.

## `countries` (type: `array`):

Keep only jobs in these countries, as 2-letter ISO codes: US, GB, DE, IN... Jobs whose country cannot be detected are dropped when this is set.

## `workplaceTypes` (type: `array`):

Keep only remote, hybrid and/or on-site jobs. Empty = all.

## `employmentTypes` (type: `array`):

Keep only these employment types. Jobs whose board does not publish a type are kept.

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

Keep only jobs posted in the last N days, e.g. 7. Jobs without a published date are kept. Empty = any date.

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

Upper limit of returned jobs per company (newest first). Keeps cost predictable for very large employers.

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

Adds descriptionText and descriptionHtml. Turn off for smaller, faster output (for SmartRecruiters and Workday this also saves one request per job).

## `includeCompanyStatusRows` (type: `boolean`):

Adds one free row (status 'no-jobs') when a company currently has no matching jobs, so you can see it was checked. Error rows are always added and are free.

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

Remembers which jobs were already returned and outputs only NEW ones on the next run. Ideal with a schedule (daily new-job alerts). The first run returns all matching jobs.

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

Separate job histories for separate tasks, e.g. 'competitors' or 'clients-eu'. Letters, digits and dashes. Stored in the named key-value store 'jobs-feed-monitor-<name>' in your account.

## `includeClosedJobs` (type: `boolean`):

In monitor mode, adds a free row (status 'closed') for every job that disappeared from the board since the last run.

## `probeAtsBoards` (type: `boolean`):

If the company's website and careers page do not link an ATS, try the company name on the public Greenhouse, Lever, Ashby, Workable and other job board APIs.

## `respectRobotsTxt` (type: `boolean`):

Skip company web pages that robots.txt disallows (ATS job APIs are always public).

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

How many companies are processed at the same time.

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

Not needed for most companies (job boards are public APIs). Turn on Apify Proxy if a company website blocks the default connection.

## Actor input object example

```json
{
  "companies": [
    "notion.so",
    "https://jobs.lever.co/palantir",
    "greenhouse:airbnb"
  ],
  "titleKeywords": [
    "engineer",
    "data"
  ],
  "excludeTitleKeywords": [
    "intern"
  ],
  "locationKeywords": [
    "remote",
    "London"
  ],
  "countries": [
    "US",
    "GB"
  ],
  "workplaceTypes": [
    "remote",
    "hybrid"
  ],
  "employmentTypes": [
    "FULL_TIME"
  ],
  "postedWithinDays": 7,
  "maxJobsPerCompany": 20,
  "includeDescription": true,
  "includeCompanyStatusRows": true,
  "onlyNewJobs": false,
  "monitorName": "default",
  "includeClosedJobs": true,
  "probeAtsBoards": true,
  "respectRobotsTxt": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Company, title, location, remote, salary, posting date and links.

## `details` (type: `string`):

All fields including the job description.

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

Companies processed, jobs returned, ATS detected and error codes.

# 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": [
        "notion.so",
        "https://jobs.lever.co/palantir",
        "greenhouse:airbnb"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("rs-automation-labs/career-site-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": [
        "notion.so",
        "https://jobs.lever.co/palantir",
        "greenhouse:airbnb",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("rs-automation-labs/career-site-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": [
    "notion.so",
    "https://jobs.lever.co/palantir",
    "greenhouse:airbnb"
  ],
  "maxJobsPerCompany": 20
}' |
apify call rs-automation-labs/career-site-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rs-automation-labs/career-site-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/6XbgGnoH7cnXEQfsO/builds/4IQOHt7gaFBJIgHJF/openapi.json
