Workday Jobs Scraper for myworkdayjobs.com
Pricing
from $0.75 / 1,000 results
Workday Jobs Scraper for myworkdayjobs.com
Reads any Workday careers site on myworkdayjobs.com through the tenant's own CXS search API and returns the requisition ID, title, employmentType, isRemote, postedAt, apply URL and a location split into city, state and country. Paginates a whole board 20 postings at a time.
Pricing
from $0.75 / 1,000 results
Rating
0.0
(0)
Developer
String
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 days ago
Last modified
Categories
Share
What does Workday Job Board Scraper do?
A Workday careers site is a React shell. Load one and the served HTML has no postings in it at all. Every board is backed by the tenant's own CXS search API, which answers an unauthenticated POST with the same JSON the site renders from, and that API is what this Actor reads.
Hand it a careers-site URL such as
https://salesforce.wd12.myworkdayjobs.com/External_Career_Site and it returns the board's postings
with requisition id, title, employment type, remote flag, posted date, apply URL, and a location split
into city, state and country.
Nothing is per-company. A Workday address encodes everything needed: the host names the tenant and its
shard (salesforce.wd12), and the first path segment names the board (External_Career_Site). Those
two rebuild the API path for any board on the platform.
- The board page, a locale-prefixed page such as
/en-US/External_Career_Site, a link to one posting, and the CXS endpoint itself all collapse to the same board and cost one fetch. - Workday answers
HTTP_400to any page larger than 20 postings, so a full board is always paginated 20 at a time, stopping at the board's own reported total. - Pages are scheduled only while rows are still wanted, so a hundred boards under a thousand-row cap fetch a thousand rows rather than a hundred boards in full.
- No Workday account, cookie or API key. This is the external careers site a logged-out visitor sees.
What data does it extract?
| Field | Type | Description |
|---|---|---|
jobId | string | Workday's requisition id as printed under the posting title, for example JR284401 |
title | string | The posting title |
company | string | Always null. See the FAQ |
tenant | string | The Workday tenant, read from the host, for example salesforce |
location | string | The displayed location, verbatim. May read 3 Locations when a posting is open in several offices |
city | string | Resolved from the location, or from the posting's own URL when the display location is absent or says 3 Locations |
state | string | US state or Canadian province code |
country | string | ISO 3166 alpha-2 code |
isRemote | boolean | true when the location or Workday's remoteType names remote, virtual, home office or telecommute |
department | string | Always null. See the FAQ |
employmentType | string | Workday's timeType, for example Full time |
postedAt | string | Calendar date, YYYY-MM-DD, reconstructed from Workday's relative label |
jobUrl | string | Direct link to the posting |
boardUrl | string | The careers site a person would open |
sourceUrl | string | The CXS endpoint the row came from |
collectedAt | string | ISO 8601 timestamp of the run |
How the location is resolved
Workday tenants write the same address every way round. Reno, NV, USA.VA.Reston,
California - San FranciscoUSA TX Houston Virtual are all real forms from production boards.
So the parts are recovered by punctuation first, falling back to whitespace only when the tenant used
none, and then each part is resolved by what it is rather than by where it sits. That is why
Denver, CO, USA and USA, CA, Pleasanton both come out correctly. A two-letter part is tried as a US
or Canadian region before a country, so the CO in Denver, CO, USA stays Colorado instead of becoming
Colombia. The trade is that a bare CA always reads as California.
Fragments that describe how a role is worked rather than where it sits, like Virtual or
Home OfficeEMEA and APAC are
allowed to be neither a city nor a country.
How postedAt is derived
The search API publishes no timestamp. It publishes Posted 4 Days Ago, so the date is reconstructed
against the run's own clock. Posted 30+ Days Ago is left null on purpose: the plus is an open
bound, and dating it exactly 30 days back would invent a day the board never claimed.
Why scrape Workday?
Workday is the ATS of large employers. If you are tracking hiring at enterprises, this is where the requisitions actually live, and the CXS API returns them as clean JSON rather than as rendered markup.
- Monitor enterprise headcount direction across a named competitor set, run on a schedule.
- Detect a new site or market entry from where requisitions start appearing.
- Feed a job board or talent CRM directly from the employer's board, keyed on a stable
jobId. - Build recruiting lists filtered on
city,state,countryorisRemote. - Score sales accounts on hiring signals, weighting by
postedAtfreshness. - Track how much of a large employer's hiring is genuinely remote, using the flag rather than the title.
How to use it
- Follow the employer's "careers" or "search jobs" link until the address bar shows
<tenant>.wd<N>.myworkdayjobs.com/<Board>. Copy the URL. A single posting's URL works too. - Add it to Job boards, up to 100 per run.
- Set Maximum results. Boards paginate 20 at a time, so this is what bounds the request count.
- Raise Concurrency toward 10 when collecting many boards.
- Run it, then export the dataset as JSON, CSV, Excel or XML, or read it over the API.
Input
| Field | Type | Default | Description |
|---|---|---|---|
boards | array of strings | required | Workday careers-site URLs on myworkdayjobs.com. Between 1 and 100 entries |
maxItems | integer | 1000 | Cap on dataset rows, up to 50,000 |
concurrency | integer | 5 | Requests in flight at once, up to 10 |
{"boards": ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site","https://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite"],"maxItems": 3000,"concurrency": 5}
Board segments are compared case-insensitively, so /Ames and /ames are one board rather than two
identical fetches. A host outside myworkdayjobs.com is rejected with a reason instead of fetched.
Output
One row per posting. Illustrative shape:
{"jobId": "JR284401","title": "Lead Solution Engineer","company": null,"tenant": "salesforce","location": "California - San Francisco","city": "San Francisco","state": "CA","country": "US","isRemote": false,"department": null,"employmentType": "Full time","postedAt": "2026-08-16","jobUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site/job/California---San-Francisco/Lead-Solution-Engineer_JR284401","boardUrl": "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site","sourceUrl": "https://salesforce.wd12.myworkdayjobs.com/wday/cxs/salesforce/External_Career_Site/jobs","collectedAt": "2026-08-20T09:14:02.118Z"}
The run also writes a SUMMARY record holding the item count, the failure count and each failed board
or page with its error.
How much does it cost?
Pay per event, charged once per result row written to the dataset. The current rate is on this Actor's pricing tab, and a board that is rejected writes no rows and costs nothing.
At 20 postings per request, requests track rows closely, so maxItems is effectively the budget dial.
Collecting the first 200 postings of fifty boards is much cheaper than collecting fifty boards in full,
and the scheduler here is built to make that first case work rather than fetching everything and
throwing the surplus away.
Runs started from an Apify free plan stop at 250 requests and 250 results and report the limit in the run status. Any paid plan runs the full input. Because pagination turns one board into many fetches, the second pass of a free-plan run is bounded against whatever the first pass left rather than against the full allowance again.
Using it with the Apify API
import { ApifyClient } from "apify-client";const client = new ApifyClient({ token: "<YOUR_APIFY_TOKEN>" });const run = await client.actor("usestring/workday-jobs").call({boards: ["https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"],maxItems: 3000,concurrency: 5});const { items } = await client.dataset(run.defaultDatasetId).listItems();const remoteShare = items.filter((job) => job.isRemote).length / items.length;console.log(`${items.length} postings, ${(remoteShare * 100).toFixed(1)}% remote`);
Read the run's SUMMARY record from its key-value store to see which boards, if any, were rejected.
Is it legal to scrape Workday?
An external Workday careers site is published so candidates and search engines can find open roles. This Actor calls the same unauthenticated CXS endpoint the public site calls, with no account, no session cookie and no API key. Internal Workday instances, which require a login, are out of reach and out of scope.
The output describes requisitions, not people. No applicant data, no application counts, no recruiter
contacts. company and department are null because Workday publishes neither, so there is nothing
personal or proprietary being reconstructed here.
Local law and the terms you have agreed to still govern what you may do with collected data. This is context, not legal advice.
Related actors
- Taleo Job Board Scraper covers the Oracle platform many of these employers migrated away from, and some still run alongside.
- iCIMS Job Board Scraper covers the other large enterprise ATS you will meet in the same employer list.
- Greenhouse Job Board Scraper returns a whole board in a single request for technology employers.
- Ashby Job Board Scraper covers the well-funded startups that have not reached Workday yet.
- Glassdoor Jobs Scraper adds the reputation layer around an enterprise requisition.
FAQ
How do I find a company's Workday careers site? Follow the careers link on the employer's own site.
Workday sites look like https://<tenant>.wd<N>.myworkdayjobs.com/<Board>, where <N> is a data-centre
number. Paste the whole URL, or paste a single posting's URL and let the Actor reduce it to the board.
How many postings come back per request? Twenty. Workday rejects anything larger with HTTP_400, so
a 2,000-posting board is 100 requests and there is no way around that.
Why is there no company name? Workday publishes none on any public endpoint. The search response has
no such field, and the detail endpoint carries only the hiring legal entity, which is often something
like 4 LZB Retail, Inc. rather than the brand a person would recognise. Rather than fill the column
with something misleading it is left null, and tenant is the identity to join on.
Why is there no department? For the same reason. Department exists on a Workday board only as the
jobFamilyGroup facet, which counts how many postings sit in each category without naming the category
of any individual posting.
How accurate is postedAt? It is exact for anything posted within the last 30 days, since
Posted 4 Days Ago resolves to a real calendar date against the run clock. Beyond that Workday only
says 30+ Days Ago, and the field is null.
Do results ever duplicate? They are de-duplicated on jobUrl before being written, which is
necessary because a board whose reported total understates it hands back page one again past the end
instead of terminating.
What happens if a board rejects the search? Workday answers a rejected search with an error envelope
carrying its own httpStatus inside a 200 response, so it would otherwise look like a successful empty
board. That envelope is read, and the board is recorded under failures in the run's SUMMARY.
Feedback
If a board returns nothing, or a location splits into the wrong fields, open an issue from this Actor's Store page with the board URL. Workday location strings vary more than anything else here, and a real example is what it takes to handle a new form.