Workday Jobs Scraper — Any myworkdayjobs.com Site | $1.50/1K
Pricing
from $0.97 / 1,000 workday jobs scraper — any myworkdayjobs.com site | $1.50/1ks
Workday Jobs Scraper — Any myworkdayjobs.com Site | $1.50/1K
Scrape job postings from any company's Workday-hosted career site (myworkdayjobs.com). Paste the career-site URL — talks to Workday's CXS search API, no browser, no proxy. Returns title, location, remote type, seniority, employment type, requisition id, posted date, apply URL, description.
Pricing
from $0.97 / 1,000 workday jobs scraper — any myworkdayjobs.com site | $1.50/1ks
Rating
0.0
(0)
Developer
Vitalii Bondarev
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
3
Monthly active users
9 days ago
Last modified
Categories
Share
Workday Jobs Scraper — Any myworkdayjobs.com Career Site
For talent-intelligence, sourcing, and job-aggregation teams that need job postings from companies hosted on Workday — one of the largest ATS/HCM platforms, used by thousands of enterprises for their careers pages (myworkdayjobs.com).
Pay per result — from $1.50 / 1,000 jobs. No API key, no browser, no proxy. Uses Workday's own CXS (Candidate Experience Service) JSON API — the same API the career-page website itself calls in the browser.
How it works — access path
Paste a company's Workday career-site URL (the URL you see when you visit their
careers page, e.g. https://nike.wd1.myworkdayjobs.com/NikeCareers), and the
actor:
- Extracts
tenant(nike),wdServer(wd1), andsite(NikeCareers) from the URL. POSTs tohttps://<tenant>.<wdServer>.myworkdayjobs.com/wday/cxs/<tenant>/<site>/jobswith{"appliedFacets": {}, "limit": N, "offset": N, "searchText": ""}and paginates viaoffset/limituntil the listing is exhausted.- Optionally (
includeDescriptions=true, default)GETs the per-job detail endpoint.../wday/cxs/<tenant>/<site>/job/<externalPath>for each posting to fill in the full description, requisition id, remote type, and employment type — fields the listing call doesn't include.
This CXS URL/JSON pattern is structurally the same across every Workday
tenant — it isn't a per-company scrape, it's one integration that works for
any myworkdayjobs.com site. Requests use Chrome TLS impersonation
(curl_cffi) since Workday fronts many tenants with bot-management that
blocks plain HTTP clients.
Input
{"siteUrls": ["https://workday.wd5.myworkdayjobs.com/Workday"],"titleKeyword": "engineer","locationKeyword": "Remote","remoteOnly": false,"includeDescriptions": true,"maxJobsPerSite": 50,"maxTotalJobs": 0}
How to find a site URL: open the company's careers page — if it's on Workday,
the address bar will show something.wdN.myworkdayjobs.com/SiteSlug. Paste that
whole URL as-is.
Output schema
| Field | Description |
|---|---|
company | Workday tenant slug (e.g. nike) |
title | Job title |
location | Primary location |
all_locations | Primary + additional locations, comma-joined |
remote_type | remote / hybrid / onsite / null |
seniority | executive/vp/director/manager/principal/staff/lead/senior/mid/entry/intern, inferred from title |
employment_type | Workday timeType (e.g. "Full time") — only populated with includeDescriptions=true |
posted_at_raw | Workday's own posted-date text, verbatim |
posted_at_is_exact | true if posted_at_raw parses as a real ISO date, false if it's a relative string like "Posted Today" |
job_id | Requisition id (jobReqId, e.g. JR-0097159) |
external_path | Workday's internal per-job path (stable across runs — usable as a dedup key) |
url | Public apply/posting URL |
apply_url | Same as url on this platform |
description_text / description_html | Full job description — only populated with includeDescriptions=true |
global_id | workday:<tenant>:<site>:<jobId or externalPath> — stable dedup key |
parse_confidence | 0.0–1.0 quality score |
warnings | Machine-readable parse-quality flags |
Known limitations (honest)
postedOnis often a relative human string, not an exact date (e.g. "Posted Today", "Posted 30+ Days Ago"). This is a real Workday platform limitation, not a parsing bug — most tenants do not expose an exact ISO timestamp via CXS.posted_at_rawcarries whatever Workday returns verbatim;posted_at_is_exacttells you whether it happens to be a real date on that tenant.- Salary and department are intentionally NOT in the schema. Workday's
CXS API does not reliably expose either across tenants — rather than ship
a column that's almost always
null, they're omitted. - Field names and exact response shape were confirmed via multiple
independent research sources (Workday integration write-ups, an
open-source Workday job crawler's documented output schema, and
third-party API-reference pages) that converge on the same
jobPostings/jobPostingInfostructure and the/wday/cxs/<tenant>/<site>/jobs+/job/<externalPath>endpoint pair. This was not verified against a live tenant response during development (research/build session ran without hitting the live target from an unproxied connection, per this fleet's access policy) — the parser is written defensively (multiple fallback field names, graceful degradation to listing-only fields) to tolerate the minor per-tenant/per-CXS-version field variation these sources note, but a first production run should be spot-checked against a couple of real tenants before scaling up. - Some tenants require additional facet parameters (e.g. a
locationsorjobFamilyGroupapplied facet) to see certain job families in the default unfiltered search — this actor sends an emptyappliedFacetsobject, which returns the full unfiltered job list on the tenants this was researched against, but an unusual tenant configuration could in principle require a facet to be pre-selected. Not observed in research, flagged for completeness. - Very large tenants (thousands of open reqs) with
includeDescriptions=truemake one extra HTTP request per job — expect proportionally longer/costlier runs; setincludeDescriptions=falsefor a fast metadata-only pass.
Wedge vs. generic Workday scrapers
Most Workday scrapers on the market return raw CXS fields as-is. This actor
adds: canonical seniority and remote_type classification, a stable
global_id dedup key independent of Workday's own (sometimes-recycled)
externalPath, an honest posted_at_is_exact flag instead of silently
mis-parsing relative date text, and single-URL-paste onboarding (no need to
separately supply tenant/site/wdServer).
Usage statistics
This Actor creates a small, content-free summary at the end of each run. It is used only to monitor reliability and improve this Actor. A copy is saved as USAGE_STATS in your own Apify key-value store, so you can see the exact record created for your run.
Set disableUsageStats to true in the input to opt out. Nothing is sent then; your USAGE_STATS record only says that statistics were disabled.
Only these fields are recorded:
- schema version, Actor name and build number;
- UTC start and finish hour (not a precise timestamp);
- run duration, number of results and time to the first result, each as a coarse range;
- whether the result was empty, the end status, and an error type from a fixed list;
- memory setting and counts of charged events;
- names of the input fields you set, never their values;
- the selected option for input fields that offer a fixed list of choices (for example a sort order).
We do not collect input text, search terms, URLs, domains, usernames, email addresses, names, proxy credentials, tokens, scraped records, output items, raw error messages, stack traces, or hashes of any of those values. Records are kept for no longer than 13 months, used only as aggregated operational statistics, and never sold or shared.
Additional fields (Phase 2)
This Actor also records your Apify user ID, whether Apify marks the account as paying, the size range of list inputs, the selected country when the input offers a fixed list of countries, and one category from a fixed Actor taxonomy. We use these fields only for aggregate reliability, repeat-use and cross-Actor analysis; reports suppress any cell with fewer than five distinct users.
The same disableUsageStats: true input flag turns these fields off too. The user ID is removed after 13 months; we do not export, sell, share, or attempt to re-identify this data.
Run-outcome signals (v2)
To learn whether a run did what it was asked to do, the record also holds a few more coarse ranges and yes/no flags. None of them contains content:
- the result limit you asked for (a range, when the input has one) and what share of it was delivered;
- results delivered per input item you listed (a range);
- output quality as ranges: how fully the result fields were filled, the share of rows that look like errors, the share of duplicate rows, and how many different fields appeared. These are counted in memory while results are saved; no result content is kept;
- how the run was started (console, API, schedule, webhook, another Actor);
- how it ended: stopped by you, timed out, reached the requested limit, stopped by the charge limit, and how many times the platform moved the run;
- if this Actor reports it: how many items to process worked or failed (ranges) and one failure reason from a fixed list;
- a short code made from the names of the input fields you set, never their values.
Repeat-run fingerprint (v2)
When your Apify user ID is recorded (see above), the record also holds an 8-character one-way code made from your input (proxy settings left out) and this Actor's name. It only lets us see that the same account ran the same input again soon after an unsatisfying run; we never see the input itself. It is stored only in the database, never published, and reports use it in aggregate with the same five-user minimum. It is the one exception to the statement above that no hashes are collected, and disableUsageStats: true turns it off.