# Workday Jobs Scraper — Company Career Sites (`tortuga/workday-jobs-scraper`) Actor

Scrape Workday jobs from any company's Workday career site (myworkdayjobs.com): job postings with title, locations, posted date, requisition id, job URL and full description. Filter by keyword, location, remote and posting age; monitor new jobs on a schedule. No login, no browser.

- **URL**: https://apify.com/tortuga/workday-jobs-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Jobs
- **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 jobs

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: Company Career Sites

Scrape Workday jobs from any company's Workday career site. Paste a `myworkdayjobs.com` career-site URL (or the company's own careers page) and get every public job posting as one clean row: title, company, every location and its country, remote or hybrid, time type, posting date, requisition id, job and apply links, the **full description** and the **pay range** when the posting states one.

The actor reads the same public JSON endpoints that the Workday career site itself loads in your browser: no login, no API key, no headless browser. A career site with 2,000 jobs is read in about a hundred small requests, so runs take seconds and cost cents. Thousands of large employers (NVIDIA, Salesforce, banks, retailers, universities, hospitals) publish their jobs through Workday, and all of their external career sites work the same way.

Typical uses: job alerts for a list of target companies, hiring signals for sales and recruiting (who is hiring which roles, where), salary benchmarking from the pay ranges in job descriptions, feeding a job board, a spreadsheet or an LLM pipeline.

### What data does Workday Jobs Scraper extract?

| Field | Description |
|---|---|
| `jobId` | Stable unique id `workday:<tenant>/<site>:<requisition>`, e.g. `workday:nvidia/nvidiaexternalcareersite:JR2025461` |
| `atsJobId`, `requisitionId` | The requisition id Workday shows for the job (`JR2025461`, `R-12345`, ...) |
| `companyName`, `companySlug`, `careerSiteUrl` | Company (from the tenant name, the careers page it was found on, or your input), the Workday tenant and the career-site URL |
| `title` | Job title |
| `department` | The Workday job category the job was found in, when you filter by **Departments / job categories** (Workday's public list does not name categories otherwise) |
| `location`, `locations` | Location text as the company writes it, and every location of multi-location jobs (with **Include full job description**; the list alone says "3 Locations") |
| `country`, `countryCode` | Country of the job (ISO 3166-1 alpha-2), from the job page or read from the location text |
| `isRemote`, `isHybrid`, `workplaceType` | Remote / hybrid flags and `remote` / `hybrid` / `onsite` from Workday's remote type (job page) or from the location text |
| `employmentType` | Workday time type: `Full time` / `Part time` (job page) |
| `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salarySource` | The first pay range written in the description, e.g. "$164,000 - $261,500" per `year` (`salarySource: "description"`); Workday publishes no structured pay fields |
| `postedAt`, `postedAgo` | Posting date (UTC, ISO 8601): the exact date from the job page, or the date behind Workday's "Posted 3 Days Ago" label, which is kept in `postedAgo` |
| `url`, `applyUrl` | The job page on the career site and its Apply link |
| `description`, `descriptionHtml` | Full job description as readable text (with bullets) and as HTML (with **Include full job description**) |
| `detailsFetched`, `detailError` | Whether the job's own page was opened, and why not if it failed |
| `sourceUrl`, `scrapedAt` | Which input produced the job, and when |
| `changeType` | `new` in monitoring mode (see below) |

`ats` (always `workday`), `team`, `city`, `region`, `seniority`, `jobFunction` and `updatedAt` are kept so rows match our multi-ATS Career Site Jobs Scraper, but Workday's public endpoints do not publish them, so they stay empty.

### How to scrape Workday jobs

1. Paste career-site URLs into **Workday career site URLs**, for example `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` or `https://salesforce.wd12.myworkdayjobs.com/External_Career_Site`. A company careers page or homepage works too: the actor follows it to the Workday site it links to.
2. Or list sites you already know under **Career sites as tenant/site**: `nvidia/NVIDIAExternalCareerSite`, `salesforce/External_Career_Site`. The tenant is the first part of the `myworkdayjobs.com` host name and the site is the first path segment of the career-site URL; the actor finds the `wd1`/`wd5`/`wd12` data centre itself.
3. Optional filters: **Title keywords** (each is also sent to Workday's own search, so only matching pages are read), **Locations**, **Departments / job categories** (applied through the site's job-category facet), **Remote jobs only**, **Posted within (days)**, **Max jobs per career site**.
4. Keep **Include full job description** on for the description, every location, the exact posting date, time type and remote type (one extra request per job, see Pricing); turn it off for a cheap, fast list.
5. Click **Start**. Jobs appear in the **Output** tab, newest first per site; export JSON, CSV or Excel, or read them through the API.

### Input example

```json
{
  "startUrls": [
    { "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" },
    { "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site?locationCountry=bc33aa3152ec42d4995f4791a106ed09" }
  ],
  "boards": ["cvshealth/CVS_Health_Careers"],
  "keywords": ["software engineer", "data scientist"],
  "locations": ["United States", "Remote"],
  "postedWithinDays": 14,
  "includeDescription": true,
  "maxItemsPerCompany": 50,
  "maxItems": 200
}
```

### Output example

One Salesforce job with **Include full job description** on (description shortened here):

```json
{
  "jobId": "workday:salesforce/external_career_site:JR363410",
  "atsJobId": "JR363410",
  "ats": "workday",
  "companyName": "Salesforce",
  "companySlug": "salesforce",
  "title": "Executive Operations & Leadership Engagement Director",
  "department": null,
  "location": "Georgia - Atlanta • Illinois - Chicago • Washington - Seattle • Indiana - Indianapolis • Texas - Austin",
  "locations": ["Georgia - Atlanta", "Illinois - Chicago", "Washington - Seattle", "Indiana - Indianapolis", "Texas - Austin"],
  "country": "United States",
  "countryCode": "US",
  "isRemote": false,
  "isHybrid": true,
  "workplaceType": "hybrid",
  "employmentType": "Full time",
  "salaryText": "$164,000 - $261,500",
  "salaryMin": 164000,
  "salaryMax": 261500,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salarySource": "description",
  "postedAt": "2026-10-12T00:00:00Z",
  "postedAgo": "Posted Today",
  "requisitionId": "JR363410",
  "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site/job/Georgia---Atlanta/Executive-Operations---Leadership-Engagement-DirectorDirector_JR363410",
  "applyUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site/job/Georgia---Atlanta/Executive-Operations---Leadership-Engagement-DirectorDirector_JR363410/apply",
  "careerSiteUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site",
  "description": "To get the best candidate experience, please consider applying for a maximum of 3 roles within 12 months ...",
  "descriptionHtml": "<p style=\"text-align:left\"><i>To get the best candidate experience ...",
  "detailsFetched": true,
  "sourceUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site",
  "scrapedAt": "2026-11-01T12:00:00Z"
}
```

With descriptions off, a row carries the list data only: title, the first location text (or "5 Locations"), `postedAgo` with its approximate `postedAt`, requisition id, company and URLs.

### Which Workday URLs work?

- The career site itself: `https://<tenant>.wd<N>.myworkdayjobs.com/<site>`, with or without a locale (`/en-US/<site>`).
- A search on the career site with filters you set there (location, job category, time type): `https://salesforce.wd12.myworkdayjobs.com/External_Career_Site?locationCountry=...`. The query parameters are applied as Workday facets and `?q=` becomes the search text, so you get exactly what the site shows.
- A single job URL (`.../<site>/job/<location>/<title>_<requisition>`): the whole site the job belongs to is scraped.
- Sites hosted at `https://wd<N>.myworkdaysite.com/recruiting/<tenant>/<site>` (some universities and public bodies).
- The JSON endpoint URL `.../wday/cxs/<tenant>/<site>/jobs`, if you already use it.
- A company careers page or homepage: the actor opens it, looks for links, iframes and scripts that point to a Workday site, follows the "Careers" / "Jobs" link and tries `/careers` and `/jobs` (at most 4 pages). Inputs where no Workday site is found are listed in the run's `SUMMARY` and cost nothing.

Internal career sites that require a Workday login are not supported, and neither are non-Workday systems: for Greenhouse, Lever, Ashby, SmartRecruiters, Workable and other ATSs use our Career Site Jobs Scraper, which outputs the same rows.

### Does it need a login or an API key?

No. A Workday career site is a JavaScript app that loads its jobs from a public JSON endpoint on the same host (`/wday/cxs/<tenant>/<site>/jobs`, 20 jobs per page, plus one request per job page). The actor calls those endpoints exactly like the page does, anonymously and without cookies, and reads only published job ads. Candidate accounts, applications, internal postings and anything behind a login are never touched.

### Monitor new Workday jobs on a schedule

Turn on **Only new jobs (monitoring)** and save the input as a task with a Schedule (Apify Console → Schedules), e.g. every morning. Each run remembers the jobs that earlier runs of the same input returned and outputs only the jobs that are **new** since then, with `changeType: "new"`; jobs seen before are not output, not charged, and their job pages are not opened. With **Max jobs per career site** set, monitoring watches that many newest jobs per site. Use **Monitoring key** to keep several schedules on the same sites apart. This is the cheapest way to get job alerts or hiring signals for a list of companies that hire through Workday.

### Pricing

Pay per event, no subscription, and the event prices include the platform usage of the run:

- **$0.0015 per job** saved to the dataset.
- **+$0.001 per job** when **Include full job description** is on, because Workday's job list has no descriptions and the actor opens each job's page (which also adds every location, the exact posting date, time type and remote type). Job pages opened only to apply a location or remote filter are free.

1,000 jobs cost $1.50 as a list, or $2.50 with full descriptions. Monitoring runs charge only for new jobs. Inputs that point to no Workday site cost nothing.

### Proxy note

Workday career sites answer the same public requests their own pages make, so by default the actor connects directly (no proxy), which is also the fastest. Turn on Apify Proxy (datacenter) only if a run log shows 403 or 429 answers. No residential proxy and no Unblocker are ever needed.

### Integrations and API

Use the results in Make, Zapier, n8n, Google Sheets, Airtable or your CRM, or call the actor from Python / Node.js with the Apify client (see the **API** tab). A Schedule plus monitoring gives you a daily feed of new jobs at your target companies.

### Is it legal to scrape Workday?

The actor reads only job ads that companies publish openly on their Workday career sites, through the same public endpoints those sites use. It does not log in, does not collect candidate or employee data, and does not access anything hidden or internal. Recruiter names that a company chooses to print in a job description stay part of that description. You are responsible for how you use the data and for complying with the sites' terms and applicable law (e.g. the GDPR).

### Support

A career site that does not work, a field you miss? Open an issue in the **Issues** tab; it is usually answered within a day.

### Related scrapers

- [Career Site Jobs Scraper](https://apify.com/tortuga/career-site-jobs-scraper): Greenhouse, Lever, Workday & Ashby
- [Greenhouse Jobs Scraper](https://apify.com/tortuga/greenhouse-jobs-scraper): Job Boards & Postings
- [Lever Jobs Scraper](https://apify.com/tortuga/lever-jobs-scraper): Job Boards & Postings
- [Ashby Jobs Scraper](https://apify.com/tortuga/ashby-jobs-scraper): Job Boards & Postings

### Found it useful?

A ★ review on this Actor's Apify Store page helps other users find it and tells us what to improve. Issues and feature requests are welcome in the Actor's **Issues** tab.

# Actor input Schema

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

Workday career sites to scrape: https://<tenant>.wd<N>.myworkdayjobs.com/<site> (e.g. https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite), a search URL with filters you set on the site (they are applied as Workday facets; ?q= becomes the search text), a single job URL (its whole site is scraped), a https://wd<N>.myworkdaysite.com/recruiting/<tenant>/<site> URL, or a company careers page / homepage that links to its Workday site.

## `boards` (type: `array`):

Optional: Workday sites you already know, written as tenant/site, e.g. nvidia/NVIDIAExternalCareerSite or salesforce/External_Career_Site (the tenant is the first part of the myworkdayjobs.com host name, the site is the first path segment of the career-site URL). The actor finds the wd<N> data centre itself; tenant.wd5/site or the full URL skips that step. Via the API you can also pass objects: {"tenant": "nvidia", "site": "NVIDIAExternalCareerSite", "companyName": "NVIDIA"}.

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

Keep only jobs whose title contains at least one of these words or phrases (case-insensitive), e.g. engineer, sales, "product manager". Up to 5 keywords are also sent to Workday's own search, so only matching pages are read. Leave empty for all jobs.

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

Keep only jobs whose location text or country contains one of these, e.g. London, Germany, US, Remote. Jobs listed as '3 Locations' have their job page opened to see every location (not charged unless descriptions are on). Leave empty for all locations.

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

Keep only jobs in Workday job categories (job families) whose name contains one of these, e.g. Engineering, Sales. Applied through the career site's own category facet, so only matching jobs are read, and the matched category is written to the `department` field. If no category of a site matches, that site returns nothing and the run's SUMMARY lists the categories it offers.

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

Keep only jobs whose Workday remote type is Remote (or whose location or title says Remote). The job list does not carry the remote type, so the actor opens each candidate's job page to check (not charged unless descriptions are on).

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

Keep only jobs published in the last N days. The job list only shows 'Posted 3 Days Ago' style dates ('Posted 30+ Days Ago' counts as 31 days), so without descriptions the dates are approximate; with descriptions the exact posting date from the job page is used. Paging stops once a whole page is older than this.

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

Open each job's page for the full description (plain text and HTML), every location of multi-location jobs, the exact posting date, time type (Full time / Part time), remote type and the pay range when the text states one. One extra request per job, charged as 'Job details fetched'. Off = list data only (title, first location text, 'Posted N Days Ago', requisition id, URL).

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

Stop after this many jobs in total. Keeps cost predictable.

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

Optional cap per career site (newest jobs first). With monitoring on, it is the number of newest jobs watched per site.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this input returned and output only jobs that are new since then. Use with a Schedule; jobs seen before are not output and not charged.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same input stay separate; defaults to a key derived from the input.

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

Not needed: Workday career sites answer the same public JSON requests their own pages make, and direct requests are fastest. Turn on Apify Proxy (datacenter) only if a run log shows 403/429 answers. No residential proxy or Unblocker is ever needed.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
    },
    {
      "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
    }
  ],
  "remoteOnly": false,
  "includeDescription": true,
  "maxItems": 20,
  "maxItemsPerCompany": 10,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
        },
        {
            "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
        }
    ],
    "maxItems": 20,
    "maxItemsPerCompany": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/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 = {
    "startUrls": [
        { "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite" },
        { "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site" },
    ],
    "maxItems": 20,
    "maxItemsPerCompany": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/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 '{
  "startUrls": [
    {
      "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
    },
    {
      "url": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
    }
  ],
  "maxItems": 20,
  "maxItemsPerCompany": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call tortuga/workday-jobs-scraper --silent --output-dataset

```

## MCP server setup

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