# Workday Jobs Scraper — Any Company, Salary & Real Dates (`yugenox/workday-jobs-scraper`) Actor

Jobs from any company's Workday careers site: type company names (TD, NVIDIA, CIBC…) or paste URLs. Keyword, location, remote and job-type filters. Full descriptions, parsed salary ranges, real posted/closing dates, past the 2,000-job limit, only-new mode.

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

## Pricing

from $1.50 / 1,000 job listings

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

Scrape open jobs from **any company that hires through Workday**. Thousands of employers use it, including TD, RBC, CIBC, BMO, NVIDIA, Salesforce, Target, CVS Health, Accenture and PwC. Type **company names** instead of hunting for career-site URLs. Filter by keyword, location, remote/hybrid and employment type. Each job comes back with its **full description, a parsed salary range and the real posted and closing dates**.

- 🏢 **Company names in, jobs out.** A built-in directory maps names like "TD", "Sun Life" or "NVIDIA" to their Workday career sites. Pasting any Workday URL also works.
- 💰 **Structured salary.** Pay ranges are pulled out of the job description into `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod`. That covers US pay-transparency blocks, bilingual Canadian postings ("81 600 $ / $81,600"), hourly rates, per-level ranges, K-notation and multi-currency pay.
- 📅 **Real dates.** You get the exact `postedDate` and `closingDate`, not "Posted 30+ Days Ago".
- ♾️ **No 2,000-job ceiling.** Many Workday sites stop listing after 2,000 results. The scraper detects this and splits the search by category and location, so you get every job.
- 🆕 **Only-new mode.** Schedule it daily and receive only jobs you haven't seen before. You pay only for new ones.
- 🌎 **Filters that understand each site.** "Canada", "Ontario", "Toronto", "Remote", "Full-time" and "Engineering" are matched to each company's own filters, whatever that site calls them.
- 🔓 **No login, no cookies, no API key.**

### How to use

**1. Jobs at specific companies**

```json
{
  "companies": ["TD", "CIBC", "NVIDIA"],
  "searchTerms": ["data analyst"],
  "locations": ["Toronto"],
  "maxItems": 200
}
```

**2. A Workday search page you already have open.** Filters in the URL are kept.

```json
{
  "startUrls": ["https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite?q=software%20engineer"],
  "remoteTypes": ["remote"],
  "postedWithinDays": 7
}
```

**3. Search across the largest Workday employers** (leave companies empty)

```json
{
  "searchTerms": ["product manager"],
  "locations": ["Canada"],
  "maxCompanies": 200,
  "maxItems": 1000
}
```

**4. Daily new-jobs alert.** Save this as a task and schedule it daily, then add a webhook, email or Slack integration.

```json
{
  "companies": ["RBC", "TD", "BMO", "CIBC", "Manulife"],
  "searchTerms": ["business analyst"],
  "onlyNew": true,
  "onlyNewStateKey": "big5-ba"
}
```

### Input

| Field | What it does |
|---|---|
| `companies` | Company names (or Workday URLs). Each name resolves to the company's main external career site. |
| `startUrls` | Workday career-site URLs: `…myworkdayjobs.com/<site>` or `…myworkdaysite.com/recruiting/<company>/<site>`. Filtered search pages and single job links also work. |
| `searchTerms` | Keywords, each run as its own search on every site. Leave empty for all open jobs. |
| `locations` | Countries, provinces/states or cities. Several are combined with OR. |
| `remoteTypes` | `remote`, `hybrid`, `onsite`. |
| `employmentTypes` | `full-time`, `part-time`, `contract`, `temporary`, `internship`. |
| `jobCategories` | Job families or departments, e.g. `Technology`, `Finance`. |
| `postedWithinDays` | Only jobs posted in the last N days. |
| `includeDetails` | Full description, salary, exact dates, all locations and similar jobs (default **on**). Turn it off for a fast list. |
| `maxItems` / `maxItemsPerCompany` | Limits for the whole run and per company. |
| `onlyNew` / `onlyNewStateKey` | Skip jobs returned by earlier runs. Use a different key per task. |
| `maxCompanies` | How many employers to search when you give keywords but no companies. |
| `proxyConfiguration` | Datacenter proxy by default. A site that blocks it switches to residential automatically. |

### Output

One row per job. This is a real example, shortened:

```json
{
  "title": "IT Data Analyst III",
  "company": "TD",
  "hiringOrganization": "The Toronto-Dominion Bank (Canada)",
  "location": "Toronto, Ontario",
  "additionalLocations": [],
  "country": "Canada",
  "countryCode": "CA",
  "remoteType": "On Site",
  "remoteTypeSource": "site",
  "timeType": "Full time",
  "jobFamily": "Data/Information Mgmt",
  "salaryMin": 69700,
  "salaryMax": 98400,
  "salaryCurrency": "CAD",
  "salaryPeriod": "YEAR",
  "salaryText": "$69,700 - $98,400 CAD",
  "postedDate": "2026-09-14",
  "postedDaysAgo": 10,
  "closingDate": "2026-09-27",
  "timeLeftToApply": "2 days left to apply",
  "url": "https://td.wd3.myworkdayjobs.com/TD_Bank_Careers/job/Toronto-Ontario/IT-Data-Analyst-III_R_1510444-1",
  "applyUrl": "https://td.wd3.myworkdayjobs.com/TD_Bank_Careers/job/Toronto-Ontario/IT-Data-Analyst-III_R_1510444-1/apply",
  "jobId": "IT-Data-Analyst-III_R_1510444-1",
  "reqId": "R_1510444",
  "descriptionText": "Work Location:\nToronto, Ontario, Canada\n\nHours:\n37.5\n\nPay Details:\n$69,700 - $98,400 CAD\n…",
  "descriptionHtml": "<p><b>Work Location:</b></p>…",
  "similarJobs": [],
  "detailsIncluded": true,
  "careerSiteUrl": "https://td.wd3.myworkdayjobs.com/TD_Bank_Careers",
  "searchText": "data analyst",
  "scrapedAt": "2026-09-24T06:28:23.527Z"
}
```

`salaryPeriod` is one of `HOUR`, `DAY`, `WEEK`, `MONTH` or `YEAR`. When a posting lists several ranges (per state, per level), `salaryMin` and `salaryMax` span all of them, and `salaryText` shows the first range as written. Salary fields are `null` when the posting doesn't state pay.

With `includeDetails` off, you still get the title, company, location, work arrangement (where the site shows it), category, posted date, job link and IDs.

### Use cases

- **Job seekers:** a daily feed of new roles at the employers you want, with pay and closing dates.
- **Recruiters and agencies:** track who is hiring for what, where, and how fast roles close.
- **Salary benchmarking:** structured pay ranges across companies, cities and job families.
- **Job boards and aggregators:** a clean, de-duplicated feed from thousands of employer career sites.
- **Labour-market and investment research:** hiring volume by company, department and country over time.
- **Sales prospecting:** find companies actively hiring for roles your product serves.

### FAQ

**Which companies are supported?**
Any company whose careers site runs on Workday. The address contains `myworkdayjobs.com` or `myworkdaysite.com`. The built-in directory covers thousands of them. If a name isn't found, paste the careers URL into `startUrls`.

**A company has several Workday sites. Which one do I get?**
Its main external site, the one with the most open jobs. The log lists the others; add their URLs if you want them too.

**How complete are the results?**
Every open job that matches your search, including sites with more than 2,000 openings. Jobs are de-duplicated across keywords, locations and search splits.

**How accurate are the dates?**
`postedDate` and `closingDate` come from the job posting itself. Some jobs have no closing date, and `closingDate` is `null` for those. Without full details, `postedDate` is estimated from the site's "Posted N days ago" text, or left `null` when the site only says "30+ days".

**How is salary found?**
From the pay section of the description. Postings without pay information return `null` salary fields. `salaryText` shows the original wording so you can check it.

**How is "remote / hybrid / on-site" decided?**
From the career site's own work-arrangement field when it has one. Otherwise it comes from the job location ("US, Remote"), or from what the posting says ("This role is hybrid…", "no remote option"). `remoteTypeSource` tells you which. When you filter for remote or hybrid, a job only counts if the site or the posting says so.

**Can I run it on a schedule?**
Yes. Save your input as a task, add a schedule, and turn on `onlyNew` so each run returns only new jobs.

**How fast is it?**
About 50 jobs with full details in 10–20 seconds. List-only runs cover a few thousand jobs a minute.

**What happens when a career site is down, private or blocks the request?**
The run still finishes successfully with everything it could collect. Sites that are unreachable, private or misspelled are named in the run's status message, retries use fresh IPs with backoff, and a site that keeps failing is paused rather than allowed to burn the whole run. If a job's full details cannot be loaded, you get its listing row instead. You are only ever charged for rows that were actually written to the dataset, and a run that reaches its time limit or your spending limit stops cleanly with a "Partial" or "Stopped at your spending limit" message.

**How much does it cost?**
$1.50 per 1,000 jobs, plus $0.50 per 1,000 for jobs returned with full details (description, salary, exact dates), so $2.00 per 1,000 detailed jobs all-in. Turn `includeDetails` off for the cheaper list-only tier. With `onlyNew` on, jobs you have already received are skipped and not charged again.

**Is it legal to scrape Workday career sites?**
This actor collects only public job postings: the same listings employers publish on their open career sites for anyone to read, without an account. The output is about jobs and employers, but a posting's description can occasionally name a recruiter or give a work email, so if you store or process that personal data, follow the data-protection rules that apply to you, such as GDPR, PIPEDA or CCPA, and use the data in line with the career site's terms. If you are unsure whether your use case is legitimate, check with a lawyer. Apify's guide [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/) is a good starting point.

**Does it access any private data?**
No. It reads only what a logged-out visitor sees on a company's public Workday careers page. It never signs in and never uses cookies, accounts or API keys of any person. Candidate applications, applicant profiles and internal-only job boards are never accessed; career sites that require a sign-in are skipped and named in the run's status message.

# Actor input Schema

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

Company names — no URL hunting needed. Resolved against a built-in directory of thousands of Workday career sites (e.g. TD, RBC, CIBC, BMO, NVIDIA, Salesforce, Target, CVS Health, Accenture, PwC). A Workday careers URL works here too.

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

Any Workday careers page: https://<company>.wd<N>.myworkdayjobs.com/<site>, https://wd<N>.myworkdaysite.com/recruiting/<company>/<site>, a search results page with filters applied (they are kept), or a single job link.

## `searchTerms` (type: `array`):

Job title or keywords, searched on each company's site (the same search as the careers page). Each keyword is a separate search; results are de-duplicated. Leave empty for all open jobs. If you give keywords but no companies, the largest Workday employers are searched.

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

Maximum number of jobs across the whole run. Leave empty for no limit.

## `maxItemsPerCompany` (type: `integer`):

Cap per company, so one big employer doesn't use up the whole run. Leave empty for no per-company limit.

## `includeDetails` (type: `boolean`):

Adds the full description (text + HTML), parsed salary range, exact posted and closing dates, time type, all locations, legal employer and similar jobs. Turn off for a faster, cheaper list of titles, locations and links.

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

Countries, provinces/states or cities, e.g. Canada, Ontario, Toronto, New York. Matched to each site's own location filters; several locations are combined with OR.

## `remoteTypes` (type: `array`):

Only remote, hybrid or on-site jobs. Uses the site's own filter where it has one; otherwise the job's listed arrangement.

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

Full-time, part-time, contract, temporary or internship/co-op — matched to each site's own job type filters.

## `jobCategories` (type: `array`):

Job families / departments, e.g. Technology, Finance, Sales, Engineering. Matched to each site's job category filter.

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

Only jobs posted in the last N days (uses the exact posting date).

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

Remembers every job this actor has returned to you and skips it next time — schedule the actor daily for a new-jobs feed. You only pay for new jobs.

## `onlyNewStateKey` (type: `string`):

Use a different name per saved task/schedule to keep their “already seen” lists separate.

## `maxCompanies` (type: `integer`):

With keywords but no companies, this many of the largest Workday employers are searched (filtered to those hiring in your locations).

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

Requests in flight across all companies.

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

Apify datacenter proxy works well and is cheapest. If a site blocks it, that site automatically switches to residential proxies.

## Actor input object example

```json
{
  "companies": [
    "TD",
    "NVIDIA"
  ],
  "searchTerms": [
    "data analyst"
  ],
  "maxItems": 50,
  "maxItemsPerCompany": 25,
  "includeDetails": true,
  "onlyNew": false,
  "onlyNewStateKey": "default",
  "maxCompanies": 150,
  "maxConcurrency": 24,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped job postings.

## `run` (type: `string`):

Status and statistics for this run.

# 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": [
        "TD",
        "NVIDIA"
    ],
    "searchTerms": [
        "data analyst"
    ],
    "maxItems": 50,
    "maxItemsPerCompany": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/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": [
        "TD",
        "NVIDIA",
    ],
    "searchTerms": ["data analyst"],
    "maxItems": 50,
    "maxItemsPerCompany": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/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": [
    "TD",
    "NVIDIA"
  ],
  "searchTerms": [
    "data analyst"
  ],
  "maxItems": 50,
  "maxItemsPerCompany": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/workday-jobs-scraper --silent --output-dataset

```

## MCP server setup

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