Workday Jobs Scraper — Any myworkdayjobs.com Site | $1.50/1K avatar

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

Go to Apify Store
Workday Jobs Scraper — Any myworkdayjobs.com Site | $1.50/1K

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

Vitalii Bondarev

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

9 days ago

Last modified

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:

  1. Extracts tenant (nike), wdServer (wd1), and site (NikeCareers) from the URL.
  2. POSTs to https://<tenant>.<wdServer>.myworkdayjobs.com/wday/cxs/<tenant>/<site>/jobs with {"appliedFacets": {}, "limit": N, "offset": N, "searchText": ""} and paginates via offset/limit until the listing is exhausted.
  3. 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

FieldDescription
companyWorkday tenant slug (e.g. nike)
titleJob title
locationPrimary location
all_locationsPrimary + additional locations, comma-joined
remote_typeremote / hybrid / onsite / null
seniorityexecutive/vp/director/manager/principal/staff/lead/senior/mid/entry/intern, inferred from title
employment_typeWorkday timeType (e.g. "Full time") — only populated with includeDescriptions=true
posted_at_rawWorkday's own posted-date text, verbatim
posted_at_is_exacttrue if posted_at_raw parses as a real ISO date, false if it's a relative string like "Posted Today"
job_idRequisition id (jobReqId, e.g. JR-0097159)
external_pathWorkday's internal per-job path (stable across runs — usable as a dedup key)
urlPublic apply/posting URL
apply_urlSame as url on this platform
description_text / description_htmlFull job description — only populated with includeDescriptions=true
global_idworkday:<tenant>:<site>:<jobId or externalPath> — stable dedup key
parse_confidence0.0–1.0 quality score
warningsMachine-readable parse-quality flags

Known limitations (honest)

  • postedOn is 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_raw carries whatever Workday returns verbatim; posted_at_is_exact tells 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 / jobPostingInfo structure 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 locations or jobFamilyGroup applied facet) to see certain job families in the default unfiltered search — this actor sends an empty appliedFacets object, 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=true make one extra HTTP request per job — expect proportionally longer/costlier runs; set includeDescriptions=false for 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.