# Workday Jobs Scraper: Careers Pages & Job Listings (`heyitsgautham/workday-jobs-scraper`) Actor

Export live jobs from public Workday career sites by URL, company website or name. Get title, location, posting date, salary when listed, seniority and description. Filter by keyword, location, date, seniority and salary. $1 per 1,000 jobs, down to $0.70 on Gold. Empty and failed sites are free.

- **URL**: https://apify.com/heyitsgautham/workday-jobs-scraper.md
- **Developed by:** [Gautham Krishna](https://apify.com/heyitsgautham) (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.70 / 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.
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

## Workday Jobs Scraper: Careers Pages & Job Listings

Get every open job from any company's Workday careers page, live, as clean JSON rows, for recruiters, job boards and job seekers tracking large employers.

Use cases, each with a ready-to-run example:

- [Get NVIDIA's jobs from its Workday careers page](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/nvidia-jobs-workday)
- [Find internships and new grad jobs](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/workday-internships-new-grad-jobs)
- [Get only the remote jobs](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/remote-jobs-on-workday)
- [Look up a company's jobs by its name](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/workday-jobs-by-company-name)
- [Track the jobs posted in the last 7 days](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/workday-jobs-posted-last-7-days)
- [Find software engineer jobs that list a salary](https://apify.com/heyitsgautham/workday-jobs-scraper/examples/workday-software-engineer-jobs-with-salary)

Paste Workday career site URLs (`nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`), company websites (`crowdstrike.com`) or company names (`Boeing`), and get one row per job with title, department, locations, remote flag, exact posting date, job and apply links, salary when the description states one, seniority and the full description.

It reads the same public job data the Workday careers page loads in your browser, so it needs no login, no browser and no proxy, and every run sees the jobs open at that moment.
Filter by keyword, location, remote, posting date, seniority (intern, entry level and up) and salary, and turn on only-new mode for a daily feed.

You pay **$1 per 1,000 jobs** ($0.001 each), and less on Apify Store discount tiers (Bronze, Silver, Gold), down to $0.70 per 1,000 on Gold.
Sites that don't exist, have no matching jobs or fail are **never charged**, and finding a company's site from its website or name costs nothing.

### At a glance

| Topic | Details |
|---|---|
| Input | Workday career site URLs on `myworkdayjobs.com` and `myworkdaysite.com`, any job link on them, a Workday address without the site, company websites and company names |
| Output | One JSON row per open job, with the same fields as our [Greenhouse, Lever, Ashby & Workable Jobs Scraper](https://apify.com/heyitsgautham/career-site-jobs-scraper), plus the requisition ID |
| Filters | Keywords, excluded words, locations, remote only, posted within N days, seniority, salary listed, minimum salary |
| Monitoring | `onlyNewSinceLastRun` returns only jobs you have not had before. Schedule it for a daily feed |
| Price | $0.001 per job ($1 per 1,000), or $0.90 per 1,000 on Bronze, $0.80 on Silver and $0.70 on Gold. No start fee. Sites not found, empty, filtered out or failed are free, and so are jobs your filters drop |
| Tested | One run on 70 real Workday career sites across tech, banking, pharma, retail, universities and nonprofits: all 67 sites with open jobs returned jobs, 41,383 in total, and the other 3 had none. Lookups: 38 of 40 websites and 40 of 40 company names found the right site, and no wrong one |

### What you get per job

The fields match our Greenhouse, Lever, Ashby & Workable Jobs Scraper, so rows from both actors fit one table, plus `requisitionId`.

| Field | What it holds |
|---|---|
| `status` | `ok` for a job. Other rows say why a career site gave nothing, see below |
| `company` | The hiring company Workday names on the job, often a local entity such as `Autodesk Canada Co.`, with leading entity codes such as `1001` removed. Empty when the site names none (Capital One) |
| `ats`, `boardSlug` | Always `workday`, and the tenant and site, such as `nvidia/NVIDIAExternalCareerSite` |
| `boardUrl`, `resolvedBy`, `resolvedFrom` | Only for inputs the scraper resolved (Workday addresses without a site, websites, names). The site used, how it was found, and the page that linked to it |
| `jobId`, `requisitionId` | Workday's job posting ID, and the company's requisition number such as `R-94651` |
| `title` | The job title |
| `department` | The site's own job category, such as `Engineering` or `Retail Stores`, when the site has a category filter that covers every job |
| `team` | Always empty. Workday's public job data has no team |
| `location`, `locations` | First location, and every location the job lists |
| `country` | The country Workday gives the job |
| `isRemote`, `workplaceType` | `true` for remote jobs. `workplaceType` is `remote`, `hybrid`, `onsite` or empty, read from the site's remote type or the locations |
| `employmentType` | `Full-time` or `Part-time` |
| `postedAt` | The day Workday shows as the posting date, in UTC (`2026-10-16T00:00:00Z`) |
| `updatedAt` | Always empty |
| `url`, `applyUrl` | The job page and the application form |
| `salary` | `{ min, max, currency, period, text }` when the description states a pay range, otherwise empty. See [Salary](#salary) |
| `descriptionText`, `descriptionHtml` | The full job description as clean text and as the original HTML, with emails and phone numbers removed |
| `seniority` | `intern`, `entry`, `mid`, `senior`, `lead`, `executive`, or empty. See [Seniority](#seniority) |

### Input

```json
{
  "companies": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://wd1.myworkdaysite.com/recruiting/snapchat/snap",
    "nike.wd1.myworkdayjobs.com",
    "crowdstrike.com",
    "Boeing"
  ],
  "keywords": ["engineer"],
  "locations": ["US"],
  "seniority": ["intern", "entry"],
  "postedWithinDays": 14
}
```

Each line in `companies` can be any of these.

| You pass | Example |
|---|---|
| A Workday career site URL | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, `https://wd1.myworkdaysite.com/recruiting/snapchat/snap` |
| Any job link on such a site | `https://nike.wd1.myworkdayjobs.com/en-US/nke/job/...` reads the whole Nike site |
| A Workday address without the site | `nike.wd1.myworkdayjobs.com`. The scraper picks the company's busiest public career site |
| A company website or careers page | `crowdstrike.com`, `careers.adobe.com` |
| A company name | `Boeing`, `Capital One` |

Career site URLs are read exactly as given.
Everything else goes through the steps in the next section.

### Finding the career site

| You pass | What the scraper does |
|---|---|
| A Workday address without the site | Reads the tenant's list of career sites, asks each public one how many jobs it has, and uses the busiest. The free summary row lists the others in `otherSites`, so you can pass one of them instead |
| A website | Reads the page you gave, the usual careers addresses (`careers.<domain>`, `<domain>/careers`, `jobs.<domain>`) and the careers links they show, and uses the first Workday site they link. If none links one, it tries the domain's name as a Workday tenant on every Workday data center |
| A name | Tries spellings of the name as a Workday tenant on every Workday data center, then reads `<name>.com` as for a website |

A tenant found by its name counts only when it points back to the company: its careers site links to the same domain or to a careers domain of that name (`capitalonecareers.com`), or its jobs name the company as the hiring company.
Otherwise you get a free `ats_not_detected` row that says what was tried and which tenants were found but did not look right.

Measured on 40 companies on Workday, each given once by website and once by name, plus 5 companies not on Workday each way (run `kAXuSJYx4vdbx2PIZ`).

| Input | Right site | Missed | Wrong site | Not on Workday, correctly nothing |
|---|---|---|---|---|
| Websites (`nvidia.com`) | 38 of 40 | 2 (`gm.com`, `disney.com`) | 0 | 5 of 5 |
| Names (`Capital One`) | 40 of 40 | 0 | 0 | 5 of 5 |

20 websites were found through a link on the company's own pages and 18 through the tenant name.
38 names were found through the tenant name, and Samsung (tenant `sec`) and Snap (tenant `snapchat`) through a link on `samsung.com` and `snap.com`.
A lookup costs about $0.0008.

Workday tenant names often differ from the company name (Samsung's is `sec`, Snap's is `snapchat`), and many careers pages show their Workday link only after JavaScript runs.
When a website or name finds nothing, pass the career site URL.
To find it, open the company's careers page and click any job: the address starts with `<tenant>.wd<N>.myworkdayjobs.com/<site>`.

### Filters

| Filter | What it does |
|---|---|
| `keywords` | Keep jobs whose title contains any of these. Each keyword also runs Workday's own search first, so a large site reads only the jobs that can match |
| `excludeKeywords` | Drop jobs whose title contains any of these, for example `senior` or `manager` |
| `locations` | Keep jobs in any of these places. A city or state is matched as a whole word to the site's own location filter, and to the job's locations and country when the filter does not name it. A country (`US`, `UK`, `Germany`) uses the site's country filter when it has one. On a site that lists only cities, every city not named as being in another country is read, and each job is checked on its own country, so `US` finds jobs in McLean, VA as well as US Remote. `remote` keeps remote jobs |
| `remoteOnly` | Keep only remote jobs, through the site's remote filter when it has one |
| `postedWithinDays` | Keep only jobs whose Workday posting date is within the last N days. Reading stops at the first page of older jobs, so a short window on a large site is fast |
| `seniority`, `keepJobsWithoutSeniority` | Keep jobs at these levels, see [Seniority](#seniority) |
| `hasSalary`, `minSalary`, `salaryCurrency`, `salaryPeriod`, `keepJobsWithoutSalary` | Keep jobs that state pay, or pay that reaches a minimum, see [Salary](#salary) |
| `onlyNewSinceLastRun` | Keep only jobs this scraper has not returned to you before, see below |
| `maxJobsPerCompany` | Stop after this many matching jobs per career site, newest first |
| `includeDescription` | Turn off for a smaller dataset. Salary and seniority are still read from the description |
| `boardSummary` | Add one free summary row per career site, see below |

Filters run before charging, so jobs they drop cost nothing.

### Salary

Workday's public job data has no pay field, so the scraper reads pay from the description, where US pay transparency laws put it.
A range counts when it carries a currency and sits close after a pay word, as in "The base salary range for this position is $140,000 - $215,000 per year".
Ranges about a bonus, a shift differential, relocation, tuition or a 401(k) are skipped, and so are amounts with no pay word near them.

| Part | How it is read |
|---|---|
| `min`, `max` | When the description lists several ranges, per location or per level, the lowest minimum and the highest maximum in the first range's currency |
| `currency` | The symbol or code in the text. A plain `$` is CAD for a job in Canada and AUD in Australia, unless the words before it name US states or the United States, and USD otherwise |
| `period` | The words next to the range (`per year`, `annually`, `hourly`). With none, a range starting at 15,000 or more is `YEAR` and one ending below 150 is `HOUR` |
| `text` | The ranges as written, up to four, joined with `;` |

On 70 real sites with 41,383 open jobs (run `1IlWmjRpIDLNTfJEe`), 17,591 jobs had a salary, and 16,360 of the 21,913 jobs in the United States (75%).
Their periods: 13,749 yearly, 3,637 hourly, 41 monthly, 2 weekly and 162 unknown.
A hand check of 20 jobs with pay on 20 sites, against their descriptions, found 19 right.
The wrong one was a Cisco job in Canada whose description lists US state ranges, read as CAD. The scraper now keeps a range in USD when the words before it name US states or the United States, which changed 26 of the 41,383 rows, all Cisco jobs in Canada.
Netflix states total compensation and Zendesk on-target earnings for sales roles, and `salary` keeps what they state.

The salary filter works like the one in our other jobs scraper.

| Input | What it does |
|---|---|
| `hasSalary` | Keep only jobs whose description states a pay range |
| `minSalary` | Keep jobs whose stated pay reaches this amount. The top of the range counts, so a job paying 120,000 to 160,000 passes a minimum of 150,000 |
| `salaryCurrency`, `salaryPeriod` | The currency and period of `minSalary`, `USD` and `YEAR` unless you set them. Amounts are never converted |
| `keepJobsWithoutSalary` | With `minSalary`, also keep jobs that state no pay in that currency and period |

### Seniority

Every job row ends with `seniority`, one of `intern`, `entry`, `mid`, `senior`, `lead` or `executive`, or empty when the job gives no clear sign.
It uses the same rules as our other jobs scraper, in this order, and the first answer wins.

| Step | What it reads | Examples |
|---|---|---|
| 1 | Level words in the title | Intern, Co-op, New Grad, Graduate, Junior, Senior, Staff, Principal, Lead, Manager, Director, VP, Head of |
| 2 | The site saying intern or early career | A job category such as `Univ Employment`, `Internships` or `Early Career` |
| 3 | The years of experience the description asks for | 0 or 1 year is `entry`, 2 to 4 is `mid`, 5 or more is `senior`. Also "this internship" and "recent graduates" |
| 4 | A level number or "Associate" in the title | Engineer I is `entry`, II is `mid`, III is `senior` |

`seniority: ["intern", "entry"]` finds internships, new grad and junior roles.
Jobs with an empty level are dropped by the filter, unless you turn on `keepJobsWithoutSeniority`.

On 70 real sites with 41,383 open jobs (run `1IlWmjRpIDLNTfJEe`, no filter), 9,196 jobs (22%) had no clear level.

| Level | Jobs |
|---|---|
| intern | 1,564 |
| entry | 3,859 |
| mid | 6,013 |
| senior | 11,847 |
| lead | 6,412 |
| executive | 2,492 |
| empty | 9,196 |

With `seniority: ["intern", "entry"]` and `postedWithinDays: 30` on 25 large employers (run `UhE5u0ypxhU2bqsvW`), every site was read and the scraper kept 1,553 jobs: 610 intern and 943 entry.
A hand check of 30 kept jobs, at most 2 per site, found 27 at a fitting level.
The 3 wrong ones were a program manager for an intern program, a "Program Management Manager" whose description asks first for 1 year of experience, and a sales specialist whose description mentions an internship.

A title that names another level, such as Senior Engineer when you ask for interns, is dropped without its detail request, so intern searches read fewer jobs.
Other jobs need their description for the level, so a seniority filter on a very large site is slow (see Limitations).

### Monitoring: only new jobs

Turn on `onlyNewSinceLastRun` and schedule the run, for example daily.
The first run returns every matching job and remembers them.
Each later run returns only jobs it has not returned to you before for the same career site and filters, so you pay only for new postings.
Workday lists jobs newest first, so a later run stops reading a site at the first page with nothing new.
A site with nothing new comes back as a free `no_jobs` row.
The memory is a key-value store named `workday-jobs-scraper-monitor` in your own Apify account, one record per career site and filter set.
Delete that store to start over.

Tested on 12 sites: the first run returned 3,036 jobs (run `7hQSuM1KlORxCAe52`).
A second run 4 minutes later returned no job and 12 free `no_jobs` rows (run `Fw9DRZoPFUz0fd46g`).
A third run about 90 minutes after the first returned the one job posted in between, a Zillow Data Scientist role, and no job from the first run (run `dksAwIOA2Hg7dI6mk`).

### Run it on a schedule

A daily run with `onlyNewSinceLastRun: true` gives you a feed of new jobs at the Workday sites you track.
We ran the same 12 Workday sites on 17 Oct and again on 20 Oct.
The 20 Oct run returned 142 jobs, and a script found none that the 17 Oct runs had returned.

1. Set your input with `onlyNewSinceLastRun: true` and click **Save as a new task**.
2. On the task page, click **Actions**, then **Schedule**, and pick how often it runs.
   [Apify's schedules guide](https://docs.apify.com/actors/running/schedules) covers cron times and time zones.
3. On the task's **Integrations** tab, choose where each run's results go.

| Integration | What it does |
|---|---|
| [Slack](https://docs.apify.com/integrations/slack) | Posts a message to your channel when a run finishes |
| [Google Drive](https://docs.apify.com/integrations/drive) | Saves each run's results as a file in your Drive |
| [Webhook](https://docs.apify.com/integrations/webhooks) | Sends the finished run, with its dataset ID, to your own URL |
| [Make](https://docs.apify.com/integrations/make), [Zapier](https://docs.apify.com/integrations/zapier), [n8n](https://docs.apify.com/integrations/n8n) | Adds each new row to a Google Sheet, a CRM or a database |

Each job has a stable `jobId`, so a sheet or database can skip rows it already holds.

### Free summary row per career site

With `boardSummary` on, each career site ends with one free row: Workday's own count of open jobs on the site, its counts by job category and by country, how many jobs matched your filters and how many this run returned.
For a Workday address without a site, `otherSites` lists the company's other public career sites.
It needs no extra request.

### Output example

This is real output from run `1IlWmjRpIDLNTfJEe`, with the description shortened here.

```json
{
  "status": "ok",
  "input": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
  "company": "NVIDIA USA",
  "ats": "workday",
  "boardSlug": "nvidia/NVIDIAExternalCareerSite",
  "jobId": "PhD-Research-Intern--Security-and-Privacy---2027_JR2025096",
  "requisitionId": "JR2025096",
  "title": "PhD Research Intern, Security and Privacy - 2027",
  "department": "Univ Employment",
  "team": null,
  "location": "US, CA, Santa Clara",
  "locations": ["US, CA, Santa Clara", "US, MA, Westford"],
  "country": "United States of America",
  "isRemote": false,
  "workplaceType": null,
  "employmentType": "Full-time",
  "postedAt": "2026-10-14T00:00:00Z",
  "updatedAt": null,
  "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite/job/US-CA-Santa-Clara/PhD-Research-Intern--Security-and-Privacy---2027_JR2025096",
  "applyUrl": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite/job/US-CA-Santa-Clara/PhD-Research-Intern--Security-and-Privacy---2027_JR2025096/apply",
  "salary": { "min": 38, "max": 94, "currency": "USD", "period": "HOUR", "text": "38 USD - 94 USD" },
  "descriptionText": "NVIDIA is seeking exceptional security and privacy researchers to contribute to the development of secure, private, and ...",
  "descriptionHtml": "<p>NVIDIA is seeking exceptional security and privacy researchers to contribute to the development of secure, ...",
  "seniority": "intern"
}
```

The free summary row for Snap's site, from the same run, with the category list shortened.

```json
{
  "status": "summary",
  "input": "https://wd1.myworkdaysite.com/recruiting/snapchat/snap",
  "company": "Snap Inc.",
  "ats": "workday",
  "boardSlug": "snapchat/snap",
  "boardUrl": "https://wd1.myworkdaysite.com/recruiting/snapchat/snap",
  "jobsOnBoard": 205,
  "jobsMatched": 205,
  "jobsReturned": 205,
  "categories": [{ "name": "Engineering", "jobs": 90 }, { "name": "Sales", "jobs": 34 }, { "name": "Product", "jobs": 16 }],
  "countries": [],
  "message": "https://wd1.myworkdaysite.com/recruiting/snapchat/snap lists 205 open jobs. This run returned 205."
}
```

A company website found through its tenant name, from run `kAXuSJYx4vdbx2PIZ`, adds these fields to each row.

```json
{
  "input": "capitalone.com",
  "company": null,
  "boardSlug": "capitalone/Capital_One",
  "boardUrl": "https://capitalone.wd12.myworkdayjobs.com/Capital_One",
  "resolvedBy": "tenant_name_match",
  "resolvedFrom": null
}
```

`resolvedBy` is `careers_page_link` when a company page linked the site (`resolvedFrom` is that page), `tenant_name_match` when a Workday tenant named like the company pointed back to it, or `tenant_site` when you gave a Workday address without the site.

A company not on Workday gives one free row, from the same run.

```json
{
  "status": "ats_not_detected",
  "input": "stripe.com",
  "ats": "workday",
  "boardSlug": null,
  "message": "No Workday career site found for https://stripe.com. Read 8 pages: https://stripe.com, https://stripe.com/careers, https://www.stripe.com/careers, https://stripe.com/jobs, https://stripe.com/careers/search, https://stripe.com/careers/compatibility. Tried Workday tenants stripe. Pass the Workday career site URL, such as https://nike.wd1.myworkdayjobs.com/nke."
}
```

A site with no open jobs gives one free row, from run `1IlWmjRpIDLNTfJEe`.

```json
{
  "status": "no_jobs",
  "input": "https://ebay.wd5.myworkdayjobs.com/TCGPlayer_External_Career",
  "ats": "workday",
  "boardSlug": "ebay/TCGPlayer_External_Career",
  "message": "Career site has no open jobs."
}
```

| Status | Meaning | Charged |
|---|---|---|
| `ok` | One open job | Yes |
| `summary` | The free summary row for a career site, only with `boardSummary` | No |
| `no_jobs` | The site exists but has no open jobs, or none matched your filters or were new | No |
| `not_found` | No Workday tenant or career site answers at that address | No |
| `ats_not_detected` | No Workday career site found for the website or name. The message lists the pages read and the tenants tried | No |
| `duplicate` | The same career site as an earlier input, so its jobs are returned once | No |
| `invalid_input` | The line is not a URL, a website or a name | No |
| `error` | Workday kept failing after retries | No |

### Use it from AI agents

The scraper works as a tool through the [Apify MCP server](https://mcp.apify.com) in Claude, Cursor, VS Code and other MCP clients.
An agent can pass company names or Workday links with `seniority: ["intern"]` and get back structured internships it can rank, summarise or match to a CV.

You can also call it through the [Apify API](https://docs.apify.com/api/v2) or the Python and JavaScript clients, and schedule it or connect it to Make, Zapier and n8n.
A daily schedule with `onlyNewSinceLastRun: true` gives you a feed of new jobs at the companies you track.

### Pricing

Prices are per 1,000 jobs.

| Event | No discount | Bronze | Silver | Gold |
|---|---|---|---|---|
| Job returned | $1.00 | $0.90 | $0.80 | $0.70 |
| Site not found, empty, filtered out, undetected, duplicate or failed, and summary rows | Free | Free | Free | Free |

Bronze, Silver and Gold are Apify Store discount tiers, and Apify's Pricing tab shows them as Starter, Scale and Business.
Apify decides which tier an account is on.

Set a maximum cost per run in the run options.
The scraper stops once that limit is reached.

### FAQ

**How do I find a company's Workday career site?**
Open the company's careers page and click any job.
The address starts with `<tenant>.wd<N>.myworkdayjobs.com/<site>` or `wd<N>.myworkdaysite.com/recruiting/<tenant>/<site>`.
Paste that address, or pass the company's website or name and check `boardUrl` on the rows.

**Is this live data?**
Yes.
Every run reads the career site at that moment, through the same public job data the careers page loads in a browser.

**Why is `salary` empty for some jobs?**
Workday has no pay field, so pay comes only from the description.
Most US jobs state a range because of pay transparency laws, and many jobs in other countries state none.

**Why is `department` empty for some sites?**
It comes from the site's own job category filter, and some sites have none, or one that leaves some jobs out.

**Is a job listed once per location?**
No.
A job with several locations is one row, with all of them in `locations`.

### Limitations

- Workday career sites only. For Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee boards, use our [Greenhouse, Lever, Ashby & Workable Jobs Scraper](https://apify.com/heyitsgautham/career-site-jobs-scraper).
- It reads the sites you give it, or the ones it finds for the companies you name. It does not search all Workday sites.
- `postedAt` is a day, with no time. Workday shows no update date.
- Some sites serve at most 2,000 jobs per query. The scraper splits those by their own filters: NVIDIA's 2,735 jobs and Abbott's 2,622 were all reached.
- Each job needs its own request, and Workday answers each in about a second from Apify. The 70-site test run read 41,383 jobs in 47 minutes, about 880 a minute. Use `maxJobsPerCompany`, `keywords` or `postedWithinDays` to read less.
- On a very large site, a seniority or salary filter needs a detail request for most jobs. A 30-day intern and entry search on Accenture's 41,577 jobs ran for over 45 minutes before we stopped it. Add `keywords` to narrow it first.
- A few very large sites serve 2,000 jobs per query and have no filter that splits them small enough. Accenture's site lists 41,577 jobs, and the splits reached 34,360 of them (83%) in a check on 17 Oct. The run note and the summary row say so when a site is reached only in part.
- Salary is read from the description text, so a description that states pay in an unusual way may be missed.

# Actor input Schema

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

One per line. A Workday career site URL (nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, wd1.myworkdaysite.com/recruiting/snapchat/snap), any job URL on such a site, a Workday address without the site (nike.wd1.myworkdayjobs.com), a company website (crowdstrike.com) or a company name (Boeing). For an address without a site, a website or a name, the scraper finds the career site itself, and each row says which one it used.

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

Keep jobs whose title contains any of these words or phrases, for example engineer or data analyst. Each keyword also runs Workday's own search, so large sites read faster. Case does not matter. Leave empty for all jobs.

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

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

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

Keep jobs in any of these places, for example London, Germany, Texas or US. They are matched to the site's own location filter when it has one, and to the job's locations and country otherwise. The word remote keeps remote jobs.

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

Keep only jobs the site marks as remote, or whose location says remote.

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

Keep only jobs posted in the last N days, by the exact posting date Workday shows on the job. 0 keeps all.

## `seniority` (type: `array`):

Keep only jobs at these levels, for example intern and entry for students and new grads. Every job row has a seniority field, read from the title, the years of experience the description asks for, the job category and the time type. Leave empty for all jobs.

## `keepJobsWithoutSeniority` (type: `boolean`):

With a seniority filter set, also keep jobs whose level the title, description and site do not show (seniority null). Off by default, so those jobs are dropped.

## `hasSalary` (type: `boolean`):

Keep only jobs whose description states a pay range. Workday has no pay field, so pay comes from the description.

## `minSalary` (type: `integer`):

Keep jobs whose stated pay reaches this amount in the currency and period below. A job paying 120,000 to 160,000 passes a minimum of 150,000. Amounts are never converted between currencies or periods. 0 turns it off.

## `salaryCurrency` (type: `string`):

Currency of the minimum salary, as a 3-letter code such as USD, EUR or GBP. Jobs paid in another currency count as having no salary.

## `salaryPeriod` (type: `string`):

The period the minimum salary is paid per. Jobs paid per another period count as having no salary.

## `keepJobsWithoutSalary` (type: `boolean`):

With a minimum salary set, also keep jobs that state no pay in that currency and period. Off by default, so those jobs are dropped.

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

For scheduled runs. Returns only jobs this actor has not returned to you before for the same career site and filters. The first run returns every matching job and remembers them. The memory is a key-value store named workday-jobs-scraper-monitor in your Apify account.

## `boardSummary` (type: `boolean`):

Adds one free row with status summary per career site, after its jobs: Workday's own count of open jobs, the counts by job category and by country, how many jobs matched and how many were returned, and the company's other Workday career sites when the scraper picked one. It needs no extra request and is never charged.

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

Stop after this many matching jobs per career site, newest first. 0 means no limit.

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

Adds the full description as plain text and HTML. Turn off for a smaller dataset. Salary and seniority are still read from it.

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

How many career sites to read at the same time.

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

Not needed. Workday's job data is public and answers without a proxy. Turn it on only if a site starts refusing requests.

## Actor input object example

```json
{
  "companies": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://crowdstrike.wd5.myworkdayjobs.com/crowdstrikecareers",
    "https://wd1.myworkdaysite.com/recruiting/snapchat/snap"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "keepJobsWithoutSeniority": false,
  "hasSalary": false,
  "minSalary": 0,
  "salaryCurrency": "USD",
  "salaryPeriod": "YEAR",
  "keepJobsWithoutSalary": false,
  "onlyNewSinceLastRun": false,
  "boardSummary": false,
  "maxJobsPerCompany": 20,
  "includeDescription": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One item per open job with company, title, department, locations, remote flag, employment type, exact posting date, job and apply URLs, salary when the description states one, seniority and the full description. Boards that fail or have no matching jobs get one uncharged item with a status and message, and the optional board summary rows are uncharged too. Only items with status ok are charged.

# 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": [
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://crowdstrike.wd5.myworkdayjobs.com/crowdstrikecareers",
        "https://wd1.myworkdaysite.com/recruiting/snapchat/snap"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("heyitsgautham/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 = {
    "companies": [
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://crowdstrike.wd5.myworkdayjobs.com/crowdstrikecareers",
        "https://wd1.myworkdaysite.com/recruiting/snapchat/snap",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("heyitsgautham/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 '{
  "companies": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://crowdstrike.wd5.myworkdayjobs.com/crowdstrikecareers",
    "https://wd1.myworkdaysite.com/recruiting/snapchat/snap"
  ],
  "maxJobsPerCompany": 20
}' |
apify call heyitsgautham/workday-jobs-scraper --silent --output-dataset

```

## MCP server setup

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