# Career Page Jobs Scraper: Name or Domain, Workday + 10 ATS (`scrapewise/ats-jobs-scraper`) Actor

Get every open job of a company from its name, website or careers link. 11 ATS in one run: Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Breezy, BambooHR, Rippling. Salary, remote, full description, daily only-new mode. Errors free.

- **URL**: https://apify.com/scrapewise/ats-jobs-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (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.85 / 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

## Career Page Jobs Scraper: company name or domain, Workday and 10 more ATS, daily only-new mode

Type a **company name** (`Hugging Face`), its **website** (`stripe.com`) or paste its **careers page or job board
link**, and get every open job in one table. The Actor finds the board for you across **11 applicant tracking
systems**: Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Breezy HR, BambooHR and
Rippling. Each row has title, department, location, remote, employment type, **salary range as numbers** when the
company publishes it, posting date, apply link and the full description. No account, no API key, no browser.

Built for **job feeds and hiring signals**: schedule it daily with `onlyNew` and every run brings only the jobs that
appeared since the last run, plus a free list of jobs that closed. Large Workday sites (10,000+ openings) are read
completely: the Actor splits the list by location and category facets to get past the 2,000-result cap of the
Workday search.

### At a glance

- **Price per 1,000 jobs, Free plan:** US$ 1.00 (US$ 0.85 on Gold and above)
- **Fee per run start:** US$ 0.01
- **ATS covered:** Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Breezy HR,
  BambooHR and Rippling, one output format for all eleven
- **Input:** company name, website, careers page, job board link or bare token; the ATS is detected for you
- **Salary as numbers:** from the board when the ATS has it (Greenhouse, Lever, Ashby, Recruitee, Rippling), otherwise
  read from the description (`salaryText`)
- **Filters:** title keywords, excluded words, locations, remote only, departments, posted within N days
- **Only new jobs since the last run (`onlyNew`):** Yes, plus closed jobs in a free `CLOSED_JOBS` record
- **Error rows (unknown token, empty board, no match, timeout too short):** Free, with an `errorCode`

### One real row

From a test run on 2026-10-09 (`https://jobs.ashbyhq.com/ramp`), description shortened:

```json
{
  "type": "job",
  "ats": "ashby",
  "company": "ramp",
  "jobId": "530d1596-c1bf-41aa-9915-548a692ed66e",
  "title": "Manager, Sales Development, Public Sector",
  "url": "https://jobs.ashbyhq.com/ramp/530d1596-c1bf-41aa-9915-548a692ed66e",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/530d1596-c1bf-41aa-9915-548a692ed66e/application",
  "department": "Sales",
  "team": "SDR",
  "employmentType": "full_time",
  "location": "New York, NY (HQ)",
  "locations": ["New York, NY (HQ)", "San Francisco, CA", "Remote (US)"],
  "country": "USA",
  "isRemote": true,
  "workplaceType": "hybrid",
  "salaryMin": 166000,
  "salaryMax": 254000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salaryText": "$166K - $254K",
  "salarySource": "structured",
  "postedAt": "2026-10-09T19:14:11Z",
  "descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams...",
  "scrapedAt": "2026-10-09T22:07:12Z"
}
```

A Workday job from the same test (NVIDIA) came with `"salaryText": "... The hourly rate for our interns is 20 USD - 71
USD."`, `"salaryMin": 20`, `"salaryMax": 71`, `"salaryInterval": "hour"`, `"salarySource": "description"`,
`"requisitionId": "JR2026839"` and `"country": "United States of America"`.

### What you can do with it

- **Job boards and newsletters:** a daily feed of new jobs from hundreds of companies, already normalized.
- **Recruiters and sales teams:** hiring signals (who opened engineering or sales roles this week, where, at what pay).
- **Job seekers:** a daily alert for remote engineering jobs at the companies you follow.
- **Salary research:** pay ranges by title, location and company, as numbers ready for a spreadsheet.
- **Market and investment research:** headcount plans by department, new offices, hiring freezes (closed jobs).
- **AI agents and RAG:** clean job descriptions in plain text, one format for eleven ATS; an agent can pass a
  company name and get its jobs.

### Input

| Field | What it does |
|---|---|
| `companies` | One per line: company name, website, careers page, job board link or board token. Mix ATS freely |
| `ats` | ATS for names and bare tokens: `auto` (default, tries the 10 list ATS at once), or force one |
| `keywords` | Keep jobs whose title contains one of these words or phrases |
| `excludeKeywords` | Drop jobs whose title contains one of these words |
| `locations` | Keep jobs in one of these places (city, state, country, `US`, `remote`) |
| `remoteOnly` | Keep remote jobs only |
| `departments` | Keep jobs whose department or team matches; on Workday, the site's own job categories |
| `postedWithinDays` | Keep jobs posted in the last N days |
| `maxItems` | Jobs per company, newest first, default 25. 0 = every open job |
| `includeDescription` | Full description in text and HTML (default on). Off = lighter rows, faster Workday |
| `onlyNew` | Deliver only jobs that appeared since the last run with the same companies and filters |
| `stateName` | Separate memory for a Task (only with `onlyNew`) |
| `maxConcurrency` | Parallel requests per Workday site, 1 to 8 (default 6) |

Accepted company formats:

| ATS | Examples |
|---|---|
| Greenhouse | `figma`, `https://job-boards.greenhouse.io/figma`, `https://boards.greenhouse.io/airbnb`, `greenhouse:databricks` |
| Lever | `zoox`, `https://jobs.lever.co/zoox`, `lever:spotify` |
| Ashby | `ramp`, `https://jobs.ashbyhq.com/ramp`, `ashby:openai` |
| Workday | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` (copy the job list address; `/en-US/` is fine) |
| SmartRecruiters | `https://jobs.smartrecruiters.com/BoschGroup`, `smartrecruiters:Visa` |
| Workable | `https://apply.workable.com/huggingface/`, `workable:huggingface` |
| Recruitee | `https://bunq.recruitee.com`, `recruitee:bunq` |
| Personio | `https://ottonova.jobs.personio.de` (also `.jobs.personio.com`) |
| Breezy HR | `https://telespazio-be.breezy.hr` |
| BambooHR | `https://prezi.bamboohr.com/careers` |
| Rippling | `https://ats.rippling.com/rippling/jobs` |
| Company name | `Hugging Face`, `Bosch Group`, `bunq`: tried on the 10 list ATS at once (Workday needs its link) |
| Website or careers page | `stripe.com`, `https://www.duolingo.com/careers`: the Actor opens the page (and `/careers`, `/jobs` for a bare domain) and finds the board link |

Example: remote engineering jobs posted this week at five companies, every morning:

```json
{
  "companies": ["stripe", "https://jobs.lever.co/zoox", "https://jobs.ashbyhq.com/openai", "ramp",
                "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],
  "keywords": ["engineer", "developer"],
  "remoteOnly": true,
  "postedWithinDays": 7,
  "maxItems": 0,
  "onlyNew": true
}
```

### How only-new works

The Actor keeps one memory per board and filter set in a key-value store in your own account,
`ats-jobs-scraper-state`.

- **First run:** delivers up to `maxItems` per company (newest first) and remembers the **whole board** as seen. Set
  `maxItems` to 0 on the first run if you also want every job that is open today.
- **Later runs:** deliver only jobs that were not on the board before. A run with nothing new delivers nothing and
  only the run start is charged.
- **Closed jobs:** jobs that left the board since the last run are listed in the run's `CLOSED_JOBS` key-value
  record (board and job id), free.
- On Workday the job list is read first (cheap) and the job page is opened only for new jobs.
- Two Tasks with the same companies and filters share their memory; give each its own `stateName` to keep them
  apart. Delete the store to start over.

### Output

Every job row: `ats`, `company` (board token or Workday tenant), `companyName` (when the ATS gives it), `jobId`, `title`, `url`,
`applyUrl`, `department`, `team`, `employmentType` (`full_time`, `part_time`, `contract`, `internship`,
`temporary`, or the board's own text), `location`, `locations` (all of them), `country`, `isRemote`, `workplaceType`
(`remote`, `hybrid`, `onsite`), `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval` (`year`, `month`,
`week`, `day`, `hour`), `salaryText`, `salarySource` (`structured` or `description`), `salaryRanges` (every range
when a board lists several, for example by country), `postedAt` (UTC), `postedText` (Workday's "Posted 3 Days Ago"),
`updatedAt` (Greenhouse), `requisitionId`, `descriptionText`, `descriptionHtml`, `isNew` and `firstSeenAt` (with
`onlyNew`), `input`, `scrapedAt`.

What each ATS gives:

| Field | Greenhouse | Lever | Ashby | Workday |
|---|---|---|---|---|
| Salary min/max | Yes, when the company publishes it | Yes, when published | Yes, when published | From the description text |
| Remote | Location and workplace type | Workplace type | Remote flag | Location and remote type |
| Department / team | Department | Department and team | Department and team | Job category (with `departments`) |
| Posting date | Exact | Exact | Exact | Exact from the job page, approximate from the list |

| Field | SmartRecruiters | Workable | Recruitee | Personio | Breezy HR | BambooHR | Rippling |
|---|---|---|---|---|---|---|---|
| Salary | From the description | From the description | Yes, when published | From the description | Yes, as text | From the description | Yes, when published |
| Remote | Remote and hybrid flags | Remote flag | Remote and hybrid flags | From the location | Remote flag | Remote flag | From the location |
| Posting date | Exact | Day | Exact | Exact | Exact | Day (with description on) | Exact (with description on) |

SmartRecruiters, Breezy HR, BambooHR and Rippling give the description only on the job page, so the Actor opens the
page only for the jobs it delivers (none with `includeDescription` off).

### Error codes (never charged)

| `errorCode` | Meaning |
|---|---|
| `INVALID_INPUT` | A line that is not a name, link or token, a Workday link without the site name, or a bad option |
| `NOT_FOUND` | No board with this token (the row says where to look), a wrong Workday site name, or no board on the page |
| `EMPTY_BOARD` | The board exists but has no open jobs, or the company moved to another ATS |
| `NO_RESULTS` | The board has jobs, none matches your filters (Workday lists its job categories) |
| `BLOCKED` | The site did not answer after several attempts; run again |
| `TIMEOUT_TOO_SHORT` | The run timeout was too short to start; raise it |
| `UNEXPECTED` | Something we did not expect on one board; the other boards go on |

### Pricing

| Event | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Job delivered, per 1,000 | US$ 1.00 | US$ 0.95 | US$ 0.90 | US$ 0.85 |
| Run start | US$ 0.01 | US$ 0.0095 | US$ 0.009 | US$ 0.0085 |

A daily `onlyNew` run over 50 companies that finds 40 new jobs costs about US$ 0.05. Error rows, duplicates,
filtered-out jobs and jobs already delivered are free. The description is included at no extra cost.

### Limitations

- Only public job boards: no login, no internal job boards, no candidate data.
- Workday sites show at most 20 jobs per page and 2,000 per search. Larger sites are read in slices by the site's
  own job categories, so every job is reached. With the description on, a site of a few thousand jobs takes a few
  minutes; turn `includeDescription` off or use filters to go faster.
- Workday has no department field; `departments` uses each site's own job categories.
- Salary is what the company publishes. On Workday it is read from the description, so a few formats may be missed;
  `salaryText` always shows the sentence it came from.
- Companies change ATS; a token that worked last month may return `EMPTY_BOARD` or `NOT_FOUND`.

### FAQ

**Do I need the board token?** No. Type the company name or its website and the Actor looks for the board. If a
name is ambiguous, paste the job board link instead (for example `jobs.lever.co/<token>` or
`<company>.recruitee.com`).

**Which companies use Workday?** Thousands of large employers, for example NVIDIA, Salesforce, Walmart, Adobe, Intel
and Target. If the careers page address contains `myworkdayjobs.com` or `myworkdaysite.com`, paste it as is.

**My Workday link does not work.** Open the company job list in the browser and copy the address from the bar. It
must include the site name after the domain, for example `.../NVIDIAExternalCareerSite`. It is case sensitive.

**Can I use it from n8n, Make, Zapier or an AI agent?** Yes, through the Apify app or the Apify MCP server. Error rows
are free, so an agent can try tokens cheaply.

**What if a run is cut by its timeout?** The Actor stops shortly before the limit and ends successfully with what it
delivered, and the status message says how to get the rest.

### Changelog

- **0.2.0 (2026-10-19):** 7 more ATS (SmartRecruiters, Workable, Recruitee, Personio, Breezy HR, BambooHR,
  Rippling); company name and bare domain as input (`Hugging Face`, `stripe.com`); the job page is opened only for
  delivered jobs on the ATS that need it.
- **0.1.7 (2026-10-16):** price cut to US$ 1.00 per 1,000 jobs (from US$ 5.00); Workday-first description.
- **0.1 (2026-10-10):** first version. Greenhouse, Lever, Ashby and Workday in one run; career URL or token with
  auto-detection; title, location, remote, department and date filters; structured salary and Workday `salaryText`;
  `onlyNew` with closed jobs; free error rows.

# Actor input Schema

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

One company per line, in any of these forms: the company name ('Hugging Face', 'Stripe'), its website (stripe.com: the Actor opens the site and its /careers page to find the board), the careers page URL, or the job board link of any of the 11 ATS (job-boards.greenhouse.io/figma, jobs.lever.co/zoox, jobs.ashbyhq.com/ramp, <company>.wd5.myworkdayjobs.com/<site>, jobs.smartrecruiters.com/<company>, apply.workable.com/<company>, <company>.recruitee.com, <company>.jobs.personio.de, <company>.breezy.hr, <company>.bamboohr.com/careers, ats.rippling.com/<company>). 'greenhouse:stripe' forces one ATS. Empty = example. Also accepts 'startUrls'.

## `ats` (type: `string`):

Which ATS a company name or bare token (like 'stripe') belongs to. Auto-detect (default) tries all 10 list ATS at the same time and keeps the board with jobs. Links always use their own ATS; Workday always needs its link.

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

Keep only jobs whose title contains at least one of these words or phrases, for example engineer, data scientist or product manager. Case and accents are ignored. Empty = every job.

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

Drop jobs whose title contains any of these words, for example intern, senior or manager.

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

Keep only jobs in one of these places, matched against every location of the job and its country, for example New York, London, Germany, US or remote. Short codes (US, UK, CA) match whole words only. Empty = everywhere.

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

Keep only remote jobs: Ashby's remote flag, Lever's and Greenhouse's workplace type, Workday's remote type, or 'remote' in the job location.

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

Keep only jobs whose department or team contains one of these words, for example Engineering, Sales or Marketing. On Workday it matches the site's own job categories.

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

Keep only jobs posted in the last N days, for example 7. Empty = any date. Workday shows dates as 'Posted 3 Days Ago'; the exact date comes from the job page.

## `maxItems` (type: `integer`):

Stop each company after this many jobs, newest first, for example 25 (default). 0 = every open job. You pay per job delivered, so this caps the cost of each company.

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

On (default): every job comes with the full description in plain text and HTML, and Workday salaries are read from it (salaryText, salaryMin, salaryMax). Off: lighter rows; on Workday it skips one request per job.

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

For scheduled runs. The first run delivers up to 'Max jobs per company' and remembers the whole board (with your filters) in a key-value store in your account ('ats-jobs-scraper-state'). Later runs deliver only jobs that appeared since; a run with nothing new delivers nothing. Jobs that closed since the last run are listed in the run's CLOSED_JOBS record, free. Delete the store to start over.

## `stateName` (type: `string`):

Only with 'Only new jobs'. Tasks with the same companies and filters share their memory; give each Task its own name here (for example team-a) to keep them apart.

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

Requests in parallel to one Workday site, 1 to 8 (default 6). Lower it if a site answers 429 (too many requests).

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

Requests go straight to the public job board APIs. Apify Proxy (default group) is used only if a site refuses them, with no extra charge. Change it only to use your own proxies.

## Actor input object example

```json
{
  "companies": [
    "Hugging Face",
    "stripe.com",
    "https://jobs.lever.co/zoox",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "ats": "auto",
  "remoteOnly": false,
  "maxItems": 25,
  "includeDescription": true,
  "onlyNew": false,
  "maxConcurrency": 6,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

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

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

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

```

## MCP server setup

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