# Workday Jobs Scraper (`boncross/workday-jobs`) Actor

Scrape every open job from a Workday careers board. Give the board URL and get the job title, employer, location, contract type, posting date and the full advert. Filter by title, location or remote working, and export to CSV, JSON or Excel.

- **URL**: https://apify.com/boncross/workday-jobs.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (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 job-details

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

### What is Workday Jobs Scraper?

Workday boards tend to be big. Salesforce's had more than 1,500 open jobs when we measured it, and others pass 2,000. Workday Jobs Scraper is built for that size, so you get the whole board and not the first few pages. It read two boards of more than 2,000 jobs each, 6,365 jobs in all, in 70 seconds, and pulled 1,000 full adverts from Salesforce in 75 to 98 seconds without a single refusal.

Paste the board URL and you get each job with its title, location, contract type, posting date and the complete advert.

Where it helps most:

- **You get boards past 2,000 jobs to the end.** Very large boards are read group by group so the count keeps going.
- **Keyword search is the board's own.** It returns the jobs you'd get by typing the same words into the board's search box, matching the title and the advert text.
- **A filtered link stays filtered.** Set category, location, job type or time type on the board, copy the URL, and the run uses exactly that.
- **You choose depth by price.** A listing-only scan of a whole board takes seconds at half the cost. Full adverts run at about 890 jobs a minute.

Worth knowing up front: Workday boards publish no department and no pay as fields, so there are no columns for them.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 26 of 26 live checks on its inputs and filters passed on 7 October 2026
- 5 boards run the same day, one made up: 60 jobs, 1 error row
- 8 of 8 sampled links name the job they lead to
- Charges matched the rows: 1 start, 4 boards, 60 jobs

### How to scrape a Workday board

1. [Sign up for a free Apify account](https://console.apify.com/sign-up) and open [Workday Jobs Scraper](https://apify.com/boncross/workday-jobs).
2. Paste the board URL. It looks like `company.wd3.myworkdayjobs.com/en-US/Careers`, or the shared form `wd3.myworkdaysite.com/en-US/recruiting/company/Careers`.
3. Add a keyword or filters, or leave them empty for the whole board.
4. Decide whether you want full adverts. They're on by default.
5. Press Start. When it finishes, export to Excel, CSV or JSON.

A URL for some other recruitment platform is reported in a row of its own, and the remaining boards are still read.

### ⬇️ Input

The board URL is the one required thing. You can list several, or load them from a file or a Google Sheet with Start URLs.

"Max jobs per board" and "Max jobs for the whole run" both default to 0, which means no limit. On a board this size you'll usually want one of them, or a keyword.

**One board**

```json
{
  "boardUrls": ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],
  "maxItemsPerBoard": 200
}
```

**Engineering roles only, several boards**

```json
{
  "boardUrls": [
    "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site",
    "https://sharecare.wd1.myworkdayjobs.com/en-US/Sharecare_Careers"
  ],
  "titleIncludes": ["engineer", "developer"],
  "maxItems": 500
}
```

**Hybrid or remote jobs only**

```json
{
  "boardUrls": ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],
  "workplaceTypes": ["Hybrid", "Remote"],
  "includeUnknownWorkplace": false
}
```

**Remote jobs posted in the past seven days**

```json
{
  "boardUrls": ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],
  "onlyRemote": true,
  "maxDaysOld": 7
}
```

**A daily run that returns only the board's new jobs**

```json
{
  "boardUrls": ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],
  "onlyNew": true,
  "dedupStoreName": "workday-seen"
}
```

How the main inputs behave on Workday:

- **Keyword** runs the board's own job search with your words. If your pasted link already has a search in it, that search is kept and the keyword matches job titles on top of it.
- **Work type** costs more here than on other platforms, and you should know why. Workday states On-site, Hybrid or Remote on the advert, not in the job list. So each advert is fetched, and billed as a fetched advert, before its job is kept or dropped. With "Max jobs per board" set, adverts are fetched only until that many matching jobs are found. Jobs that state no arrangement (some employers never do) are kept unless "Keep jobs with no stated work type" is off, and one whose location or title says remote counts as Remote.
- **Fetch full job adverts** opens each job for its advert. Turn it off when you want a fast, cheap listing-only scan.
- **Title must contain**, **Title must not contain** and **Location must contain** filter on words, ignoring case.
- **Remote jobs only** keeps jobs marked remote and drops jobs that don't say.
- **Posted within (days)** keeps the last N days, and 0 keeps everything.
- **Include advert text** is on, **Include advert HTML** is off. The HTML makes rows much larger.

#### For developers

- Keys: `boardUrls`, `startUrls`, `maxItemsPerBoard`, `maxItems`, `keyword`, `titleIncludes`, `titleExcludes`, `locationIncludes`, `onlyRemote`, `workplaceTypes`, `includeUnknownWorkplace`, `maxDaysOld`, `fetchDetails`, `includeDescription`, `includeDescriptionHtml`, `onlyNew`, `dedupStoreName`, `maxConcurrency`, `delayMs`.
- A pasted link keeps its filters and its search exactly as the board applied them: category, location, job type, time type and any other filter the board offers.
- Boards with more than 2,000 jobs are read group by group, by job family or country, whichever the board offers.
- A capped run with no filters stops as soon as it has enough.
- Several boards are read at once and adverts are fetched side by side. A very large board with adverts is read at a steady pace the site accepts.
- `onlyNew` with a `dedupStoreName` skips jobs an earlier run with the same store name returned, and the store is saved every minute. An empty store name remembers nothing.
- `maxConcurrency` defaults to 8, the fastest level measured clean. `delayMs` defaults to 0. You can leave both.
- Rows are saved as they're collected, so a run that reaches its timeout keeps what it delivered. A run the platform restarts carries on without delivering or charging any job twice.

### ⬆️ Output

You get one row per job. The Overview view shows title, employer, location, contract type, posting date and advert link.

```json
{
  "id": "JR361902",
  "url": "https://salesforce.wd12.myworkdayjobs.com/en-US/External_Career_Site/job/California---Remote/Sr-Solution-Engineer_JR361902-1",
  "title": "Sr Solution Engineer",
  "company": "salesforce",
  "location": "California - Remote",
  "employmentType": "Full time",
  "isRemote": true,
  "postedAt": "2026-09-25",
  "postedText": "Posted Yesterday",
  "description": "To get the best candidate experience, please consider applying for a maximum of 3 roles wi…",
  "ats": "workday",
  "tenant": "salesforce",
  "scrapedAt": "2026-09-26T07:28:18.711Z",
  "boardUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
}
```

- `company` is the employer's Workday tenant name (`salesforce`), not its legal name.
- `postedAt` is the advert's own posting date when the full advert is fetched. Without it, it's the date that Workday's "Posted 3 Days Ago" points to. "Posted 30+ Days Ago" leaves it empty, and the wording is always kept in `postedText`.
- With the full advert, `locations` lists each location the job is open in, and `workplaceType` gives `On-site`, `Hybrid` or `Remote` where the employer publishes it.
- `isRemote` is true or false only where the location, title or work type says so. Otherwise it's null.

### What data can you extract from a Workday board?

| Field | Field |
|---|---|
| 💼 Job title | 🏢 Employer |
| 📍 Location | Contract type |
| 📄 Full advert text | Advert HTML, optional |
| 📅 Posted date | Posting date as Workday wrote it |
| 🏠 Remote flag | 🔗 Advert link |
| Job id | Board name |
| Board URL | When the row was collected |
| On-site, hybrid or remote, with the full advert | Every location, with the full advert |

### How large a board can it read, and how fast?

Whole runs on Apify, 1 and 2 October 2026:

| Run | Result |
|---|---|
| Salesforce's whole board, no adverts | 1,503 jobs in 9 s |
| Four boards, up to 100 jobs each with full adverts | 294 to 295 jobs in 8 to 11 s |
| 20 jobs with full adverts | 20 jobs in 3 to 7 s |
| Salesforce, 1,000 jobs with full adverts | 1,000 jobs in 75 to 98 s, none refused |
| Two 2,000+ job boards, 600 jobs each with full adverts | 1,200 jobs in 81 s (about 890 a minute), none refused |
| Two boards with more than 2,000 jobs each, listing only | 6,365 jobs in 70 s |

At the bulk rate, one run inside the default one-hour timeout gets you roughly **50,000 jobs with full adverts**, or far more as a listing only.

The job id, link, title, employer and advert were on every row of the capped run.

### How much does it cost to scrape Workday jobs?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.001 | $0.001 | $0.001 | $0.001 |
| `board-scanned`, per careers board read | $0.0002 | $0.0002 | $0.0002 | $0.0002 |
| `job-detail`, per job with the full advert | $0.001 | $0.0009 | $0.0008 | $0.0007 |
| `job-listed`, per job without the full advert | $0.0005 | $0.00045 | $0.0004 | $0.00035 |

Enterprise plans pay the Business price.

**$1.00 per 1,000 jobs** with the full advert on the Free plan, or $0.70 on Business. Listing-only it's $0.50 per 1,000 on the Free plan and $0.35 on Business. There's no proxy to pay for, and platform usage is included.

- 500 jobs with full adverts from one board: $0.001 + $0.0002 + 500 × $0.001 = **$0.5012** ($0.3512 on Business).
- The same 500 as a listing: $0.001 + $0.0002 + 500 × $0.0005 = **$0.2512** ($0.1762 on Business).

Each job is billed once:

- `job-detail` when the job's full advert was opened. That includes an advert whose row "Posted within (days)" then drops.
- `job-listed` for a job delivered without its advert, either because adverts are off or because one couldn't be opened.
- `board-scanned` once for each board read.

On a big board your choice matters. A 1,500-job board costs about $1.50 with adverts and about $0.75 without on the Free plan. Apify's $5 of monthly free credits covers about 4,900 jobs with adverts.

### Limitations

- **Workday boards only.** A board on another platform returns a row saying so.
- **No department and no salary.** Workday boards don't publish them as fields. Pay, where an employer gives it, is only in the advert text.
- **`company` is the tenant name**, for example `salesforce`. Keep your own mapping if you need legal names.
- **The job list gives dates as wording.** With full adverts on, you get the advert's own date. With them off, the date is derived from "Posted 3 Days Ago", and "Posted 30+ Days Ago" leaves it empty.
- **Boards over 2,000 jobs.** They're read group by group, and a job the board files under no group could be missed.
- **Location is only as good as the employer's listing.** You see what the board shows.
- **An occasional advert is a placeholder.** One employer posted a job whose whole body read "TBC". You get what the board holds.
- **No applications** can be submitted through this actor.

### FAQ

#### Can it read a board with more than 2,000 jobs?

It can, and you don't have to do anything special. Two such boards returned 6,365 jobs in a listing-only run. They're read by job family or by country, so the only job at risk is one the board has filed under no group at all.

#### Why does the work-type filter cost more on Workday?

The arrangement is on the advert, so each advert has to be opened to check it, and an opened advert is billed `job-detail` whether or not the job is kept. Set "Max jobs per board" and fetching stops once that many matches are found.

#### Why is there no salary or department column?

Workday boards don't publish either as a field. If an employer mentions pay, it's in the advert text, which you can search with a keyword.

#### Why is `postedAt` empty on some jobs?

In a listing-only run, a job marked "Posted 30+ Days Ago" has no date to derive. Turn "Fetch full job adverts" on and the advert's own posting date is used.

#### How do I monitor one employer's new jobs?

Schedule the run with "Only jobs not seen before" on and a store name. Listing-only is enough to spot new jobs, and it's the cheaper mode.

#### My list mixes Workday with other platforms. What should I use?

[ATS Jobs Scraper](https://apify.com/boncross/ats-jobs) reads Workday and eight other platforms from one list of URLs.

#### Do I need a proxy or a Workday account?

No to both. There's nothing to configure.

#### Is scraping Workday boards legal?

The actor reads adverts that employers post on public boards, without signing in. Gathering public data is generally lawful in the UK and EU. Responsibility for how the data is used sits with you.

### Schedules, API and MCP

A daily schedule with only-new on is the common setup for watching your target employers, with a webhook, Slack, Google Sheets, Zapier, Make or Airbyte receiving each run's rows.

From code, call Apify's run-sync-get-dataset-items endpoint for a capped run and you get the rows in the response. For a whole large board, start the run and read the dataset when it finishes. Use `apify-client` in Python or JavaScript.

MCP-capable AI clients can add `https://mcp.apify.com` and call the actor as a tool, for example to pull a company's open roles in one country and group them by title.

### More from BonCross

- [Ashby Jobs Scraper](https://apify.com/boncross/ashby-jobs): Every open job on an Ashby careers board.
- [ATS Jobs Scraper](https://apify.com/boncross/ats-jobs): Jobs from any company careers page.
- [Greenhouse Jobs Scraper](https://apify.com/boncross/greenhouse-jobs): Every open job from a Greenhouse careers board.
- [Lever Jobs Scraper](https://apify.com/boncross/lever-jobs): A Lever careers board for every open job.
- [CharityJob Scraper](https://apify.com/boncross/charityjob-jobs): UK charity and non-profit jobs from CharityJob.
- [Glassdoor Job Scraper](https://apify.com/boncross/glassdoor-jobs): Glassdoor job listings for a role and location.

### Your feedback

If a board's job count here is lower than the count on the board itself, we want the URL. Post it on the Issues tab in Apify Console. BonCross reads every issue and replies there.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/workday-jobs/changelog.md

# Actor input Schema

## `boardUrls` (type: `array`):

One or more Workday careers boards, for example https://freshfields.wd3.myworkdayjobs.com/en-US/FBD_101

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

The same thing, but able to bulk-load Workday boards from a file or a Google Sheet.

## `maxItemsPerBoard` (type: `integer`):

Row limit for each board. 0 means no limit.

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

Row ceiling across every board in the run. 0 means no limit.

## `keyword` (type: `string`):

Searched with the board’s own job search, which matches the title and the advert text (the same results as typing it into the board’s search box). If a pasted board link already has its own search, that search is kept and the keyword keeps only jobs whose title contains it.

## `titleIncludes` (type: `array`):

Keep a job only if its title contains at least one of these words. Case-insensitive.

## `titleExcludes` (type: `array`):

Drop a job if its title contains any of these words. Case-insensitive.

## `locationIncludes` (type: `array`):

Keep a job only if its location contains one of these words, for example "London".

## `onlyRemote` (type: `boolean`):

Keep only jobs the employer marked as remote. Jobs where the board says nothing about remote working are dropped, not assumed.

## `workplaceTypes` (type: `array`):

Keep only jobs with these working arrangements, as the employer states them (the workplaceType column). Leave empty for all. Jobs whose board does not say are kept unless you turn off the option below; a job with no stated arrangement whose location or title says remote counts as Remote. Workday states the arrangement on the advert, so the job advert is fetched (and billed) before the job can be kept or dropped.

## `includeUnknownWorkplace` (type: `boolean`):

Only used with Work type. On (the default): jobs whose board says nothing about the arrangement are kept, because many employers never state it. Off: only jobs that state one of the chosen arrangements are kept.

## `maxDaysOld` (type: `integer`):

Keep only jobs posted in the last N days. 0 keeps everything.

## `fetchDetails` (type: `boolean`):

Open each job for its full advert. Turn off for a fast, cheap listing-only scan.

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

Include the job advert as plain text.

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

Also include the advert's original HTML. Makes rows considerably larger.

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

Skip jobs returned by an earlier run that used the same store name below.

## `dedupStoreName` (type: `string`):

Named key-value store that remembers job ids between runs. Leave empty to remember nothing.

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

How many requests run at once across the whole run. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## `delayMs` (type: `integer`):

Optional pause before each call, in milliseconds. 0 (the default) runs as fast as the parallel limit allows.

## Actor input object example

```json
{
  "boardUrls": [
    "https://freshfields.wd3.myworkdayjobs.com/en-US/FBD_101"
  ],
  "startUrls": [],
  "maxItemsPerBoard": 0,
  "maxItems": 0,
  "keyword": "",
  "titleIncludes": [],
  "titleExcludes": [],
  "locationIncludes": [],
  "onlyRemote": false,
  "workplaceTypes": [],
  "includeUnknownWorkplace": true,
  "maxDaysOld": 0,
  "fetchDetails": true,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "onlyNew": false,
  "dedupStoreName": "",
  "maxConcurrency": 8,
  "delayMs": 0
}
```

# Actor output Schema

## `dataset` (type: `string`):

Every job the run returned.

## `stats` (type: `string`):

Counts for the 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 = {
    "boardUrls": [
        "https://freshfields.wd3.myworkdayjobs.com/en-US/FBD_101"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/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 = { "boardUrls": ["https://freshfields.wd3.myworkdayjobs.com/en-US/FBD_101"] }

# Run the Actor and wait for it to finish
run = client.actor("boncross/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 '{
  "boardUrls": [
    "https://freshfields.wd3.myworkdayjobs.com/en-US/FBD_101"
  ]
}' |
apify call boncross/workday-jobs --silent --output-dataset

```

## MCP server setup

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