# Workday Jobs Scraper: myworkdayjobs careers, filters, new jobs (`siftsmith/workday-jobs`) Actor

Open jobs from myworkdayjobs career sites, narrowed by each site's own filters (country, job family, time or remote type). Options: up to 10 public sites per company; only jobs not yet returned. A name or domain is charged only when the site ties to that company. $0.001 per job; misses free.

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

## Pricing

$1.00 / 1,000 job rows

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

Open jobs from Workday career sites, by career site URL or by company name or domain.

Built for recruiters and staffing agencies, job boards, and sales teams tracking which accounts are hiring.

**Free coverage check:** open an issue on this Actor's Issues tab with up to 20 Workday career site URLs, company names or domains. We run them through this Actor for free and reply in the issue with the result for each: the career site and how many open jobs it lists, or the reason no jobs come back. Issues are public, so list only employers, not personal details.

Not affiliated with Workday, Inc. "Workday" here only names the platform the career sites run on.

### What it reads

- **Career site URLs** (`startUrls`): `https://{company}.wdN.myworkdayjobs.com/{site}` (a locale such as `/en-US/` is fine) or `https://wdN.myworkdaysite.com/recruiting/{company}/{site}`. A job posting URL reads the career site it belongs to.
- **Company names, domains and pasted rows** (`companies`): looked up on Workday only. A name's jobs are returned and charged only when the site's own postings tie to that employer. A one-word name (for example "Prudential") is matched only when a sampled posting's employer is that name, or the postings name it on its own and give its own .com (prudential.com) as an address; otherwise it is a free row asking for the website. A domain, or a row with a website, is matched only when the company's own site links the Workday site or at least 2 sampled postings give that domain. Names and domains are found less often than URLs. On 26 October 2026, across 15 large Workday employers we hadn't tested before, a company name alone found 6 and a domain alone found 5. The rest got free status rows. For a company you know is on Workday, paste its career site URL.

Every request to Workday goes to the career site's own public job list and job pages, after reading its robots.txt. A site that robots.txt asks automated tools not to read is never read. For a domain, or a row with a website, the company's own homepage and careers page are also read, after that site's robots.txt, to check that they link the Workday site.

### What you get

- **One row per open job** (`type` = `job`), with the same columns as [Company Jobs](https://apify.com/siftsmith/company-jobs), plus `requisitionKey` and `workdayFilterKey` (below): title, location (also `locations` and `locationsCount` for a job posted in several places), country, remote, posted date, job URL, the career site it came from, match confidence and a stable `globalId`. A field the site doesn't give is empty, never guessed.
- **`requisitionId`, `hiringOrganization`, `timeType`, `remoteType`**: `requisitionId`, `hiringOrganization` (the employing legal entity as the employer writes it, often with a number in front, for example `084 PGIM Quantitative Solutions LLC`) and `timeType` (for example `Full time`) come from the job's own page, unchanged. That page is read for every job when `includeDescription` is on, and otherwise only for a job in several places or with no place in the list, so with descriptions off a job in one place has these three empty. They are also empty when the page couldn't be read or doesn't give them. `remoteType` is the work type the career site's job list gives (for example `Hybrid`), empty when the list gives none.
- **`requisitionKey`**: the key a job is matched by across the company's sites, `wdreq:<tenant>:<requisition>` (for example `wdreq:pru:R-123456`), taken from the career site's job list, so it is there whether or not the job's own page was read. Empty when the list gives the job no requisition number. Within a run, a job is returned and charged once per key, across sites, inputs and restarts.
- **`workdayFilterKey`**: the Workday filters the site was read under, as Workday's own filter and value IDs (for example `Location_Country=dcc5b7608d8644b3a93716604e78e995`, Germany on HP's site; several values of one filter are joined by `,`, several filters by `&`). It is on job rows and on that site's status row (with `allSites`, its entry in `sitesRead`). Empty when the site was read without Workday filters, or returned no jobs under them. Within a run, two inputs on the same site with different filters are read separately, and a job that matches both is still returned and charged once (see `requisitionKey`); with the same filters, the later input is a free duplicate. This holds after a restart too.
- **One free status row per input** (`type` = `company`): found or not and why not, the open-job count and hiring signals, the sites read and skipped (with `allSites`), and the filters applied and any names the site lacks (with `workdayFilters`). In a CSV or spreadsheet export, filter the `type` column to `job`.

### Inputs

| Field | What it does |
|---|---|
| `startUrls` | Workday career site URLs. Any other URL gets one free status row and no request. |
| `companies` | Names, domains or pasted rows, one per line. |
| `allSites` | Also reads the company's other Workday career sites (see below). Off by default. |
| `workdayFilters` | Filters Workday applies itself, by the names the career site shows: countries, job families, time types, remote types (see below). |
| `minMatchConfidence` | How sure a name-to-site match must be before its jobs are returned and charged: `medium` (default) or `high`. Low-confidence matches are never charged. |
| `titleKeywords`, `locationKeywords`, `remoteOnly` | Keep matching jobs only. Jobs filtered out are not charged. |
| `includeDescription` | Adds each job's description from its own page. Email addresses, phone numbers and labelled contact lines are removed. |
| `maxJobsPerCompany` | Up to 1,000 per company (all its sites together) when left empty (the form starts at 10). |
| `maxItems` | Cap on job rows for the whole run. |
| `onlyNewJobs`, `stateKey` | For schedules: skip jobs an earlier run with the same key returned. |

### A company's other career sites (`allSites`)

Some employers run more than one Workday career site, for example Prudential's Careers and PGIM_Careers. With `allSites` on:

- The sites come from the career host's robots.txt. Sites robots.txt asks automated tools not to read and sites whose name looks private (internal, alumni, contractor and similar) are skipped, even the one in the URL.
- Of the rest, up to 10 are read: the one in the URL or found by name first, then sites with external, career or jobs in the name. Any past those 10 are skipped too. The status row lists every skipped site in `sitesSkipped`.
- If there is no robots.txt, or it names no other site, only that one site is read. If robots.txt can't be read, no site is read and nothing is charged.
- `maxJobsPerCompany` counts all of a company's sites together.
- A job posted on several of the company's sites is returned and charged once, from the first site in alphabetical order that returns it, with that site's link. Copies are matched by requisition ID. A job with no requisition ID is returned only from the first site; elsewhere it is dropped and not charged.

### Workday's own filters (`workdayFilters`)

`{"countries": ["Germany"], "jobFamilies": ["Engineering"], "timeTypes": ["Full time"], "remoteTypes": ["Remote"]}` asks Workday itself for those jobs only, so a large site is read down to the part you need. A name must equal a value the site lists, apart from case and punctuation: "full-time" matches "Full time", but "Fulltime" does not, and "Mexico" does not match "México". In a list, the names the site has are applied and the rest are listed in its status row. Most career sites offer job families and time types; many have no country filter, and few offer remote types. For a site with no country filter, leave `countries` out and narrow by place with `locationKeywords` (the city or country names the site uses). A site that can't apply a filter exactly gives one free status row and no jobs. Filter parameters in a career site URL are checked the same way.

### Price

$0.001 per job row ($1 per 1,000). No start fee.

**Free, always:** every status row (one per input); a URL that isn't a Workday career site; a board on another ATS; a name or domain with no Workday career site; a name the postings don't tie to; a site robots.txt asks us not to read, or a private-looking site; duplicates; rows past a cap.

If a run restarts (Apify moves it to another server, it is rebooted, or you resurrect it), it carries on from its own dataset: jobs already in it are not returned or charged again, and a company that already has its status row is not looked up again. That includes companies marked `skipped` or `timedOut` and companies whose jobs were cut short (`jobsTruncated`), so resurrecting a run that hit `maxItems`, its maximum charge or its timeout returns nothing new for them. To get the rest, start a new run with those companies. If a restarted run can't read its earlier rows in full, it stops with a message before charging anything more, so nothing is charged twice.

### What it doesn't cover

- Jobs past the first 1,000 of one career site. That site's status row (with `allSites`, its entry in `sitesRead`) says `jobsTruncated` with `reason` `sourceCap`, and `jobsAvailable` gives the total Workday reports for the site. On some sites that total stops at 2,000, so `jobsAvailable` can say 2,000 for a bigger site. With `workdayFilters`, the 1,000 counts only the jobs that match them.
- A second, different job that a company posts under a requisition ID it already used. Postings that share a requisition ID are returned once, as one job.
- Pay ranges: the job list and job page give no pay field, and pay isn't read out of description text.
- Names and domains whose Workday site goes by another name, or whose postings don't tie to the company: free status rows (see the recall above).
- Other ATSes. [Company Jobs](https://apify.com/siftsmith/company-jobs) reads Greenhouse, Lever, Workable, Breezy HR, Personio and Workday by name, domain or URL, and Ashby and Rippling by board URL, in the same columns at the same price.

### Related tools

- [Career Page Jobs](https://apify.com/siftsmith/career-page-jobs): paste careers page URLs or domains and get each company's jobs from the board its page links (Workday or one of 7 other ATSes) or, when it links none, the board its domain matches. Same $0.001 per job row.

# Actor input Schema

## `startUrls` (type: `array`):

Workday career sites to read: https://{company}.wdN.myworkdayjobs.com/{site} (a locale such as /en-US/ is fine, and a job posting URL reads its site) or https://wdN.myworkdaysite.com/recruiting/{company}/{site}. Any other URL gets one free status row and no request; a board on Greenhouse, Lever, Ashby and other ATSes is read by Company Jobs. A site the employer's robots.txt asks automated tools not to read is free and not read.

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

One per line: a company name (Target), a domain (target.com) or a pasted row. Each is looked up on Workday only; its jobs are returned and charged only when the postings tie to that employer. A name with no Workday career site gets one free status row (Company Jobs also looks names up on Greenhouse, Lever, Workable, Breezy HR and Personio, and reads Ashby and Rippling boards by URL).

## `workdayFilters` (type: `object`):

Filters Workday applies itself before any job is returned, by the names the career site shows: {"countries": \["Germany"], "jobFamilies": \["Engineering"], "timeTypes": \["Full time"], "remoteTypes": \["Remote"]}. A name must equal a value the site lists, apart from case and punctuation: "full-time" matches "Full time", but "Fulltime" does not, and "Mexico" does not match "México". In a list, the names the site has are applied and the rest are listed in its status row. A site that can't apply a filter exactly (it has no such filter, has none of the names, or has them under two of its filters) gives one free status row and no jobs. Filter parameters in a career site URL are checked against the site the same way; when both are given, a job must match both. Only jobs that pass every filter are returned and charged.

## `allSites` (type: `boolean`):

Read the company's other Workday career sites too, not just the one in the URL or the largest one found by name (for example Prudential's Careers and PGIM_Careers). Sites come from the career host's robots.txt, up to 10: the one in the URL or found by name first, then others with external, career or jobs in the name. They are read in alphabetical order. Sites robots.txt asks automated tools not to read and sites whose name looks private (internal, alumni, contractor and similar) are skipped, even the one in the URL; so are any beyond those 10. Skipped sites are listed in the status row. If there is no robots.txt, or it names no other site, only that one site is read. If robots.txt can't be read, no site is read and nothing is charged. 'Max jobs per company' counts all of a company's sites together. A job posted on several of the company's sites is returned and charged once, from the first site in alphabetical order that returns it, with that site's link. Copies are matched by requisition ID. A job with no requisition ID is returned only from the first site; on the others it is dropped and not charged. Workday filters are checked on each site separately; a site that can't apply them returns no jobs and gives its reason in the status row.

## `minMatchConfidence` (type: `string`):

How sure the match from a company name or domain to a Workday career site must be before its jobs are returned and charged: 'medium' (default) or 'high'. 'high' needs the company's domain: its own site links the career site, or at least 2 sampled postings give the domain, so a name alone is never charged. Sites below the bar return no jobs and cost nothing; the free status row (type 'company') says why and gives the site URL to paste instead. Career site URLs you give need no match. Low-confidence matches are never charged.

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

Keep jobs whose title contains any of these as whole words (case-insensitive): 'ML' keeps 'ML Engineer', not 'HTML Developer'. End a keyword with \* and its last word also matches longer words: 'engineer\*' also keeps 'Engineering Manager'. Empty = all.

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

Keep jobs whose location contains any of these (case-insensitive), in the city or country names the site uses, e.g. 'London'. A job with no known place is dropped and not charged.

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

Keep only remote jobs. On Workday, a remote type that says remote counts, and one that says hybrid, not remote, on-site, office or field doesn't. With no remote type, or another one such as Flex, the job's place decides ('Remote - US'), and a place that says hybrid doesn't count.

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

For scheduled runs: return (and charge) only jobs that an earlier run with the same state key hasn't already returned. The first run returns every job as usual. Job IDs are kept in a key-value store named 'workday-jobs-state' in your own Apify account. Jobs cut by a cap, the charge limit or the timeout are offered again next time, so 'new' means not returned before, not recently posted: with a cap smaller than a board, later runs return jobs that were already on it. Once a run returns a board in full (no jobsTruncated on its status row), later runs return only jobs added since. To get there, set 'Max jobs per company' above your largest board (this form starts at 10) and allow enough charge limit and timeout; Workday career sites over 1,000 jobs are never read in full.

## `stateKey` (type: `string`):

With 'Skip jobs an earlier run returned': which saved state to use. Give each schedule or employer list its own key so they don't share what counts as already returned. Letters, digits and - \_ . only.

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

Jobs past this cap are not returned and not charged. With 'All public career sites' on, it counts all of a company's sites together. The company's free status row still reports how many jobs the site lists (on some sites Workday's count stops at 2,000). This form starts at 10 so a first run is quick; raise it or clear it for more (up to 1,000 per company when left empty).

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

Cap on job rows (and so on spend) for the whole run. Empty = no cap beyond the run's maximum charge.

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

Adds each job's description text, read from the job's own Workday page, one job at a time per employer. Email addresses, phone numbers and labelled recruiter or contact lines are removed automatically. The scrub matches patterns, so a contact written an unusual way, such as a name inside a sentence, can remain. Off keeps rows small for spreadsheets.

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

How many companies to process in parallel.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://hp.wd5.myworkdayjobs.com/ExternalCareerSite"
    }
  ],
  "allSites": false,
  "minMatchConfidence": "medium",
  "remoteOnly": false,
  "onlyNewJobs": false,
  "stateKey": "default",
  "maxJobsPerCompany": 10,
  "includeDescription": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

## `companies` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://hp.wd5.myworkdayjobs.com/ExternalCareerSite"
        }
    ],
    "maxJobsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("siftsmith/workday-jobs").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 = {
    "startUrls": [{ "url": "https://hp.wd5.myworkdayjobs.com/ExternalCareerSite" }],
    "maxJobsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("siftsmith/workday-jobs").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 '{
  "startUrls": [
    {
      "url": "https://hp.wd5.myworkdayjobs.com/ExternalCareerSite"
    }
  ],
  "maxJobsPerCompany": 10
}' |
apify call siftsmith/workday-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,siftsmith/workday-jobs"
        }
    }
}
```

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/yxtIO5WH5Ye92Q5Zm/builds/gCfBnxr31FpkibmZa/openapi.json
