# Workday Jobs Scraper & API — Any Career Site + New-Job Alerts (`wowlab/workday-jobs-scraper`) Actor

Scrape every open job from any Workday career site (myworkdayjobs.com): title, location, remote type, job category, posted date, description and parsed salary. Many companies per run, keyword/location/remote/date filters, beats the 2,000-job cap, new & changed job alerts. No login.

- **URL**: https://apify.com/wowlab/workday-jobs-scraper.md
- **Developed by:** [Erwinbooze Ricardo](https://apify.com/wowlab) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

## Workday Jobs Scraper & API — Any Career Site + New-Job Alerts

**Workday Jobs Scraper** extracts every open job from any company career site hosted on **Workday** (`*.myworkdayjobs.com` and `*.myworkdaysite.com`): NVIDIA, Salesforce, Red Hat, Mastercard, CrowdStrike, Zendesk, Workday itself, and thousands of other enterprises, banks, hospitals, universities and government employers that recruit with Workday.

It reads the same public JSON data that the Workday careers page loads in your browser — **no login, no browser, no proxy, no cookies** — so runs are fast, cheap and stable. Paste one or hundreds of career site URLs and get clean, structured job data: title, company, locations, country, remote / hybrid type, job category, time type, posting date, full description, apply URL and **parsed salary ranges** (min, max, currency, period) wherever the employer publishes pay.

### Why this Workday scraper?

- ✅ **Any Workday company** — paste the careers URL; data centre (`wd1`, `wd3`, `wd5`, `wd12`, `wd103`…) and site are handled for you. A bare tenant name like `workday` or `crowdstrike` is auto-detected (best effort).
- ✅ **Beats the 2,000-job limit** — Workday's own search stops at 2,000 results. Large employers are automatically split by job category / location, so you get *every* job (e.g. 2,700+ NVIDIA jobs in one run).
- ✅ **Salaries** — pay ranges parsed from the description: `$218,400 - $365,200 annually`, `£60k–£75k`, `$40–$45/hour`, with currency and period (YEAR / MONTH / HOUR).
- ✅ **New-job alerts** — monitoring mode outputs only **new**, optionally **changed** and **removed** (filled / closed) jobs since the last run. Schedule it and connect Slack, email, Google Sheets or a webhook.
- ✅ **Filters** — Workday search text, title keywords, locations, job categories, remote only, posted within N days, max jobs per company.
- ✅ **Many companies per run** with per-company error reporting: a wrong URL never fails the whole run (see `RUN_SUMMARY`).
- ✅ **Polite and robust** — rate limiting per host, automatic retries and back-off on HTTP 429 / 5xx.
- ✅ **AI-agent ready** — clear input fields with safe defaults, clean JSON with plain-text descriptions; works through the **Apify MCP server** in Claude, ChatGPT, Cursor and other agents.

### What can you use it for?

- **Job boards & aggregators** — feed fresh enterprise jobs that never appear on Greenhouse or Lever.
- **Sales & recruiting intelligence (lead generation)** — see which companies are hiring, for which teams, in which countries; hiring spikes are strong buying signals.
- **Salary benchmarking** — collect published pay ranges by role, location and company.
- **Job alerts for yourself** — "tell me when NVIDIA posts a new remote ML job".
- **Market research & HR analytics** — track headcount growth, new offices, remote-work share.
- **LLM / RAG pipelines** — plain-text descriptions ready for classification and matching.

### How to find a company's Workday career site URL

Open the company's careers page, click *Search jobs* / *View all jobs*. If the address looks like
`https://COMPANY.wd5.myworkdayjobs.com/en-US/SiteName` (or `https://wd3.myworkdaysite.com/recruiting/company/SiteName`) — that's it, paste it. A link to a single job on that site works too.

Accepted formats:

| Input | Example |
|---|---|
| Career site URL | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` |
| With language / job path | `https://salesforce.wd12.myworkdayjobs.com/en-US/External_Career_Site/job/...` |
| myworkdaysite.com URL | `https://wd3.myworkdaysite.com/recruiting/company/Careers` |
| Shorthand | `redhat.wd5/jobs` or `redhat/jobs` |
| Tenant name only (auto-detect) | `workday`, `crowdstrike` |
| Custom company name | `Red Hat | https://redhat.wd5.myworkdayjobs.com/jobs` |

### Input examples

**All jobs from several companies (fast list, no descriptions):**

```json
{
  "careerSites": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://redhat.wd5.myworkdayjobs.com/jobs",
    "https://zendesk.wd1.myworkdayjobs.com/zendesk"
  ],
  "includeJobDetails": false,
  "maxJobs": 0
}
```

**US engineering jobs posted this week, with salaries:**

```json
{
  "careerSites": [
    "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site",
    "https://mastercard.wd1.myworkdayjobs.com/CorporateCareers"
  ],
  "searchText": "engineer",
  "locations": ["United States"],
  "departments": ["Engineering"],
  "postedWithinDays": 7
}
```

**Daily new-job alerts (schedule this run):**

```json
{
  "careerSites": ["https://crowdstrike.wd5.myworkdayjobs.com/crowdstrikecareers"],
  "remoteOnly": true,
  "onlyNewJobs": true,
  "includeRemovedJobs": true,
  "skipExistingOnFirstRun": true,
  "monitoringStoreName": "crowdstrike-remote-alerts"
}
```

#### Input fields

| Field | Default | Description |
|---|---|---|
| `careerSites` | – | **Required.** Workday career site URLs, shorthands or tenant names. |
| `searchText` | "" | Workday's own full-text search (like the search box). |
| `keywords` | \[] | Keep jobs whose title contains any keyword. |
| `locations` | \[] | Country / city / region, matched to Workday location filters or job locations. |
| `departments` | \[] | Workday job categories / job families, e.g. `Engineering`. |
| `remoteOnly` | false | Remote jobs only. |
| `postedWithinDays` | 0 | Posted in the last N days (0 = any). |
| `includeJobDetails` | true | Description, salary, exact date, country, time type (1 extra request per job). |
| `includeDescriptionHtml` | false | Also return the description HTML. |
| `onlyNewJobs` | false | Monitoring mode: only jobs not seen before. |
| `includeChangedJobs` / `includeRemovedJobs` | false | Also output changed / removed jobs in monitoring mode. |
| `skipExistingOnFirstRun` | false | First monitoring run only saves a baseline. |
| `monitoringStoreName` | workday-jobs-monitor | Named key-value store for monitoring state. |
| `dedupe` | true | Drop duplicate jobs. |
| `splitLargeSites` | true | Get more than 2,000 jobs per site. |
| `maxJobsPerCompany` | 0 | Limit per career site (0 = no limit). |
| `maxJobs` | 1000 | Limit per run (0 = no limit). |
| `maxConcurrency` | 4 | Parallel requests per Workday host. |

### Output

One dataset item per job (JSON, CSV, Excel, XML, HTML or RSS). Example (description shortened):

```json
{
  "jobId": "JR365295",
  "jobPostingId": "Software-Engineering-Architect---Digital-Marketing-Technology_JR365295",
  "requisitionId": "JR365295",
  "title": "Software Engineering Architect — Digital Marketing Technology",
  "companyName": "Salesforce",
  "ats": "workday",
  "tenant": "salesforce",
  "careerSite": "External_Career_Site",
  "careerSiteUrl": "https://salesforce.wd12.myworkdayjobs.com/en-US/External_Career_Site",
  "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site/job/Washington---Seattle/Software-Engineering-Architect---Digital-Marketing-Technology_JR365295",
  "applyUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site/job/Washington---Seattle/Software-Engineering-Architect---Digital-Marketing-Technology_JR365295/apply",
  "location": "Washington - Seattle",
  "locations": ["Washington - Seattle", "California - Palo Alto", "Illinois - Chicago", "New York - New York", "Indiana - Indianapolis", "California - San Francisco"],
  "country": "United States of America",
  "countryCode": "US",
  "isRemote": false,
  "workplaceType": "Office Tech-Flexible",
  "departments": [],
  "timeType": "Full time",
  "postedOn": "Posted Yesterday",
  "postedDaysAgo": 1,
  "firstPublished": "2026-10-29",
  "canApply": true,
  "salaryMin": 218400,
  "salaryMax": 365200,
  "salaryCurrency": "USD",
  "salaryPeriod": "YEAR",
  "salarySource": "description",
  "salaryText": "The typical base salary range for this position is $218,400 - $365,200 annually.",
  "descriptionText": "To get the best candidate experience, please consider applying for...",
  "scrapedAt": "2026-10-30T10:48:49.450Z"
}
```

Field notes:

- `departments` = Workday job category / job family (filled when the site exposes a category filter or you filter by department).
- `salary*` fields are `null` when the employer publishes no pay; `salaryRanges` lists all ranges found (e.g. different cities).
- `changeType` (`NEW` / `CHANGED` / `REMOVED`) appears only in monitoring mode.
- With `includeJobDetails: false` you get the fast listing fields only (title, location, remote, category, posted, URL).

A **`RUN_SUMMARY`** record in the default key-value store reports, per career site: status (`ok`, `not_found`, `error`), jobs on site, jobs listed, matched and saved, whether the crawl was complete, warnings (e.g. a department filter that matched nothing, with the available categories) and request statistics.

### Pricing

Pay per result: you pay only for jobs saved to the dataset (see the Pricing tab), no monthly rental. A full listing-only run of a 2,000-job company takes about a minute. Set *Max jobs* or your *maximum cost per run* to stay in budget — the Actor stops cleanly at that limit.

### Job alerts & integrations (Slack, email, Sheets, Make, n8n, Zapier)

1. Run once with `onlyNewJobs: true` and `skipExistingOnFirstRun: true` to save the baseline.
2. Create a **Schedule** (e.g. every morning).
3. Add an integration: Slack / email / Google Sheets in the Integrations tab, or a **webhook** on *Run succeeded* that pulls `…/datasets/{defaultDatasetId}/items`.

The Actor works with **Make**, **n8n**, **Zapier**, **Pipedream**, the Apify API, and the Python / JavaScript clients:

```bash
curl -X POST "https://api.apify.com/v2/acts/wowlab~workday-jobs-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"careerSites":["https://redhat.wd5.myworkdayjobs.com/jobs"],"searchText":"python","maxJobs":50}'
```

### Use it from AI agents (MCP)

Add the Actor to the **Apify MCP server** (`https://mcp.apify.com?tools=wowlab/workday-jobs-scraper`) and ask your agent things like *"List remote security engineering jobs CrowdStrike posted this week with salaries"*. Inputs have safe defaults (max 1,000 jobs per call), and the agent only pays per result.

### Other ATS scrapers

Need Greenhouse, Lever or Ashby boards too? See our **Greenhouse Jobs Scraper**, **Lever Jobs Scraper** and **Ashby Jobs Scraper** — same output format, so you can merge the data.

### FAQ

**Do I need a Workday account or proxy?** No. Only publicly visible job postings are read, through the same JSON the careers page uses.

**Why did a tenant name fail?** Some companies use an unusual site name (e.g. `external_experienced`). Paste the full career site URL instead — it always works.

**Can it get more than 2,000 jobs from one company?** Yes, `splitLargeSites` (on by default) splits big sites by job category and location filters. If a site cannot be split far enough, `RUN_SUMMARY` says so.

**Does it return internal / employee-only jobs?** No, only jobs on the public external career site you provide.

**Is it legal?** The Actor collects publicly available job postings, without logging in. Job ads contain no personal data beyond what employers publish; you are responsible for using the data in line with applicable laws and the sites' terms.

**Something missing?** Open an issue on the Issues tab — fixes are usually quick.

# Actor input Schema

## `careerSites` (type: `array`):

One entry per company. Best: paste the company's Workday careers URL, e.g. `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` (language prefixes like /en-US/ and job URLs also work). Also accepted: `tenant.wd5/Site` shorthand, `wd3.myworkdaysite.com/recruiting/tenant/Site` URLs, or just a tenant name like `workday` (the data centre and site name are then auto-detected — best effort). Optional `Company Name | URL` sets the companyName field.

## `searchText` (type: `string`):

Free-text search sent to Workday's own search (same as the search box on the careers page), e.g. `data engineer`. Leave empty for all jobs.

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

Keep only jobs whose title contains at least one of these words (case-insensitive), e.g. `senior`, `python`. Applied after Workday search. Empty = keep all.

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

Keep only jobs in these places, e.g. `United States`, `London`, `Germany`. Matched against the site's location/country filters (server-side, fast) or, if no filter matches, against the job's locations (case-insensitive substring).

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

Keep only jobs in these Workday job categories (a.k.a. job family / function), e.g. `Engineering`, `Sales`. Case-insensitive substring match against the site's category filter. RUN_SUMMARY lists available categories if nothing matches.

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

Keep only remote jobs (Workday remote type = Remote/Fully Flexible, or 'Remote' in the location).

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

Keep only jobs posted within this many days (uses Workday's 'Posted N Days Ago' and the exact posting date from job details). 0 = no limit.

## `includeJobDetails` (type: `boolean`):

Fetch each job's detail page: full description text, parsed salary range, exact posting date, country code, time type, all locations. One extra request per job. Turn off for a fast, cheap list of titles, locations and URLs only.

## `includeDescriptionHtml` (type: `boolean`):

Also output the original description HTML (larger results). Needs job details on.

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

Output only jobs not seen in previous monitoring runs (each item gets changeType = NEW). State is kept per career site and filter set in a named key-value store, so schedule this Actor daily/hourly to get fresh-job alerts.

## `includeChangedJobs` (type: `boolean`):

In monitoring mode, also output jobs whose title, locations or remote type changed since the last run (changeType = CHANGED).

## `includeRemovedJobs` (type: `boolean`):

In monitoring mode, also output a short record for jobs that disappeared since the last run (changeType = REMOVED, i.e. filled or closed). Only when the site was crawled completely.

## `skipExistingOnFirstRun` (type: `boolean`):

In monitoring mode, the very first run stores all current jobs as 'seen' without outputting them, so later runs alert only on truly new jobs.

## `monitoringStoreName` (type: `string`):

Name of the key-value store that keeps seen job IDs. Use different names for independent monitors.

## `dedupe` (type: `boolean`):

Skip the same job if it appears twice (in several categories, several career sites of the same company, or repeated inputs).

## `splitLargeSites` (type: `boolean`):

Workday returns at most 2,000 jobs per query. When a site is bigger, the query is automatically split by job category/location filters so you get every job.

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

Maximum jobs to output per career site after filtering. 0 = no limit.

## `maxJobs` (type: `integer`):

Maximum jobs to output in this run (also capped by your max charge per run). Default 1000 keeps accidental big runs cheap; set 0 for no limit.

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

Parallel requests per Workday host. Keep low (default 4) to stay polite; the Actor slows down automatically on rate limits (HTTP 429).

## Actor input object example

```json
{
  "careerSites": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://redhat.wd5.myworkdayjobs.com/jobs"
  ],
  "searchText": "",
  "keywords": [],
  "locations": [],
  "departments": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeJobDetails": true,
  "includeDescriptionHtml": false,
  "onlyNewJobs": false,
  "includeChangedJobs": false,
  "includeRemovedJobs": false,
  "skipExistingOnFirstRun": false,
  "monitoringStoreName": "workday-jobs-monitor",
  "dedupe": true,
  "splitLargeSites": true,
  "maxJobsPerCompany": 0,
  "maxJobs": 1000,
  "maxConcurrency": 4
}
```

# Actor output Schema

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

All scraped job postings (title, company, location, remote flag, job category, posted date, salary min/max/currency/period, URL, description, changeType in monitoring mode).

## `runSummary` (type: `string`):

Per-career-site status: jobs on site, jobs listed, matched and saved, available filters, warnings and errors.

# 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 = {
    "careerSites": [
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://redhat.wd5.myworkdayjobs.com/jobs"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wowlab/workday-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 = { "careerSites": [
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://redhat.wd5.myworkdayjobs.com/jobs",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wowlab/workday-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 '{
  "careerSites": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://redhat.wd5.myworkdayjobs.com/jobs"
  ]
}' |
apify call wowlab/workday-jobs-scraper --silent --output-dataset

```

## MCP server setup

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